Compare commits

..
Author SHA1 Message Date
dependabot[bot]andGitHub 714ad2296b Bump js-yaml from 4.3.1 to 4.3.2
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.3.1 to 4.3.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.2/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.3.1...4.3.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-13 04:56:17 +00:00
Théophile DesmedtandGitHub 8c599e64c0 Doc fixes following PR #10019 (#10022)
* add examples using the new templates $:/core/templates/plain-text and $:/core/templates/rendered-text

* Fix broken links, use documentation macro and correct the system tag given in the example

* fix version number

* fix version number

* use the tid documentation macro
2026-09-11 16:52:01 +01:00
Jeremy Ruston 2b60da0dcf Updated Catalan translation 2026-09-10 14:00:07 +01:00
Jeremy Ruston 5d3f2685a3 Merge branch 'tiddlywiki-com' 2026-09-08 11:40:21 +01:00
Joshua FontanyandGitHub 685a80dfc6 Document that an unquoted parameter value cannot contain a colon (#9999)
Calls stated that a value needs no delimiters if it contains no spaces or
quotes. A colon also requires them: name:value is call syntax, so the text
before the colon is read as a parameter name and the positional parameter
receives nothing, silently.

Call Syntax already has this right - param-name ":" value is one of its
productions - so this brings the prose into line with the grammar, and adds
a warning naming the two ways round it.
2026-09-08 09:39:22 +01:00
Théophile DesmedtandGitHub 3aec096a07 Add $:/core/templates/plain-text and $:/core/templates/rendered-text (#10017)
* Add $:/core/templates/plain-text core template

This template renders a single `text` variable as plain text using the
<$text> widget. It enables exporting and downloading dynamic strings
via messages like `tm-download-file` using the `variables` paramObject,
eliminating the need to create temporary tiddlers in the wiki store
purely for rendering purposes.

* add release note

* add rendered text template

* update change note
2026-09-08 09:38:27 +01:00
Théophile DesmedtandGitHub ddc59ee77b add examples using the new templates $:/core/templates/plain-text and $:/core/templates/rendered-text (#10019) 2026-09-08 09:38:05 +01:00
Zaid AlmomaniandGitHub e0e6ab69b1 Fix LinkWidget href fallback when tv-filter-export-link returns empty (#10009) 2026-09-08 09:31:24 +01:00
Zaid AlmomaniandGitHub e4ce6b3433 Sign CLA: Zaid (#10010) 2026-09-08 09:30:56 +01:00
Théophile DesmedtandGitHub 47806feb85 Fix plugin library iframes hanging if onload never fires by adding readiness handshake (#10003)
* Fix race condition in plugin library iframe message handling

Introduce a PLUGIN-LIBRARY-READY handshake verb for plugin library iframes. 
This ensures that postMessage commands are not prematurely dropped before 
the iframe's internal script has fully bound its message listeners. 

Retains iframe.onload as a backward-compatible fallback for legacy or 
external libraries that do not emit the ready signal.

* add changenote

* feat(plugin-library): add PLUGIN-LIBRARY-READY handshake to plugin library iframe

    Add PLUGIN-LIBRARY-READY message emission in libraryserver.js

    Signals to parent window when iframe is ready to receive messages

    Complements browser-messaging.js PLUGIN-LIBRARY-READY handler

    Includes comprehensive tests for callback queueing and handshake flow

    Fixes race condition in plugin library iframe message handling

* fix(plugin-library): emit PLUGIN-LIBRARY-READY message on iframe initialization

Emit the PLUGIN-LIBRARY-READY message after the message listener is bound,

signaling to the parent window that the iframe is ready to receive postMessage

commands. This completes the handshake implementation to eliminate the race

condition where messages could be lost before the iframe's script initialization

completes.

* fix indentation

* remove extra space

* remove typo

* refactor(test-browser-messaging): update test descriptions and remove unused code

* lint fix

* fix: correct the update note
2026-09-08 09:28:15 +01:00
Mario PietschandGitHub 5577a3d07b Allow colons in variable names in call syntax (#10015)
Accept a colon in the variable name of a `<<...>>` call and of an
`((...))` attribute reference, restoring the v5.3.8 name character
class. Call Syntax already describes the callee name as any
non-whitespace character other than `(` or `>`, and the colon is only
meaningful at the parameter name position.

* Add test cases for a colon name standalone, as an attribute value, as
  an =-separated parameter value, and with named parameters
* Add the 5.5.0 change note
2026-09-08 09:12:02 +01:00
Théophile DesmedtandGitHub d62b75cceb Fix #10004 iframe DOM leak in unloadIFrame loop (#10018)
* Fix unloadIFrame loop condition for proper iframe unloading

* add changenote for #10018

* add missing field to changenote
2026-09-08 12:11:06 +04:00
30a51be168 Bump @humanfs/node from 0.16.7 to 0.16.8 (#10008)
Bumps [@humanfs/node](https://github.com/humanwhocodes/humanfs/tree/HEAD/packages/node) from 0.16.7 to 0.16.8.
- [Release notes](https://github.com/humanwhocodes/humanfs/releases)
- [Changelog](https://github.com/humanwhocodes/humanfs/blob/main/packages/node/CHANGELOG.md)
- [Commits](https://github.com/humanwhocodes/humanfs/commits/node-v0.16.8/packages/node)

---
updated-dependencies:
- dependency-name: "@humanfs/node"
  dependency-version: 0.16.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-07 15:00:46 +04:00
Jeremy Ruston 38fa4486e4 Merge branch 'tiddlywiki-com' 2026-09-05 14:58:11 +01:00
Théophile DesmedtandGitHub d0a0198f49 Fix image reference for TiddlyWiki architecture (#10000)
Fix the broken reference to "TiddlyWiki Architecture.svg"
2026-08-29 23:26:01 +01:00
Jeremy Ruston 52c60be3a0 Merge branch 'tiddlywiki-com' 2026-08-25 17:24:38 +01:00
Jeremy Ruston b3279e348d Update Quine URL 2026-08-25 17:24:25 +01:00
Jeremy Ruston 516135e1b2 Merge branch 'master' of https://github.com/TiddlyWiki/TiddlyWiki5 2026-08-24 22:13:04 +01:00
Jeremy Ruston 6845f1c47e Merge branch 'tiddlywiki-com' 2026-08-24 22:12:30 +01:00
Théophile DesmedtandGitHub 6680967875 Improve discoverability of the style attribute feature (#9975)
* Improve discoverability of the style attribute feature

* Add missing tiddler  "Style Attributes"
2026-08-21 09:04:34 +02:00
Mario PietschandGitHub f9d5ee0ad7 Add ButtonWidget examples and execution order (#9945)
Document the button widget with runnable test cases and explain how its
attributes combine.

* Add eleven test case tiddlers, listed by title prefix so a new one needs
  no edit to the widget page
* Describe the order in which a button runs body actions, to, message,
  popup, set and actions, whatever order they are written in
* Prefer class over a hardcoded style
2026-08-16 13:17:33 +02:00
Mario PietschandGitHub 68630c939d Docs only Groupedlists examples (#9954)
* Add GroupedLists examples

Document grouped lists with runnable test cases over a shared
bibliography sample.

* Cover plain grouping, search, tabs by first character, both combined,
  and grouping on one field while searching another
* Name the grouped field in one procedure, so the grouping changes in
  one line
* Import it with import-compound, and list the examples by tag so a new
  one needs no page edit
* Rewrite the opening paragraph, which described only the sidebar tabs

* Replace GroupedLists code dumps with examples

Turn the two sidebar tabs the page describes into runnable test cases,
and tighten how the examples handle an empty result.

* Give each new example its own dummy payload, and point the page at the
  live tabs instead of quoting core source
* Carry the values through the filter from the start, so an All tab with
  no matches yields nothing rather than the literal All
* Use the list-empty widget

* use tc-tiny-gap instead of -left -right
2026-08-16 13:16:04 +02:00
Simon HuberandGitHub 5e5937838b Fix: #9879 change release note for version 5.5.0 (#9968) 2026-08-14 12:56:09 +02:00
Simon HuberandGitHub 6c8ac9b6a7 Refactor class attributes for edit field wrapper (#9879)
* Refactor class attributes for edit field wrapper

The problem here is, that if we have an existing field with name - say - "field1" and we want to add a field with name "field12345", at the moment we insert "field1" the edit-text widget re-renders because its classes change. The `tc-edit-field-exists` class must go outside to the container div.

* Add changenote for bugfix in field-name inputs

Fixes the field-name input re-rendering issue that caused loss of focus when inserting existing field-names.
2026-08-14 08:31:20 +02:00
Simon HuberandGitHub 0c60e1fa7a Add class assignment to DOM node in editors (#9965)
* Add class assignment to DOM node in editor

* Fix indentation in assignDomNodeClasses method

* Fix conditional check for changedAttributes class

* Improve class assignment in EditTextWidget

Refactor class assignment logic to avoid duplicates and handle whitespace.

* Refactor DOM class assignment in EditTextWidget

* Refactor updateDomNodeClasses for clarity and efficiency

* Add changenote for enhancement in editor refresh behavior
2026-08-13 12:21:20 +02:00
Mario PietschandGitHub b40b6de3ae Make sort order using sortby more consistent (#9747)
* make sort order more consistent

* Fix tests, as they are to be different due to the change.

* Add ChangeNote

* sortby: add "end" operand to place unlisted last

Give the sortby filter operator an optional second operand `end` that
places input titles missing from the reference list after the listed
ones, while the default still keeps them at the start.

* x-listops: read a second operand; `end` sorts unlisted titles to the
  end of the list, the default (no operand) leaves them at the start
* Document the optional `place` parameter on the sortby operator and
  rename the operator and examples tiddlers to match their titles
* Add a `sortby[...],[end]` example to the operator examples
* Replace the 5.5.0 change note with one describing the new `end`
  operand and its unchanged default
* Extend the sortby tests to cover both default (unlisted first) and
  `end` (unlisted last) placement

* Make the sortby end flag a suffix

Specify the placement of unlisted titles with an operator suffix.
Eg: `sortby:end[a b c]`

* Read the flag from `operator.suffix`
* Move the example and the change note to the suffix syntax
* Switch the sortby tests to the suffix syntax

* Cover the sortby guard and unlisted ordering

Close gaps found by mutating the sortby operator

* Sort two titles to catch an off-by-one in the length guard
* Keep unlisted titles in input order under the `end` suffix to catch a
  comparator tie break
* Return a single title untouched, exercising the early return
2026-08-13 11:18:38 +01:00
aac08a6252 Bump js-yaml from 4.3.0 to 4.3.1 (#9966)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.3.0 to 4.3.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.1/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.3.0...4.3.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 15:19:57 +02:00
Simon HuberandGitHub 40b353bd0e Touch a temp tiddler when removing a tag (#9889)
* Touch a temp tiddler when removing a tag

Like that removing a tag doesn't make TiddlyWiki5 wait for the Typing timeout to remove it but removes it instantly, because also a non-draft Tiddler has changed

* Add release notes for bugfix in Edit Mode tags

Fixes an issue where tags of Tiddlers in Edit Mode don't animate instantly when they get removed.

* Add inline comment

* Update release version to 5.5.0 in changenote
2026-08-11 10:50:55 +02:00
superuser-doesandGitHub 7efbd01801 update 5.4.0 release notes: there was no change to default code wrap (#9962) 2026-08-08 11:46:30 +02:00
Théophile DesmedtandGitHub 5143138c16 [DOCS] Update [[Custom Widgets]] with new example for overriding LinkWidget (#9961)
* [DOCS] Update [[Custom Widgets]] with new example for overriding LinkWidget

* fix: non-svg link icon are now sizing properly

* replace HelloThere by list-link in the example for robustness

* Add class to span for better styling in Custom Widgets

* Fix typo in Custom Widgets.tid documentation

* Improve doc by using the proper macro to link widgets

* Change font size style to important for title icon

Updated the font size style for the title icon to be important.

* Update transclude and slot elements in Custom Widgets

Provide a fallback if no body for the link is given

* Enhance link widget to show icons conditionally

Updated the link widget to conditionally display an icon next to the link based on the target tiddler's icon field. Modified the rendering logic to use a conditional statement for the icon display.

* Change transclude height to size in Custom Widgets
2026-08-07 22:05:06 +02:00
Jeremy Ruston 8e65fdc06a Merge branch 'tiddlywiki-com' 2026-08-06 10:50:33 +01:00
Jeremy Ruston ceb0817176 Update Quine instructions 2026-08-06 10:48:53 +01:00
Simon HuberandGitHub 2f578589a0 Fix typo in story width variable name (#9958)
* Fix typo in story width variable name

* Add change note for release 5.5.0

Fixes a typo in the CSS custom properties
2026-08-06 11:20:13 +02:00
916df90cc9 Fix $tw.utils.pulseElement() (#9741)
* Fix $tw.utils.pulseElement() by replacing missing $tw.browser.animationEnd

Use $tw.utils.convertEventName("animationEnd") and add pulse CSS animation

Fixes #6835

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add ChangeNote

* add tc- prefix to pulse class

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-30 06:15:38 +02:00
ea18c85a4c Bump brace-expansion from 1.1.12 to 1.1.16 (#9953)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.16.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.16)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.16
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-28 21:53:27 +02:00
Mario PietschandGitHub abf134afe4 Fix regression introduced by PR #9815 (#9944)
* Keep retained tiddler subdirectories on save

Make generateTiddlerFilepath keep a retained tiddler's recorded subdirectory
and produce a valid filename for every path segment.

* Normalise originalpath separators to "/" before the sanitiser, so recorded
  subdirectories survive
* Validate each path segment (reserved names, trailing dots or spaces), so
  "sub/CON" is valid on every OS
* Run that pass after transliteration, which can itself create a reserved name
* Add filesystem and adversarial specs, covering generateTiddlerFileInfo and
  generateTiddlerExtension

* update changenote
2026-07-28 11:34:09 +01:00
Saq ImtiazandGitHub 45d2ca948a Optimizes filterrunprefixes & filters using ES2017 (#9943)
* refactor: use ES2017 to optimize filter run prefixes

* chore: eslint

* chore: eslint

* fix: added missing file

* refactor: prefix, suffix and subfilter operators

* refactor: further improvements using new String methods

* docs: added changenote

* chore: renamed docs tiddler

* chore: renamed docs tiddler
2026-07-28 12:32:48 +02:00
Mario PietschandGitHub 94b046b8cb Fix button widget selection state with setTitle (#9951)
Make the button widget apply selectedClass correctly when the state is
addressed with setTitle instead of set.

Issue #9949, the button could not be rendered at all

* Guard the setField read in isSelected(), which dereferenced the result of
  getTiddler() directly. A missing state tiddler threw a TypeError, and that
  tiddler is normally only created by the first click

Issue #9950, every button of a set reported itself as selected

* Rewrite isSelected() as an if/else. The nested ternary mixed `||` with
  `?:`, so the setTitle branch returned a fallback value instead of a
  comparison
* Watch the setTitle state tiddler in refresh(), so the selected class
  follows the state as it already does for set

Documentation and tests

* Document that setField takes preference over setIndex. That has always
  been the behaviour, it was never written down
* Document that selectedClass and default apply to setTitle as well as to set
* Add wiki based test cases for the set, setTitle, setField and setIndex
  selection paths. Six of the seven fail against v5.4.1, the one that passes
  uses set, which was never broken

Fixes #9949
Fixes #9950
2026-07-28 11:19:12 +01:00
Saq ImtiazandGitHub c710a56b21 Optimizes x-listops using ES2017 (#9942)
* refactor: use ES2017 to optimize x-listops

* chore: eslint

* refactor: optimize listops.js using ES2017

* refactor: prefix operator

* docs: added changenote

* feat: added tests
2026-07-28 11:12:35 +01:00
saqimtiaz e681096127 fix: remove duplicate widget evaluation for multi-valued variables 2026-07-24 21:04:54 +02:00
24b433211d feat: add JSON output support to makepatches operator (#9940)
* feat: enhance makepatches function to support multiple suffixes and JSON output format

* feat: add release notes for makepatches JSON output enhancement

* doc: update makepatches operator documentation to document new json output

* doc: add JSON output examples to makepatches and applypatches documentation

* chore: convert space indentations to tabs

* test: add tests for makepatches operator with JSON output support

* chore: change space to tab indentation

* test: add DiffMergePatch4 integration test for testing makepatches json output

* fix: remove superfluous heading character

* refactor the parsing of the makepatches suffixes

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>

* refactor: improve makepatches function for better readability and performance

* chore: apply style guide by collapsing consecutive variable assignments

* chore: remove extraneous tabs

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
2026-07-24 16:17:34 +02:00
abf8ffdbca Fix 9814 file system paths "pragma: \ define" tiddler (#9815)
* New test for all "forbidden" directory characters

* Fix for 9814 Pragma: \define creates dir problem

* improve handling of tiddlers in root/community directory

* Add ChangeNote

* Apply suggestion from @saqimtiaz

* Apply suggestion from @saqimtiaz

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
2026-07-22 13:45:25 +02:00
Mario PietschandGitHub 97e27d0dad Fix regex for code block end detection in wikiparser (#9739)
* Fix regex for code block end detection in wikiparser

* Anchor the codeblock end fence to its own line

Close an empty code block without consuming the tiddler, while a fence
only counts when it stands alone on its line.

* Match the end fence with (^|\r?\n) so the empty block case closes at
  the line start and a code line ending in ``` stays inside the block
* Add test-codeblock-parser.js covering empty blocks with language and
  CRLF, delimiter newline handling, mid-line fences and a missing fence
2026-07-22 13:12:55 +02:00
Jeremy Ruston 855dc2fbb9 Merge branch 'master' of https://github.com/TiddlyWiki/TiddlyWiki5 2026-07-21 17:24:39 +01:00
lin onetwoandGitHub e1e34f4907 Move background action console.log inside platforms check (#9891)
* Move background action log inside platforms check

* Add change note for #9891

* Shorten change note

* Release notes: move #9891 from 5.4.1 to 5.5.0

PR #9891 is still open, so the background-action log change is planned for 5.5.0 instead of 5.4.1.

* Fix change-category for #9891 release note

 is not a valid category; use  instead.
2026-07-21 18:16:33 +02:00
Jeremy Ruston 7196b9ee9b Merge branch 'tiddlywiki-com' 2026-07-21 12:11:44 +01:00
Jeremy Ruston c0b3403f87 Remove extraneous github ribbon in the dev edition 2026-07-21 12:11:14 +01:00
Jeremy Ruston ed71c8262a Merge branch 'tiddlywiki-com' 2026-07-18 11:36:50 +01:00
Jeremy Ruston 2ececf21c7 Cherry pick docs update from master 2026-07-18 11:36:37 +01:00
7516d96eed Update docs: running a custom Node.js TiddlyWiki version with npx (#9886)
* Update docs: running a custom Node.js TiddlyWiki version with npx

* Update docs: document different options of running multiple TW versions

---------

Co-authored-by: shadow <shadow@darkstar.localdomain>
Co-authored-by: me <me@localhost>
2026-07-18 10:31:42 +01:00
4bf7e9d192 [Bug] Fix the CSV parser blanking a table (#9919)
* Fix the CSV parser blanking a table

getCellInfo read the loop variable i before its declaration, so hoisting made
it undefined and charAt(undefined) read the first character of the whole text.
Any CSV opening with a separator therefore returned every cell empty.

- Test the cell against the start of the cell rather than the hoisted i
- Keep a separator inside a quoted cell literal
- Cover the parser with tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add a change note for the CSV fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 17:26:59 +02:00
Bram ChenandGitHub 04cd3081e4 Update chinese language files (#9933)
* Update chinese language files

* Add WikiInformation/Generate/Caption in ControlPanel.multids

* Add ChangeNote
2026-07-14 15:50:37 +01:00
saqimtiaz d27716c1e0 chore: fixed erroneous changenote number 2026-07-14 13:17:58 +02:00
Mario PietschandGitHub 7f7f36d986 Skip system tiddlers in back-indexer updates (#9917)
* Skip system tiddlers in back-indexer updates

Fix #9916: editing a system tiddler that links or transcludes another
tiddler made it a backlinks[]/backtranscludes[] source until the next
index rebuild (shipped since v5.3.4).

* Guard BackSubIndexer.update() with isSystemTiddler() on both sides,
  matching the initial scan; this also skips parsing $:/StoryList on
  every navigation
* Add test-back-indexer.js: regression guards plus adversarial probes
  for shadow reveals and hostile __proto__ titles

* Add ChangeNote
2026-07-14 13:10:21 +02:00
Mario PietschandGitHub 86a4e18134 diff-text change newline to ↲ (#9736)
* diff-text change newline to ↲

* Add ChangeNote
2026-07-14 13:04:50 +02:00
Mario PietschandGitHub 304858c7c5 Make Click to generate wiki info button translatable (#9737)
* Make Click to generate wiki info button translatable

* Add ChangeNote
2026-07-14 12:53:23 +02:00
Mario PietschandGitHub 7ececf9e0f Align fakedom tagname with HTML spec (#9843)
* Fakedom: uppercase tagName for HTML elements per DOM spec

Browsers uppercase tagName for HTML elements. Other namespaces (SVG,
MathML, XML) preserve case. Fakedom now matches, so widget code can use
the natural `node.tagName === "OPTGROUP"` form in both environments.

https://dom.spec.whatwg.org/#dom-element-tagname

* Tests: cover fakedom tagName spec compliance

Three specs pin the DOM contract for tagName: uppercase for HTML
elements, case preservation for other namespaces, and non-mutating
reads. Includes the OPTGROUP predicate the select widget will rely on
once it can drop its defensive .toUpperCase() call.

https://dom.spec.whatwg.org/#dom-element-tagname

* Fakedom: empty or null namespace creates a no-namespace element

Per DOM spec, createElementNS("") and createElementNS(null) have to produce
elements with no namespace. Fakedom previously defaults both to HTML,
which made tagName incorrectly uppercase non-HTML elements.
createElement without arguments still defaults to HTML.

https://dom.spec.whatwg.org/#dom-document-createelementns

* Add ChangeNote
2026-07-14 12:22:45 +02:00
saqimtiaz 521e530e11 docs: added size comparison of empty.html from prerelease and latest release 2026-07-14 07:55:48 +02:00
XLBillyandGitHub 4c29dae4af Replace some wikify widget with call dynamic attribute syntax (#9816)
* Replace some wikify widget with call dynamic attribute syntax

* Apply suggestions

* Add change note
2026-07-13 15:57:04 +02:00
Mario PietschandGitHub f5317dc225 Fix Node.js deprecated warning (#9742)
* Fix Node.js deprecated warning

* Add ChangeNote

* Change deprecation to bugfix for DEP0169 warning

Updated change type from 'deprecation' to 'bugfix' for the Node.js server's handling of the DEP0169 warning.
2026-07-13 13:43:07 +02:00
lin onetwoandGitHub c952450c2e fix(filter): optimize tag[] and !tag[] with Set for O(1) lookup (#9715)
* fix(filter): optimize tag[] and !tag[] with Set for O(1) lookup, resolves performance gap vs search:tags[]

* useless test

* note

* note
2026-07-13 13:37:05 +02:00
Rob HoelzandGitHub 1eb7ec4402 Convert deeply nested if/else to do/while(false) with breaks for parseAttribute (#9770)
01d3cde96 refactored parseMacroParameterAsAttribute to use a
do/while(false) construct with break statements - this updates
parseAttribute with an analogous refactoring for consistency
2026-07-13 08:15:26 +02:00
9a0bbf831b Signing the CLA (#9923)
* Signing the CLA

* Apply suggestion from @saqimtiaz

* Apply suggestion from @saqimtiaz

* Apply suggestion from @saqimtiaz

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
2026-07-12 19:37:43 +02:00
superuser-doesandGitHub a30854a4c7 [DOCS] Corrected Description Lists tiddler (#9819)
* [DOCS] Corrected Description Lists tiddler

* Correct modified, remove trailing whitespace
2026-07-12 09:48:53 +02:00
869557f7d1 Bump js-yaml from 4.1.1 to 4.3.0 (#9903)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.0.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.3.0)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-12 09:22:08 +02:00
Mario PietschandGitHub 856057be81 Add 8972 field names with parens impact note (#9875) 2026-07-12 09:20:31 +02:00
saqimtiaz c9f1154643 chore: preparing for v5.5.0 2026-07-10 12:41:53 +02:00
Jeremy Ruston 748f04c9e3 Update TiddlyWiki release checklist 2026-07-10 11:01:22 +01:00
saqimtiaz d391595836 Version number update for 5.4.1 2026-07-10 11:39:38 +02:00
saqimtiaz 967140a148 Merge branch 'master' of github.com:TiddlyWiki/TiddlyWiki5 2026-07-10 11:37:07 +02:00
saqimtiaz 95e68b0437 chore: added missing changenotes 2026-07-10 11:36:59 +02:00
Jeremy Ruston 8ddede1611 Missing v5.4.1 release notes 2026-07-10 10:36:20 +01:00
saqimtiaz ceb200b08c chore: update license and readme 2026-07-10 11:17:53 +02:00
saqimtiaz 00e5f48a59 chore: preparing for v5.4.1 release 2026-07-10 11:12:01 +02:00
saqimtiaz ea0e9105bc Merge branch 'tiddlywiki-com' 2026-07-10 11:00:56 +02:00
Jeremy Ruston 51459815ba Fix CI errors 2026-07-09 16:16:36 +01:00
Jeremy Ruston 8c62935a01 Fix incorrect reference to BurningTreeC's website 2026-07-09 14:14:47 +01:00
Jeremy Ruston 839fa2417d Fix CI issues
1. Remove references to obsolete plugins
2. Fix duplicate language string entry
2026-07-09 14:12:10 +01:00
Saq ImtiazandGitHub 1b8610e4d8 Fixes issue with copying cross window event properties (#9905)
* fix: issue with copying cross window event properties

* docs: added changenote
2026-07-09 12:50:12 +01:00
Mario PietschandGitHub ca063cbe90 Add quick test runner (#9743) 2026-07-08 13:56:16 +01:00
Jeremy Ruston 7d4328b2fb Merge branch 'master' of https://github.com/TiddlyWiki/TiddlyWiki5 2026-07-08 12:02:55 +01:00
Jeremy Ruston 1ae224ab74 Merge branch 'tiddlywiki-com' 2026-07-08 12:02:50 +01:00
Mario PietschandGitHub c308fc44c4 Fix invalid source positions in parse tree nodes (#9882)
* Fix invalid source positions in parse tree nodes

Several wikitext rules recorded start and end offsets that did not match
the source they represent. The offsets are only used for source position
mapping, not rendering or serialization, so output is unchanged and
source.slice(start, end) now equals the node text.

* import: the filter attribute start was set to the whole source string
  instead of the numeric offset. It used this.parser.source where it
  meant this.parser.pos, so every \import node carried a copy of the
  entire source as its start.

* codeinline: the text node end pointed past the closing backtick, so the
  span included the closing delimiter and could read one or two characters
  too far. It now ends where the content ends.

* wikilinkprefix and extlink: a suppressed link such as ~SomeLink or
  ~http://example.com produced a text node whose span included the
  leading ~ while its text did not. The span now starts after the ~.

* Add 5.4.1 change note for #9882

Document the parse tree source position fixes: inline code, suppressed
external links, suppressed wikilinks, and the import filter rule.

* Add tests for parse tree source positions

Cover the four wikitext parser rules whose `start` and `end` offsets are
corrected in this PR: codeinline, extlink, wikilinkprefix, and import.
2026-07-08 10:03:11 +01:00
Jeremy Ruston aa3fb85919 BurningTreeC is leader of the TiddlyDesktop team
@BurningTreeC please check the details of your card,
2026-07-08 09:58:40 +01:00
Jeremy Ruston bd052a33f8 Correct v5.4.1 banner 2026-07-08 09:45:29 +01:00
superuser-doesandGitHub bb766c36c3 [DOCS] Fix survey image link (#9897) 2026-07-01 15:55:49 +02:00
566a341328 Bump js-yaml from 4.1.0 to 4.1.1 (#9777)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 08:11:15 +01:00
9316234001 Bump picomatch from 4.0.3 to 4.0.4 (#9776)
Bumps [picomatch](https://github.com/micromatch/picomatch) from 4.0.3 to 4.0.4.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 08:11:02 +01:00
c1cb93c9df Bump minimatch from 3.1.2 to 3.1.5 (#9775)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 08:10:52 +01:00
e46361fbc0 Bump flatted from 3.3.3 to 3.4.2 (#9774)
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 08:10:40 +01:00
s793016andGitHub e730836d6f Freelinks Plugin: Add configurable MaxLinks cap and remove search truncation (#9836)
* Update aho-corasick.js

Optimized Aho-Corasick string matching algorithm implementation with enhanced
performance and error handling for TiddlyWiki freelinking functionality.
 
- Uses WeakMap for failure links. WeakMap keys are compared by object identity
  (reference equality), which is required here because trie nodes are plain
  objects — a regular {} map would not work because JavaScript only supports
  string and Symbol keys, forcing object keys to be coerced to strings.
- Outputs are merged at build time (classic AC optimization), eliminating the
  need to walk the failure chain during search.
- search() converts case per character to avoid Unicode index desync (e.g.
  Turkish İ expands under toLowerCase(), shifting subsequent indices).
- No match count cap in search(); truncation is handled at the render stage
  by processTextWithMatches() to avoid silently dropping matches mid-text.
- Optional word boundary filtering: CJK always allowed; Latin requires
  non-word characters on both sides.

* Update text.js

- Render output capped by $:/config/Freelinks/MaxLinks (default 500).
  The cap applies to the final set of non-overlapping rendered links, not to
  the raw search results: search always runs to completion so that the
  longest-match selection has full information. Text beyond the cap remains
  as plain text rather than being silently omitted.

* Create config-Freelinks-MAX_LINKS_TIDDLER.tid

setting for MAX_LINKS_TIDDLER

* Update and rename config-Freelinks-MAX_LINKS_TIDDLER.tid to config-Freelinks-MaxLinks.tid

fix typo

* Update settings.tid

add MaxLinks setting

* Update readme.tid

add MaxLinks setting text

* Create #9836.tid

release note

* Update tiddlywiki.info

add freelinks for test build

* Update macros-view.tid

fix structure problem

* Update text.js

add IGNORE_CASE_TIDDLER  to whitelist

* Rename #9836.tid to #9836.tid

move to 5.4.1

* Update text.js

I deleted the wrong line last time, so I'm putting it back.

* Update text.js

eslint fix

* Update text.js

refactor: inline plain-text via dynamic core reference

* Delete plugins/tiddlywiki/freelinks/plain-text.js

remove plain-text.js: now inlined via dynamic core reference

* Update text.js

restore plain-text.js, remove new Function extraction

* Add files via upload

restore plain-text.js, remove new Function extraction

* Update #9836.tid

update new bug

* Update #9836.tid

tw version fix

* Update tiddlywiki.info

reverse to original
2026-06-20 19:25:19 +01:00
XLBillyandGitHub d050dd30cc Fix KaTeX missing font (#9873) 2026-06-09 16:36:22 +01:00
IchijikuIchigoandGitHub 635f6b5e76 [ja_JP] Update of Japanese translations (#9870)
* [ja_JP] Japanese translation update from commit: 3ed481b

* [ja_JP] Japanese translation update from commit: ad3587b

* [ja_JP] Japanese translation update from commit: 6bc77cf

* [ja_JP] Japanese translation update from commit: 5d1c1ea, c4991a5

* [ja_JP] Japanese translation update from commit: 37a4613

* [ja_JP] Japanese translation update from commit: 748ef8a

* [ja_JP] Japanese translation update from commit: 92caa73

* [ja_JP] Japanese translation update from commit: 87ba87b

* [ja_JP] Japanese translation update from commit: 15ba415

* [ja_JP] Japanese translation update from commit: 64ee20e

* [ja_JP] Japanese translation update from commit: 5d1c1ea,add3d42

* [ja_JP] Japanese translation update from commit: 64ee20e

* [ja_JP] Japanese translation update from commit: b001333

* [ja_JP] Japanese translation update from commit: b434b9d

* [ja_JP] Japanese translation update from commit: 3983086
2026-06-05 16:23:47 +01:00
Saq ImtiazandGitHub 40d0d542f7 playwright: revert timeout to 60s 2026-06-04 09:46:36 +02:00
Saq ImtiazandGitHub a66d9a596c playwright: change timeout to 45s 2026-06-04 09:37:21 +02:00
Saq ImtiazandGitHub 23063ea9c8 playwright: increase timeout to 60s 2026-06-04 09:32:23 +02:00
Jeremy Ruston 9c1f69e9c1 Revert "[ja_JP] Update of Japanese translations (#9853)"
Reverting as was inadvertently merged to tiddlywiki-com

This reverts commit 14b11575d0.
2026-06-04 08:28:09 +01:00
Saq ImtiazandGitHub 6abfcb631d Update playwright.config.js to address build failures 2026-06-04 09:26:56 +02:00
IchijikuIchigoandGitHub 14b11575d0 [ja_JP] Update of Japanese translations (#9853)
* [ja_JP] Japanese translation update from commit: 3ed481b

* [ja_JP] Japanese translation update from commit: ad3587b

* [ja_JP] Japanese translation update from commit: 6bc77cf

* [ja_JP] Japanese translation update from commit: 5d1c1ea, c4991a5

* [ja_JP] Japanese translation update from commit: 37a4613

* [ja_JP] Japanese translation update from commit: 748ef8a

* [ja_JP] Japanese translation update from commit: 92caa73

* [ja_JP] Japanese translation update from commit: 87ba87b

* [ja_JP] Japanese translation update from commit: 15ba415

* [ja_JP] Japanese translation update from commit: 64ee20e

* [ja_JP] Japanese translation update from commit: 5d1c1ea,add3d42

* [ja_JP] Japanese translation update from commit: 64ee20e

* [ja_JP] Japanese translation update from commit: b001333

* [ja_JP] Japanese translation update from commit: b434b9d

* [ja_JP] Japanese translation update from commit: 3983086
2026-06-04 08:25:12 +01:00
Maurycy ZarzyckiandGitHub c9b1fbbb76 Add/update translations to Polish language: (#9829)
- 0e765bd
- 9c09841
- 33b2f51
- cd8b1fa
- 0177f09
- b673651
- 9afe522
2026-06-04 08:24:43 +01:00
Jeremy Ruston 27c568e53e Try increasing Firefox timeout because of build errors 2026-06-04 08:21:35 +01:00
Jeremy Ruston 0023d3f6fa Update license date 2026-06-04 08:03:01 +01:00
Jeremy Ruston 76ebe9d8e9 Merge branch 'tiddlywiki-com' 2026-05-17 16:09:36 +01:00
Sean ClaytonandGitHub 40444eade5 Signing CLA (#9856) 2026-05-17 15:15:54 +01:00
Jeremy Ruston fe8723be49 Prepare for v5.4.1, not v5.5.0
See discussion at #9832
2026-05-08 18:13:41 +01:00
Mario PietschandGitHub 56ea0789e1 Update deprecated.js issues (#9833)
* Fix RSOD when $tw.utils.addClass receives a class string with whitespace

PR #9251 replaced the manual setAttribute("class", ...) implementation of
$tw.utils.addClass/removeClass/toggleClass with direct Element.classList
calls. Unlike setAttribute, classList.add/remove/toggle throws
InvalidCharacterError on any token containing whitespace, so callers that
pass a whole class string (e.g. modal.js passing tiddler.fields.class)
now crash.

Manual repro on tw5-com: open SampleWizard, set the `class` field to
"aaa bbb", Done, open popup -> OK -> open nested popup -> RSOD.

Fix: split the className argument on whitespace in deprecated.js and feed
individual tokens to classList. A small splitClasses() helper keeps the
three functions symmetrical.

Adds adversarial regression tests in test-utils.js covering:
- ASCII whitespace variants (space, tab, CR, LF, mixed runs, padding)
- Unicode whitespace (U+00A0 non-breaking space)
- de-duplication across single and multiple calls
- remove/toggle no-op on missing tokens
- toggle with status undefined / true / false
- silent no-op for whitespace-only / empty / non-string / null input
- silent no-op when the element has no classList

* Move new tests to their own file

* Add backwards-compat regression tests for deprecated.js

Locks in pre-5.4.0 tolerant behaviour of $:/core/modules/utils/
deprecated.js helpers that regressed in PR #9251. Each spec targets an
edge-case input the current one-line modern equivalents reject:

- repeat: negative count / null / undefined str
- startsWith / endsWith: RegExp search arg
- stringifyNumber: null / undefined
- domContains: boolean return, self-check
- hasClass: null element, classless element
- getLocationPath: query preservation, hash stripping
  (browser-only; pends in Node because the TW5 sandbox has no `window`)

Also picks up the addClass/removeClass/toggleClass whitespace specs
moved out of test-utils.js by the previous commit, so all deprecated.js
coverage lives together.

Fails 8 specs on current HEAD; the follow-up deprecated.js restoration
commit turns them green.

* Restore pre-5.4.0 behaviour of deprecated.js utilities

PR #9251 replaced several helpers in $:/core/modules/utils/deprecated.js
with one-line ES2017 equivalents that diverge from the originals on
edge-case inputs. Follow-up PRs fixed the most visible cases
(getLocationHash #9622, isDate #9771, addClass empty-string #9561 and
whitespace 005e17537); this commit closes the rest:

- repeat: manual loop tolerates negative count / null / undefined str
- startsWith / endsWith: substring compare tolerates RegExp search arg
- stringifyNumber: `num + ""` coercion tolerates null / undefined
- domContains: `a !== b && a.contains(b)` returns boolean, handles self
- hasClass: null-element guard, strict-false return
- getLocationPath: `toString().split("#")[0]` preserves the query
  string in permalinks (startup/story.js:214, 217) -- the most visible
  user-facing regression, causing ?lang=de etc. to silently drop.

IE-only fallbacks in Math.sign, strEndsWith, domContains, and
domMatchesSelector are removed; TW5 no longer supports IE.

Covered by the regression specs added in the previous commit.

* make comments more refined
2026-05-05 15:27:40 +01:00
Jeremy RustonandGitHub fff648b959 Exclude Claude from npm (#9847) 2026-05-05 10:28:28 +01:00
Mario PietschandGitHub e1cff6068c Fix SelectWidget multi-select highlight regression for options containing HTML (#9839) (#9841)
PR #8093 used `child.children.length === 0` to distinguish a plain <option> from an <optgroup>. This test misfires when an <option> contains inline HTML.

E.g. tc-tiddlylink anchors auto-generated for "$:/..." titles.
So on refresh the option's `selected` state was never restored.

- This change switches to a tagName check.
- Adds a regression test plus a guard for the original PR #8092 optgroup
behaviour.
2026-05-05 10:23:36 +01:00
Mario PietschandGitHub 6721164f15 Add a new test that fails, because a missing typeof test in fakedom.js (#9840)
* Add a new test that fails, because a missing typeof test in fakedom.js

* Add typeof strint fix to fakedom to avoid throw
2026-05-05 11:20:49 +02:00
buggyjandGitHub 3c37aa267d Fix for #9834 Widgets are compiled before modules are loaded (#9835) 2026-05-05 10:16:21 +01:00
Jeremy Ruston a603146b3c Update version number to v5.4.1 2026-05-05 10:13:05 +01:00
Mario PietschandGitHub f992f4ffab Fix 9826 min height issue (#9828)
* Add new tests

* fix 9826 minHeight handling + docs
2026-05-05 10:11:01 +01:00
Mario PietschandGitHub dfedd8594f save impact note 9609 as .tid instead of .json (#9844) 2026-04-29 16:01:35 +02:00
Jeremy Ruston ea84baa5a3 Merge branch 'tiddlywiki-com' 2026-04-21 20:24:23 +01:00
Mario PietschandGitHub a4e4d36bf6 Fix Typo in Link in Multi-Valued Variables (#9824) 2026-04-20 21:31:52 +01:00
Mario PietschandGitHub 3ed481b2e2 Update the Archive and Release Notes Description (#9823) 2026-04-20 21:31:09 +01:00
Jeremy Ruston 27c60ff58d Prepare for v5.5.0 2026-04-20 20:03:12 +01:00
Jeremy Ruston 748ef8aa8d New release should be first thumbnail 2026-04-20 19:56:08 +01:00
Jeremy Ruston 9cfa5a29fb Version number update for 5.4.0 2026-04-20 19:36:07 +01:00
Jeremy Ruston 5ea43ce212 Revert package.json 2026-04-20 19:35:55 +01:00
Jeremy Ruston df6bbbdedf More v5.4.0 preparations 2026-04-20 19:33:07 +01:00
Jeremy Ruston 37a461323e Preparing for release of v5.4.0 2026-04-20 19:31:36 +01:00
Cameron FischerandGitHub b29da7baac I didn't capitalize one of the instances of my name (#9822) 2026-04-19 16:42:52 +01:00
Mario PietschandGitHub 75b54457ed German translations update (#9821)
* German translations update

* fix typo
2026-04-18 15:16:32 +01:00
superuser-doesandGitHub 51f322c3c6 [5.4.0] Add release note for Greek translation update (#9818)
* [5.4.0] Add release note for Greek translation update

Add release note for #9782

* Remove trailing newline
2026-04-18 14:03:27 +01:00
853af2d848 Fix: limit macro call parser to need >> to work, prevent > in regex (#9813)
* fix: limit macro call parser to need >> to work, prevent > in regex

* test: add malformed macro parameter regression coverage

The parser fix on this branch only changes parseMacroParameterAsAttribute() when an unquoted value starts with <<, so the previous broader parser tests did not prove the regression. Add a focused structural test that fails without the guard and passes with it.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* Revert "fix: limit macro call parser to need >> to work, prevent > in regex"

This reverts commit f96b062902.

* lint: test

* Reapply "fix: limit macro call parser to need >> to work, prevent > in regex"

This reverts commit 075f7cc282.

---------

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-18 09:59:22 +01:00
Jeremy RustonandGitHub 2c1cb33081 Restore v5.3.8 handling of malformed attribute syntax (#9812)
Also add a bunch of tests

Fixes #9808
2026-04-18 09:56:22 +01:00
Keiran HarcombeandGitHub 2f63abc12a Merge pull request #9809 from kjharcombe/master
Remove CNAME
2026-04-15 10:34:50 +01:00
Keiran Harcombe 5f80256576 Remove CNAME
I've removed the CNAME file which is blocking access to Yunohost
2026-04-14 12:44:30 +01:00
Jeremy Ruston aa837300d0 Update Chinese translation change note 2026-04-13 17:10:03 +01:00
Bram ChenandGitHub 7f2baa17a9 Update chinese translations (#9804)
* Update chinese translations

* Update languages/zh-Hans/ControlPanel.multids (commit 33b2f51)
* Update languages/zh-Hant/ControlPanel.multids (commit 33b2f51)
* Update languages/zh-Hans/Import.multids (commit b673651)
* Update languages/zh-Hant/Import.multids (commit b673651)
* Update languages/zh-Hans/TiddlerInfo.multids (commit 0177f09, cd8b1fa )
* Update languages/zh-Hant/TiddlerInfo.multids (commit 0177f09, cd8b1fa )
* Add languages/zh-Hant/Draft.multids (commit 9c09841)

* Update chinese translations

* Clarify wording of tiddler info cascade view
2026-04-13 17:08:23 +01:00
Jeremy Ruston 39c6d8fb53 Missing change notes
Fixes #9773
2026-04-12 14:50:40 +01:00
Jeremy Ruston 9afe5226f1 Clarify wording of tiddler info cascade view 2026-04-12 14:33:52 +01:00
Jeremy Ruston 94aa37fe7e Merge branch 'tiddlywiki-com' 2026-04-11 08:38:49 +01:00
superuser-doesandGitHub 1e9c1ef82a [DOCS] Fix MWS Banner image display (#9801) 2026-04-11 08:45:27 +02:00
Saq ImtiazandGitHub 6cde5e94ff Update pr-validation.yml to use Cerebrus v8.1 2026-04-11 08:45:01 +02:00
Saq ImtiazandGitHub fd0d3ccc27 Revert "Replace fill rules in tw5.com edition (#9624)" (#9800)
This reverts commit dc764b3a4a.
2026-04-10 12:23:37 +02:00
Saq ImtiazandGitHub 1ad2e66cbc Revert "Use currentColor to style svg (#9316)" (#9799)
This reverts commit dc7f2a57bb.
2026-04-10 12:23:07 +02:00
Saq ImtiazandGitHub 4699db9f89 Revert "Fix side effects of PR 9316 (#9568)" (#9798)
This reverts commit bf7c0b575c.
2026-04-10 12:22:41 +02:00
lin onetwoandGitHub d977b0ac5c Fix #9788: only allow colon-separator named params with strict identifiers (#9791)
The reAttributeName regexp in parseMacroParameterAsAttribute was too
permissive, allowing single-character names like dollar sign followed by
colon. This caused values such as dollar-colon-slash-plugins-foo to be
mis-parsed as a named parameter dollar with value slash-plugins-foo.

Fix: when the separator is colon (legacy syntax), require the parameter
name to match [A-Za-z0-9-_]+ (same as the historic parseMacroParameter).
When the separator is equals (new-style dynamic parameters from #9055),
the wide character set is preserved so that names like double-dollar-one
continue to work.

Adds regression test Transclude/Procedures/Dollar/Param.
2026-04-10 11:06:07 +02:00
Saq ImtiazandGitHub 7298684951 Update package.json to resolve CI issues 2026-04-10 08:35:32 +02:00
Mario PietschandGitHub f78d8252af Fix issue #9795 tree view regression (#9796) 2026-04-10 08:29:54 +02:00
Saq ImtiazandGitHub 54260b5be8 Updates Cerebrus action to v8.1 (#9793)
* Update pr-check-build-size.yml

* Update pr-comment-build-size.yml

* Update pr-validation.yml
2026-04-09 09:13:45 +02:00
IchijikuIchigoandGitHub 95f12eb857 [ja_JP] Update of Japanese translations (#9792)
* [ja_JP] Japanese translation update from commit: a71ac56

* [ja_JP] Japanese translation update from commit: 32a3a3e

* [ja_JP] Japanese translation update from commit: 65fcded

* [ja_JP] Japanese translation update from commit: a3acbaa

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\functions\Functions.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\functions\Functions.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\definitions\Base64.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\definitions\Definitions.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\definitions\Cascading Style Sheets.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\definitions\Tiddlyhost.tid'
2026-04-07 14:56:55 +02:00
IchijikuIchigoandGitHub 207a68cc59 [ja_JP] Japanese translation update - 'Reference' section of tiddlywiki.com (#9790)
* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\reference\Reference.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\concepts\WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Horizontal Rules in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\_tw_shared\doc-utilities\wikitext-macros.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Block Quotes in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Code Blocks in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Conditional Shortcut Syntax.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Block Quotes in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Block Quotes in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Dashes in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Description Lists in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Filtered Attribute Values.tid'

* [ja-JP] A little correction to the Japanese translation

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Formatting in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Headings in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Paragraphs in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Hard Linebreaks in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\howtos\Hard_Linebreaks_with_CSS.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\howtos\Hard_Linebreaks_with_CSS_-_Example.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\HTML Entities.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Literal Attribute Values.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Lists in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Tables in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Table Classes Captions Headers and Footers.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Transcluded Attribute Values.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Utility Classes.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Widgets in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\parser\WikiText Parser Modes.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\HTML in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\HTML_Links_in_WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Typed Blocks in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Anchor Links using HTML.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Linking in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Macro Calls.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Macro Definitions.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Macro Parameter Handling.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Substituted Attribute Values.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Substituted Attribute Values.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\Concatenating variables to create a URL.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\Concatenating a text reference to create a URL.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\procedures\Procedure Calls.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\procedures\Procedure Definitions.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\procedures\Procedure Parameter Handling.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Transclusion and Substitution.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Transclusion in WikiText.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Transclusion Basic Usage.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Transclusion Basic Usage.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Transclusion with Templates.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Variable Attribute Values.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\variables\Behaviour of variables invoked via widget attributes.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Tables in WikiText CSS Utility Classes.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\Widget Attributes.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\concepts\TemplateTiddlers.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\concepts\Transclusion.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\parser\table-example.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\wikitext\parser\WikiText parser mode_ transclusion examples.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\concepts\TextReference.tid'
2026-04-06 11:34:48 +02:00
superuser-doesandGitHub b434b9d7ea [DOCS] Include description lists in lists tiddler (#9786) 2026-04-05 10:55:36 +01:00
superuser-doesandGitHub b0013333de [DOCS] Expand description list documentation (#9784)
* [DOCS] Expand description list documentation

* remove stray word
2026-04-05 10:15:15 +01:00
superuser-doesandGitHub bcc30e305a Update Greek translation for 5.4.0 (#9782)
* Update Greek translation for 5.4.0

* Add Greek translation for Draft

* Correction to 'Saving'
2026-04-04 14:08:54 +01:00
Jeremy Ruston 34f4dfb903 Merge branch 'tiddlywiki-com' 2026-04-04 09:23:58 +01:00
superuser-doesandGitHub 32a3a3e478 [DOCS] Clean up Forums tiddler (#9780) 2026-04-04 08:49:55 +01:00
Bram ChenandGitHub c6520c4429 Update chinese translations (#9781)
* Update languages/zh-Hans/ControlPanel.multids (commit 33b2f51)
* Update languages/zh-Hant/ControlPanel.multids (commit 33b2f51)
* Update languages/zh-Hans/Import.multids (commit b673651)
* Update languages/zh-Hant/Import.multids (commit b673651)
* Update languages/zh-Hans/TiddlerInfo.multids (commit 0177f09, cd8b1fa )
* Update languages/zh-Hant/TiddlerInfo.multids (commit 0177f09, cd8b1fa )
* Add languages/zh-Hant/Draft.multids (commit 9c09841)
2026-04-04 08:48:34 +01:00
Jeremy Ruston 83d242fb2c Merge branch 'tiddlywiki-com' 2026-04-03 11:10:58 +01:00
Jeremy Ruston ecafb7a4c0 A very minor tweak to the donation graphic
Spot the difference; the wonky text was offending me
2026-04-03 11:10:45 +01:00
Jeremy Ruston 0640e0abe2 Merge branch 'tiddlywiki-com' 2026-04-03 11:00:11 +01:00
Jeremy Ruston a71ac56cc9 More prominent donations link 2026-04-03 10:49:26 +01:00
Jeremy Ruston f518bdf27c Hire Jeremy banner now defaults to just being in the sidebar 2026-04-03 10:49:14 +01:00
Jeremy Ruston 0387b1100b Update CI dependencies 2026-04-01 17:13:32 +01:00
Jeremy Ruston c3a73fccd1 Fixed typo in v5.3.8 change note 2026-04-01 17:00:29 +01:00
Jeremy RustonandGitHub c25659d87c Restore compact call syntax (#9778)
* Initial commit

* Oops broken test
2026-04-01 15:22:42 +02:00
Saq ImtiazandGitHub 0c26a75472 Updates cerebrus action to v8 (#9779)
* Update pr-validation.yml

* Update pr-comment-build-size.yml

* Update pr-check-build-size.yml
2026-04-01 15:21:16 +02:00
Saq ImtiazandGitHub a24dc0e9e8 Update package.json to allow all current LTS versions of nodejs 2026-04-01 15:13:27 +02:00
Jeremy Ruston a499ed0906 Fix CI
Broken by 3cfb6b1202
2026-04-01 13:22:42 +01:00
Jeremy Ruston 3cfb6b1202 Update minimum Node version for as discussed for v5.4.0 2026-04-01 11:51:43 +01:00
Jeremy Ruston ac769e5dcd Commit package-lock.json
Benefit is that it pins dependencies and sub-dependencies, helping mitigate supply chain attacks
2026-04-01 11:42:17 +01:00
Jeremy Ruston ed01af8e47 Update release note with new release banner 2026-03-31 18:43:00 +01:00
Jeremy Ruston 92caa7312e Update new release banner
See https://talk.tiddlywiki.org/t/discussion-ai-and-vote-for-the-banner-for-5-4-0/15108/10
2026-03-31 18:25:20 +01:00
Mario PietschandGitHub 478dce7009 fix problem with idDate() duplication in boot.js (#9771) 2026-03-31 18:50:31 +02:00
IchijikuIchigoandGitHub f3c9cb2310 [ja_JP] Update Japanese translation (#9768)
* [ja_JP] Japanese translation update from commit: 5d0d2b1, e8fe6b9, 33b2f51

* [ja_JP] Japanese translation update from commit: 3543fe5

* [ja_JP] Japanese translation update from commit: 9c09841

* [ja_JP] Japanese translation update from commit: 390b755, 3e966d4, d17525e

* [ja_JP] Japanese translation update from commit: 4007610, 65afdac

* [ja_JP] Japanese translation update from commit: 5e8420a, 2adf091

* [ja_JP] Japanese translation update from commit: b673651

* [ja_JP] Japanese translation update from commit: a494361, 3af2a0a, 0e765bd

* [ja_JP] Japanese translation update from commit: daa24a5

* [ja_JP] Japanese translation update from commit: daa24a5, 881aed8

* [ja_JP] Japanese translation update from commit: 98e7255

* [ja_JP] Japanese translation update from commit: 4d9e683, cd8b1fa, 0177f09

* [ja_JP] Japanese translation update from commit: a494361

* [ja_JP] Japanese translation update from commit: eee3a0c, 169a381, f4fd5e7, 6332089, 1ce9973, c05c0d3, 9268a8c, e16635a

* [ja_JP] Delete duplicate Japanese translation files

* [ja_JP] Japanese translation update from commit: c02c3a0

* [ja_JP] Japanese translation update from commit: 147d758

* [ja_JP] Japanese translation update from commit: c6e4b7a, c4e2793, 12630d4

* [ja_JP] Japanese translation update from commit: 11b09be

* [ja_JP] Japanese translation update from commit: f7e50e0, e9557b5, 4ccdaf3, 6f93ce6

* [ja_JP] Japanese translation update from commit: f7e50e0, e9557b5, e87dadd, 814353d, 35a7a66, 5d91c27

* [ja_JP] Japanese translation update from commit: f7e50e0, e9557b5, 35a7a66

* [ja_JP] Japanese translation update from commit: d880cb1, 5176f00, 814353d, 35a7a66

* [ja_JP] Japanese translation update from commit: 5e8420a, 2adf091
2026-03-30 07:52:57 +02:00
Cameron FischerandGitHub 85fb634cae Moved bulkops relink behavior into dedicated module (#9703)
* Moved bulkops relink behavior into dedicated module

* Release notes

* Fixes for lint
2026-03-28 12:06:27 +00:00
Saq ImtiazandGitHub 280701fbde Fixes MVV's so that getVariableInfo returns undefined (#9765)
* wip: non-existent variables as attributes should be undefined

* wip: non-existent variables as attributes should be undefined

* tests: added missing test

* fix: restore mistakenly commited files

* fix: whitespace
2026-03-28 12:04:29 +00:00
Saq ImtiazandGitHub 01d3cde964 Fixes an issue where blockquotes trigger parsing as macros (#9695)
* fix: blockquotes trigger parsing as macros

* fix: blockquotes trigger parsing as macros

* fix: remove backwards incompatible change

* fix: whitespace

* fix: whitespace

* merge improvents from @hoelzro
2026-03-25 12:24:32 +01:00
Jeremy Ruston 2ea3663ea7 Merge branch 'tiddlywiki-com' 2026-03-24 17:14:24 +00:00
Jeremy Ruston 78b6f6f442 Docs: clarify parameters within calls in filters 2026-03-24 12:23:58 +00:00
Jeremy Ruston 3a4a8a206f Hotfix for broken test for dates
Fixes #9726
2026-03-24 11:19:17 +00:00
Mario PietschandGitHub aff5be7195 fix flaky test runner (#9718) 2026-03-24 09:48:32 +01:00
Mario PietschandGitHub c4991a54a0 Some minor changes to the filter docs (#9709)
* Some minor changes to the filter docs

* Fix wording in Intersection Filter Run Prefix documentation
2026-03-24 09:46:03 +01:00
Mario PietschandGitHub 1d915389d9 Gitignore for automated tests (#9761)
* Add elements to gitignore, that are used for automated future test

* Add playwright configuration for Edge users that have no Chrome installed

* update tw-mcp setting
2026-03-22 08:42:13 +00:00
Mario PietschandGitHub f5b4b1781e Fix edit toolbar button spaceing (#9763) 2026-03-22 08:31:38 +00:00
Mario PietschandGitHub 65fcded29f Fix name clashes - definition tiddlers with images (#9759) 2026-03-20 07:54:03 +00:00
Urban AličandGitHub 962692c90c FIX: restore mhchem require for \ce and \pu macro support (#9756) 2026-03-19 22:34:56 +00:00
Mario PietschandGitHub 533414b1df Change codewrapping option to pre-wrap
Fixes: #9757

Changed at: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9107/changes#diff-9c7b0f26dc347b90265ea42dd89565ecf1d7b85ac8b5ff3f7dc49eeec42003b5

Talk:  https://talk.tiddlywiki.org/t/5-4-0-prerelease-code-lines-pre-wrap-setting-as-default/15066
2026-03-19 19:47:26 +01:00
HimmelandGitHub ec27a4bf20 Add new contributor Himmel to CLA (#9755) 2026-03-19 07:12:33 +00:00
Jeremy Ruston e1cf523e2c Merge branch 'tiddlywiki-com' 2026-03-17 13:20:55 +00:00
Keiran HarcombeandGitHub 1ece822d7a Update kjharcombe.tid (#9750)
I've created my community card for tiddlywiki.com
2026-03-16 23:27:50 +00:00
Keiran HarcombeandGitHub b7a3418823 Signing CLA (#9749) 2026-03-16 21:58:42 +00:00
Xavier CazinandGitHub bb6d88f144 fr-FR translation catchup before 5.4.0 (#9748)
* fr-FR translation for the Alerts aria string

* fr-FR translation for WikiInformation-related strings

* fr-FR updates for TiddlySpot/TiddlyHost-related strings

* fr-FR translation for Stability- and InfoTab-related strings
2026-03-16 17:08:06 +00:00
Jeremy Ruston 57c72756ef Fix releasenote avatars
Fixes #9746

Thanks @pmario
2026-03-16 16:57:55 +00:00
Jeremy Ruston dda4c7fb10 Update to latest version of dom-to-image-more library
Include it in tw5.com for testing
2026-03-15 16:53:51 +00:00
Jeremy Ruston fd3b96e2dd Merge branch 'tiddlywiki-com' 2026-03-15 10:46:16 +00:00
Jeremy Ruston c07396c453 Community: Add @kjharcombe as infrastructure team lead
Please add your community card when you can, many thanks.
2026-03-15 10:46:02 +00:00
Jeremy Ruston 7fc255f90c Merge branch 'tiddlywiki-com' 2026-03-14 18:18:09 +00:00
Jeremy Ruston 4cd84a6ba1 Geospatial plugin: remove residue of dom-to-image plugin
Fixes #9683
2026-03-11 17:30:23 +00:00
Jeremy Ruston fdfcd66c9b dom-to-image fix indentation 2026-03-11 17:14:47 +00:00
3983086b96 Document alternating table row styling (#9713)
* Document alternating table row styling

Resolves issue #8738 (and explains why my old wiki row styles were swapped).

* Make note more prominent

Use note macro for note

Co-authored-by: Mario Pietsch <pmariojo@gmail.com>

---------

Co-authored-by: Mario Pietsch <pmariojo@gmail.com>
2026-03-11 14:22:49 +00:00
Jeremy Ruston a61331e6ed Fix readme for tw5.com-docs plugin
Fixes #9721
2026-03-11 13:50:37 +00:00
Jeremy Ruston 8773a0433c Dynaview: Fix RSOE with Update address bar while scrolling
See https://talk.tiddlywiki.org/t/your-help-is-needed-to-test-v5-4-0/14945/52
2026-03-11 12:22:14 +00:00
Mario PietschandGitHub 846deb3039 Git Ignore Claude AI local settings (#9719) 2026-03-09 17:09:07 +00:00
Saq ImtiazandGitHub 111a168b0c feat: added community card for saqimtiaz (#9701) 2026-03-06 22:47:35 +00:00
Cameron FischerandGitHub 02b4c04a56 Release notes for PRs I've made, as requested (#9707)
* Release notes for PRs I've made, as requested

* Update #9297.tid

blog -> blob
2026-03-03 09:23:27 +01:00
Saq ImtiazandGitHub 9d5b5111d0 Revert "Add locale support for sort operator (#9400)" (#9702)
This reverts commit 98a61f01bb.
2026-03-01 08:02:18 +01:00
btheadoandGitHub 48cff401b2 Add tests/examples for transclusion shortcut syntax (#9705) 2026-03-01 07:58:59 +01:00
Saq ImtiazandGitHub 7a866b93e3 fix: alt support for images in markdown (#9700) 2026-02-27 18:53:58 +01:00
Jeremy Ruston a3acbaa2f1 Update road map 2026-02-20 09:30:25 +00:00
525 changed files with 11066 additions and 1816 deletions
+8 -8
View File
@@ -5,17 +5,17 @@ on:
- master
- tiddlywiki-com
env:
NODE_VERSION: "22"
NODE_VERSION: "22.22"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "${{ env.NODE_VERSION }}"
- run: "./bin/ci-test.sh"
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v7
if: always()
with:
name: playwright-report
@@ -30,8 +30,8 @@ jobs:
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
TW5_BUILD_OUTPUT: "./output/prerelease"
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "${{ env.NODE_VERSION }}"
- run: "./bin/ci-pre-build.sh"
@@ -62,8 +62,8 @@ jobs:
TW5_BUILD_OUTPUT: "./output"
TW5_BUILD_ARCHIVE: "./output"
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "${{ env.NODE_VERSION }}"
- run: "./bin/ci-pre-build.sh"
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
steps:
- name: build-size-check
id: get_sizes
uses: TiddlyWiki/cerebrus@v7
uses: TiddlyWiki/cerebrus@v8.1
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
@@ -52,4 +52,4 @@ jobs:
pr_size: '${{ needs.calculate-build-size.outputs.pr_size }}',
base_size: '${{ needs.calculate-build-size.outputs.base_size }}'
}
});
});
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
steps:
- name: Build and check size
uses: TiddlyWiki/cerebrus@v7
uses: TiddlyWiki/cerebrus@v8.1
with:
pr_number: ${{ inputs.pr_number }}
repo: ${{ github.repository }}
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
steps:
# Step 1: Validate PR paths
- name: Validate PR Paths
uses: TiddlyWiki/cerebrus@v6
uses: TiddlyWiki/cerebrus@v8.1
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
@@ -26,7 +26,7 @@ jobs:
# Step 2: Validate change notes
- name: Validate Change Notes
uses: TiddlyWiki/cerebrus@v7
uses: TiddlyWiki/cerebrus@v8.1
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
+11 -1
View File
@@ -2,10 +2,20 @@
.c9/
.vs/
.vscode/
.claude/
# TiddlyWiki
tmp/
output/
node_modules/
$__StoryList.tid
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
$__StoryList.tid
/playwright/.auth/
test-screenshots/
test-output.txt
.playwright-mcp
# TiddlyWiki MPC
.tw-mcp
+1
View File
@@ -3,3 +3,4 @@
tmp/
output/
node_modules/
.claude/
+1 -1
View File
@@ -5,7 +5,7 @@
# Default to the current version number for building the plugin library
if [ -z "$TW5_BUILD_VERSION" ]; then
TW5_BUILD_VERSION=v5.4.0
TW5_BUILD_VERSION=v5.5.0.
fi
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
+1 -1
View File
@@ -45,7 +45,7 @@ git clone --depth=1 --branch=main "https://github.com/TiddlyWiki/tiddlywiki.org-
# Make the CNAME file that GitHub Pages requires
echo "tiddlywiki.org" > $TWORG_BUILD_OUTPUT/CNAME
# echo "tiddlywiki.org" > $TWORG_BUILD_OUTPUT/CNAME
# Delete any existing static content
+7 -5
View File
@@ -47,6 +47,13 @@ $tw.utils.hop = function(object,property) {
/** @deprecated Use Array.isArray instead */
$tw.utils.isArray = (value) => Array.isArray(value);
/*
Determine if a value is a date, even across VM boundaries
*/
$tw.utils.isDate = function(value) {
return Object.prototype.toString.call(value) === "[object Date]";
};
/*
Check if an array is equal by value and by reference.
*/
@@ -124,9 +131,6 @@ $tw.utils.pushTop = function(array,value) {
return array;
};
/** @deprecated Use instanceof Date instead */
$tw.utils.isDate = (value) => value instanceof Date;
/** @deprecated Use array iterative methods instead */
$tw.utils.each = function(object,callback) {
if(object) {
@@ -1577,8 +1581,6 @@ $tw.Wiki.prototype.processSafeMode = function() {
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
// Set $:/DefaultTiddlers to point to our report
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
// Switch to the safe mode layout
this.addTiddler({title: "$:/layout", text: "$:/core/ui/SafeLayout"});
};
/*
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,7 @@
created: 20250909171928024
modified: 20251110133437795
tags: Community/Team
leader: @kjharcombe
team: @MotovunJack
title: Infrastructure Team
@@ -12,4 +13,4 @@ The infrastructure includes:
* github.com/TiddlyWiki
* tiddlywiki.com DNS
* Netlify account for PR previews
* edit.tiddlywiki.com
* edit.tiddlywiki.com
@@ -0,0 +1,8 @@
title: TiddlyWiki Team
tags: Community/Team
modified: 20260708095630754
created: 20260708095630754
leader: @BurningTreeC
team:
The TiddlyDesktop development repository is at https://github.com/TiddlyWiki/TiddlyDesktop
+1 -1
View File
File diff suppressed because one or more lines are too long
+33 -5
View File
@@ -217,6 +217,11 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
fileInfo.isEditableFile = true;
fileInfo.originalpath = options.fileInfo.originalpath;
}
// Propagate the pinFilepath flag (so generateTiddlerFilepath can short-circuit
// FileSystemPaths and write back to the original location)
if(options.fileInfo && !!options.fileInfo.pinFilepath) {
fileInfo.pinFilepath = true;
}
// Check if the tiddler has any unsafe fields that can't be expressed in a .tid or .meta file: containing control characters, or leading/trailing whitespace
var hasUnsafeFields = false;
$tw.utils.each(tiddler.getFieldStrings(),function(value,fieldName) {
@@ -319,9 +324,16 @@ exports.generateTiddlerFilepath = function(title,options) {
extension = options.extension || "",
originalpath = (options.fileInfo && options.fileInfo.originalpath) ? options.fileInfo.originalpath : "",
overwrite = options.fileInfo && options.fileInfo.overwrite || false,
pinFilepath = !!(options.fileInfo && options.fileInfo.pinFilepath),
filepath;
// If the tiddler's filepath is pinned via tiddlywiki.files, the originalpath
// wins and the path filters are skipped entirely.
if(pinFilepath && originalpath) {
var pinnedExt = path.extname(originalpath);
filepath = originalpath.substring(0,originalpath.length - pinnedExt.length);
}
// Check if any of the pathFilters applies
if(options.pathFilters && options.wiki) {
if(!filepath && options.pathFilters && options.wiki) {
$tw.utils.each(options.pathFilters,function(filter) {
if(!filepath) {
var source = options.wiki.makeTiddlerIterator([title]),
@@ -336,13 +348,14 @@ exports.generateTiddlerFilepath = function(title,options) {
//Use the originalpath without the extension
var ext = path.extname(originalpath);
filepath = originalpath.substring(0,originalpath.length - ext.length);
// normalise "\" to "/" so the sanitiser keeps subdirectories
// (it strips "\", not "/") instead of flattening them.
filepath = filepath.split(path.sep).join("/");
} else if(!filepath) {
filepath = title;
// Remove any forward or backward slashes so we don't create directories
filepath = filepath.replace(/\/|\\/g,"_");
}
// Replace any Windows control codes
filepath = filepath.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i,"_$1_");
// Replace any leading spaces with the same number of underscores
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_");});
//If the path does not start with "." or ".." && a path seperator, then
@@ -352,8 +365,23 @@ exports.generateTiddlerFilepath = function(title,options) {
}
// Replace any Unicode control codes
filepath = filepath.replace(/[\x00-\x1f\x80-\x9f]/g,"_");
// Replace any characters that can't be used in cross-platform filenames
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
// Replace any characters that can't be used in cross-platform filenames.
if(!pinFilepath) {
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^|\\/g,"_"));
}
// Per segment (catches "sub/CON"), MUST be after transliterate which can create a
// reserved name. Reserved names are wrapped on every path incl pinned;
// trailing dots/spaces (Windows strips) fixed for generated names, not pinned.
filepath = filepath.split("/").map(function(segment) {
if(segment === "" || segment === "." || segment === "..") {
return segment;
}
segment = segment.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i,"_$1_");
if(!pinFilepath) {
segment = segment.replace(/[. ]+$/,function(u) { return u.replace(/[. ]/g,"_"); });
}
return segment;
}).join("/");
// Replace any dots or spaces at the end of the extension with the same number of underscores
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_");});
// Truncate the extension if it is too long
+4 -5
View File
@@ -9,15 +9,14 @@ Serve tiddlers over http
"use strict";
let fs, url, path, querystring, crypto, zlib;
let fs, path, crypto, zlib, URL;
if($tw.node) {
fs = require("fs"),
url = require("url"),
path = require("path"),
querystring = require("querystring"),
crypto = require("crypto"),
zlib = require("zlib");
URL = require("url").URL;
}
/*
@@ -260,8 +259,8 @@ Server.prototype.requestHandler = function(request,response,options) {
state.wiki = options.wiki || self.wiki;
state.boot = options.boot || self.boot;
state.server = self;
state.urlInfo = url.parse(request.url);
state.queryParameters = querystring.parse(state.urlInfo.query);
state.urlInfo = new URL(request.url, "http://localhost");
state.queryParameters = Object.fromEntries(state.urlInfo.searchParams);
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
// Enable CORS
if(this.corsEnable) {
+2 -1
View File
@@ -255,4 +255,5 @@ ViewTemplateTags/Caption: View Template Tags
ViewTemplateTags/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the tags area of a tiddler.
WikiInformation/Caption: Wiki Information
WikiInformation/Hint: This page summarises high level information about the configuration of this ~TiddlyWiki. It is designed to enable users to quickly share relevant aspects of the configuration of their ~TiddlyWiki with others, for example when seeking help in one of the forums. No private or personal information is included, and nothing is shared without being explicitly copied and pasted elsewhere
WikiInformation/Drag/Caption: Drag this link to copy this tool to another wiki
WikiInformation/Drag/Caption: Drag this link to copy this tool to another wiki
WikiInformation/Generate/Caption: Click to generate wiki information report
-1
View File
@@ -59,7 +59,6 @@ Manager/Controls/Show/Option/Tiddlers: tiddlers
Manager/Controls/Show/Prompt: Show:
Manager/Controls/Sort/Prompt: Sort by:
Manager/Item/Colour: Colour
Manager/Item/Editor: Editor
Manager/Item/Fields: Fields
Manager/Item/Icon/None: (none)
Manager/Item/Icon: Icon
+1 -1
View File
@@ -10,7 +10,7 @@ Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text te
Advanced/ShadowInfo/Shadow/Source: It is defined in the plugin <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>
Advanced/ShadowInfo/OverriddenShadow/Hint: It is overridden by an ordinary tiddler
Advanced/CascadeInfo/Heading: Cascade Details
Advanced/CascadeInfo/Hint: These are the view template segments (tagged <<tag "$:/tags/ViewTemplate">>) using a cascade filter and their resulting template for the current tiddler.
Advanced/CascadeInfo/Hint: These are the view template segments that are resolved for each of the system view template cascades
Advanced/CascadeInfo/Detail/View: View
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Active cascade filter
Advanced/CascadeInfo/Detail/Template: Template
+1 -1
View File
@@ -78,7 +78,6 @@ class BackgroundActionTracker {
fnProcess: (changes) => {
if(this.hasChanged) {
this.hasChanged = false;
console.log("Processing background action", this.title);
const tiddler = this.wiki.getTiddler(this.title);
let doActions = true;
if(tiddler && tiddler.fields.platforms) {
@@ -89,6 +88,7 @@ class BackgroundActionTracker {
}
}
if(doActions) {
console.log("Processing background action", this.title);
this.wiki.invokeActionString(
this.actions,
null,
+2 -3
View File
@@ -156,14 +156,13 @@ Fix the height of textarea to fit content
FramedEngine.prototype.fixHeight = function() {
// Make sure styles are updated
this.copyStyles();
// If .editRows is initialised, it takes precedence
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
if(this.widget.editTag === "textarea") {
if(this.widget.editAutoHeight) {
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
this.iframeNode.style.height = newHeight + "px";
}
} else {
} else if(!this.widget.editRows) {
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
fixedHeight = Math.max(fixedHeight,20);
this.domNode.style.height = fixedHeight + "px";
+2 -3
View File
@@ -100,13 +100,12 @@ SimpleEngine.prototype.getText = function() {
Fix the height of textarea to fit content
*/
SimpleEngine.prototype.fixHeight = function() {
// If .editRows is initialised, it takes precedence
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
if(this.widget.editTag === "textarea") {
if(this.widget.editAutoHeight) {
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
}
} else {
} else if(!this.widget.editRows) {
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
fixedHeight = Math.max(fixedHeight,20);
this.domNode.style.height = fixedHeight + "px";
+27 -1
View File
@@ -210,6 +210,29 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.editShowToolbar = this.wiki.getTiddlerText(ENABLE_TOOLBAR_TITLE,"yes");
this.editShowToolbar = (this.editShowToolbar === "yes") && !!(this.children && this.children.length > 0) && (!this.document.isTiddlyWikiFakeDom);
};
EditTextWidget.prototype.updateDomNodeClasses = function() {
var domNodeClasses = this.engine.domNode.className.split(/\s+/).filter(Boolean),
oldClasses = this.editClass.split(/\s+/).filter(Boolean),
newClasses;
this.editClass = this.getAttribute("class","");
newClasses = this.editClass.split(/\s+/).filter(Boolean);
// Remove classes assigned from the old value of the class attribute
domNodeClasses = domNodeClasses.filter(function(className) {
return !oldClasses.includes(className);
});
// Add new classes from the updated class attribute
domNodeClasses = domNodeClasses.concat(
newClasses.filter(function(className) {
return !domNodeClasses.includes(className);
})
);
this.engine.domNode.className = domNodeClasses.join(" ");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
@@ -217,7 +240,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
EditTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Completely rerender if any of our attributes have changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
this.refreshSelf();
return true;
} else if(changedTiddlers[this.editRefreshTitle]) {
@@ -226,6 +249,9 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
var editInfo = this.getEditInfo();
this.updateEditor(editInfo.value,editInfo.type);
}
if(changedAttributes["class"]) {
this.updateDomNodeClasses();
}
this.engine.fixHeight();
if(this.editShowToolbar) {
return this.refreshChildren(changedTiddlers);
@@ -13,14 +13,15 @@ Export our filter prefix function
exports.intersection = function(operationSubFunction) {
return function(results,source,widget) {
if(results.length !== 0) {
var secondRunResults = operationSubFunction(source,widget);
var firstRunResults = results.toArray();
const secondRunResults = operationSubFunction(source,widget),
secondRunSet = new Set(secondRunResults),
firstRunResults = results.toArray();
results.clear();
$tw.utils.each(firstRunResults,function(title) {
if(secondRunResults.indexOf(title) !== -1) {
firstRunResults.forEach((title) => {
if(secondRunSet.has(title)) {
results.push(title);
}
});
}
};
};
};
+15 -20
View File
@@ -13,33 +13,28 @@ Export our filter prefix function
exports.sort = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
var suffixes = options.suffixes,
const suffixes = options.suffixes,
sortType = (suffixes[0] && suffixes[0][0]) ? suffixes[0][0] : "string",
invert = suffixes[1] ? (suffixes[1].indexOf("reverse") !== -1) : false,
isCaseSensitive = suffixes[1] ? (suffixes[1].indexOf("casesensitive") !== -1) : false,
invert = suffixes[1] ? suffixes[1].includes("reverse") : false,
isCaseSensitive = suffixes[1] ? suffixes[1].includes("casesensitive") : false,
inputTitles = results.toArray(),
sortKeys = [],
indexes = new Array(inputTitles.length),
compareFn;
results.each(function(title) {
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
}));
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
results.each((title) => {
const key = operationSubFunction(
options.wiki.makeTiddlerIterator([title]),
widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
})
);
sortKeys.push(key[0] || "");
});
results.clear();
// Prepare an array of indexes to sort
for(var t=0; t<inputTitles.length; t++) {
indexes[t] = t;
}
// Sort the indexes
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
indexes = indexes.sort(function(a,b) {
return compareFn(sortKeys[a],sortKeys[b]);
});
// Add to results in correct order
$tw.utils.each(indexes,function(index) {
let indexes = Array.from(inputTitles.keys());
indexes.sort((a,b) => compareFn(sortKeys[a],sortKeys[b]));
indexes.forEach((index) => {
results.push(inputTitles[index]);
});
}
+1 -1
View File
@@ -296,7 +296,7 @@ exports.compileFilter = function(filterString) {
var varTree = $tw.utils.parseFilterVariable(operand.text);
var resultList = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source});
if((resultList.length > 0 && resultList[0] !== undefined) || resultList.length === 0) {
operand.multiValue = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}) || [];
operand.multiValue = resultList || [];
operand.value = operand.multiValue[0] || "";
} else {
operand.value = "";
+30 -54
View File
@@ -9,69 +9,56 @@ Filter operators for manipulating the current selection list
"use strict";
/*
Fetch titles from the current list
*/
const prepare_results = (source) => {
const results = [];
source((tiddler,title) => results.push(title));
return results;
};
/*
Order a list
*/
exports.order = function(source,operator,options) {
var results = [];
if(operator.operand.toLowerCase() === "reverse") {
source(function(tiddler,title) {
results.unshift(title);
});
} else {
source(function(tiddler,title) {
results.push(title);
});
}
return results;
const results = prepare_results(source);
return operator.operand.toLowerCase() === "reverse" ?
results.reverse() :
results;
};
/*
Reverse list
*/
exports.reverse = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.unshift(title);
});
return results;
return prepare_results(source).reverse();
};
/*
First entry/entries in list
*/
exports.first = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,1),
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(0,count);
const count = $tw.utils.getInt(operator.operand,1);
return prepare_results(source).slice(0,count);
};
/*
Last entry/entries in list
*/
exports.last = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,1),
results = [];
if(count === 0) return results;
source(function(tiddler,title) {
results.push(title);
});
return results.slice(-count);
const count = $tw.utils.getInt(operator.operand,1);
return count === 0 ?
[] :
prepare_results(source).slice(-count);
};
/*
All but the first entry/entries of the list
*/
exports.rest = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,1),
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(count);
const count = $tw.utils.getInt(operator.operand,1);
return prepare_results(source).slice(count);
};
exports.butfirst = exports.rest;
exports.bf = exports.rest;
@@ -80,12 +67,9 @@ exports.bf = exports.rest;
All but the last entry/entries of the list
*/
exports.butlast = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,1),
results = [];
source(function(tiddler,title) {
results.push(title);
});
var index = count === 0 ? results.length : -count;
const count = $tw.utils.getInt(operator.operand,1),
results = prepare_results(source),
index = count === 0 ? results.length : -count;
return results.slice(0,index);
};
exports.bl = exports.butlast;
@@ -94,22 +78,14 @@ exports.bl = exports.butlast;
The nth member of the list
*/
exports.nth = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,1),
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(count - 1,count);
const count = $tw.utils.getInt(operator.operand,1);
return prepare_results(source).slice(count - 1,count);
};
/*
The zero based nth member of the list
*/
exports.zth = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,0),
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(count,count + 1);
};
const count = $tw.utils.getInt(operator.operand,0);
return prepare_results(source).slice(count,count + 1);
};
+17 -32
View File
@@ -13,37 +13,22 @@ Filter operator for checking if a title starts with a prefix
Export our filter function
*/
exports.prefix = function(source,operator,options) {
var results = [],
suffixes = (operator.suffixes || [])[0] || [];
if(suffixes.indexOf("caseinsensitive") !== -1) {
var operand = operator.operand.toLowerCase();
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title.toLowerCase().substr(0,operand.length) !== operand) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(title.toLowerCase().substr(0,operand.length) === operand) {
results.push(title);
}
});
const results = [],
suffixes = (operator.suffixes || [])[0] || [],
caseInsensitive = suffixes.includes("caseinsensitive"),
negate = operator.prefix === "!";
const operand = caseInsensitive ?
operator.operand.toLowerCase() :
operator.operand;
source((tiddler,title) => {
const value = caseInsensitive ? title.toLowerCase() : title,
matches = value.startsWith(operand);
if(negate ? !matches : matches) {
results.push(title);
}
} else {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title.substr(0,operator.operand.length) !== operator.operand) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(title.substr(0,operator.operand.length) === operator.operand) {
results.push(title);
}
});
}
}
});
return results;
};
};
+5 -5
View File
@@ -14,31 +14,31 @@ Export our filter function
*/
exports.sort = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
return results;
};
exports.nsort = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
return results;
};
exports.sortan = function(source, operator, options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]);
options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
return results;
};
exports.sortcs = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
return results;
};
exports.nsortcs = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
return results;
};
+7 -12
View File
@@ -14,13 +14,13 @@ Export our filter function
*/
exports.sortsub = function(source,operator,options) {
// Compile the subfilter
var filterFn = options.wiki.compileFilter(operator.operand);
let filterFn = options.wiki.compileFilter(operator.operand);
// Collect the input titles and the corresponding sort keys
var inputTitles = [],
let inputTitles = [],
sortKeys = [];
source(function(tiddler,title) {
inputTitles.push(title);
var r = filterFn.call(options.wiki,function(iterator) {
let r = filterFn.call(options.wiki,function(iterator) {
iterator(options.wiki.getTiddler(title),title);
},options.widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
@@ -29,17 +29,12 @@ exports.sortsub = function(source,operator,options) {
sortKeys.push(r[0] || "");
});
// Rather than sorting the titles array, we'll sort the indexes so that we can consult both arrays
var indexes = new Array(inputTitles.length);
for(var t=0; t<inputTitles.length; t++) {
indexes[t] = t;
}
let indexes = Array.from(inputTitles.keys());
// Sort the indexes
var compareFn = $tw.utils.makeCompareFunction(operator.suffix,{defaultType: "string",invert: operator.prefix === "!"});
indexes = indexes.sort(function(a,b) {
return compareFn(sortKeys[a],sortKeys[b]);
});
let compareFn = $tw.utils.makeCompareFunction(operator.suffix,{defaultType: "string",invert: operator.prefix === "!"});
indexes = indexes.sort((a,b) => compareFn(sortKeys[a],sortKeys[b]));
// Make the results array in order
var results = [];
let results = [];
$tw.utils.each(indexes,function(index) {
results.push(inputTitles[index]);
});
+26 -13
View File
@@ -91,22 +91,35 @@ function diffLineWordMode(text1,text2,mode) {
return diffs;
}
exports.makepatches = function(source,operator,options) {
var suffix = operator.suffix || "",
result = [];
source(function(tiddler,title) {
let diffs, patches;
if(suffix === "lines" || suffix === "words") {
diffs = diffLineWordMode(title,operator.operand,suffix);
patches = dmp.patchMake(title,diffs);
exports.makepatches = function(source, operator, options) {
const suffixes = operator.suffixes || [],
[modeArg = [], formatArg = []] = suffixes,
modeSuffix = modeArg[0] || operator.suffix || "",
mode = ["lines", "words"].includes(modeSuffix) ? modeSuffix : "",
isJson = formatArg[0] === "json",
results = [];
source((tiddler, title) => {
if (isJson) {
const diffs = (mode === "lines" || mode === "words")
? diffLineWordMode(title, operator.operand, mode)
: dmp.diffMain(title, operator.operand);
const jsonOutput = diffs.map(([typeCode, text]) => ({
type: typeCode === 1 ? "insert" : (typeCode === -1 ? "delete" : "equal"),
text
}));
results.push(JSON.stringify(jsonOutput));
} else {
patches = dmp.patchMake(title,operator.operand);
const patches = (mode === "lines" || mode === "words")
? dmp.patchMake(title, diffLineWordMode(title, operator.operand, mode))
: dmp.patchMake(title, operator.operand);
results.push(dmp.patchToText(patches));
}
Array.prototype.push.apply(result,[dmp.patchToText(patches)]);
});
return result;
return results;
};
exports.applypatches = makeStringBinaryOperator(
@@ -235,4 +248,4 @@ exports.charcode = function(source,operator,options) {
}
});
return [chars.join("")];
};
};
+5 -4
View File
@@ -13,11 +13,12 @@ Filter operator returning its operand evaluated as a filter
Export our filter function
*/
exports.subfilter = function(source,operator,options) {
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source);
const list = options.wiki.filterTiddlers(operator.operand,options.widget,source);
if(operator.prefix === "!") {
var results = [];
source(function(tiddler,title) {
if(list.indexOf(title) === -1) {
const results = [],
listSet = new Set(list);
source((tiddler,title) => {
if(!listSet.has(title)) {
results.push(title);
}
});
+17 -31
View File
@@ -13,41 +13,27 @@ Filter operator for checking if a title ends with a suffix
Export our filter function
*/
exports.suffix = function(source,operator,options) {
var results = [],
const results = [],
suffixes = (operator.suffixes || [])[0] || [];
if(!operator.operand) {
source(function(tiddler,title) {
source((tiddler,title) => {
results.push(title);
});
} else if(suffixes.indexOf("caseinsensitive") !== -1) {
var operand = operator.operand.toLowerCase();
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title.toLowerCase().substr(-operand.length) !== operand) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(title.toLowerCase().substr(-operand.length) === operand) {
results.push(title);
}
});
}
} else {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title.substr(-operator.operand.length) !== operator.operand) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(title.substr(-operator.operand.length) === operator.operand) {
results.push(title);
}
});
}
return results;
}
const caseInsensitive = suffixes.indexOf("caseinsensitive") !== -1,
negate = operator.prefix === "!",
operand = caseInsensitive ? operator.operand.toLowerCase() : operator.operand;
source((tiddler,title) => {
const value = caseInsensitive ? title.toLowerCase() : title,
matches = value.endsWith(operand);
if(negate ? !matches : matches) {
results.push(title);
}
});
return results;
};
+4 -5
View File
@@ -22,12 +22,11 @@ exports.tag = function(source,operator,options) {
});
} else {
// Old semantics:
var tiddlers;
if(operator.prefix === "!") {
// Returns a copy of the input if operator.operand is missing
tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
const excludeTagSet = new Set(options.wiki.getTiddlersWithTag(operator.operand));
source(function(tiddler,title) {
if(tiddlers.indexOf(title) === -1) {
if(!excludeTagSet.has(title)) {
results.push(title);
}
});
@@ -39,9 +38,9 @@ exports.tag = function(source,operator,options) {
return indexedResults;
}
} else {
tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
const includeTagSet = new Set(options.wiki.getTiddlersWithTag(operator.operand));
source(function(tiddler,title) {
if(tiddlers.indexOf(title) !== -1) {
if(includeTagSet.has(title)) {
results.push(title);
}
});
+76 -81
View File
@@ -11,20 +11,18 @@ Extended filter operators to manipulate the current list.
/*
Fetch titles from the current list
*/
var prepare_results = function (source) {
var results = [];
source(function (tiddler, title) {
results.push(title);
});
*/
const prepare_results = (source) => {
const results = [];
source((tiddler,title) => results.push(title));
return results;
};
/*
Moves a number of items from the tail of the current list before the item named in the operand
*/
exports.putbefore = function (source, operator) {
var results = prepare_results(source),
*/
exports.putbefore = function(source,operator) {
const results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
@@ -34,9 +32,9 @@ exports.putbefore = function (source, operator) {
/*
Moves a number of items from the tail of the current list after the item named in the operand
*/
exports.putafter = function (source, operator) {
var results = prepare_results(source),
*/
exports.putafter = function(source,operator) {
const results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
@@ -46,9 +44,9 @@ exports.putafter = function (source, operator) {
/*
Replaces the item named in the operand with a number of items from the tail of the current list
*/
exports.replace = function (source, operator) {
var results = prepare_results(source),
*/
exports.replace = function(source,operator) {
const results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
@@ -58,39 +56,39 @@ exports.replace = function (source, operator) {
/*
Moves a number of items from the tail of the current list to the head of the list
*/
exports.putfirst = function (source, operator) {
var results = prepare_results(source),
*/
exports.putfirst = function(source,operator) {
const results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1);
return results.slice(-count).concat(results.slice(0, -count));
return [...results.slice(-count), ...results.slice(0, -count)];
};
/*
Moves a number of items from the head of the current list to the tail of the list
*/
exports.putlast = function (source, operator) {
var results = prepare_results(source),
*/
exports.putlast = function(source,operator) {
const results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1);
return results.slice(count).concat(results.slice(0, count));
return [...results.slice(count), ...results.slice(0, count)];
};
/*
Moves the item named in the operand a number of places forward or backward in the list
*/
exports.move = function (source, operator) {
var results = prepare_results(source),
*/
exports.move = function(source,operator) {
const results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1),
marker = results.splice(index, 1),
offset = (index + count) > 0 ? index + count : 0;
offset = (index + count) > 0 ? index + count : 0;
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
};
/*
Returns the items from the current list that are after the item named in the operand
*/
exports.allafter = function (source, operator) {
var results = prepare_results(source),
*/
exports.allafter = function(source,operator) {
const results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1) ? [] :
(operator.suffix) ? results.slice(index) :
@@ -99,9 +97,9 @@ exports.allafter = function (source, operator) {
/*
Returns the items from the current list that are before the item named in the operand
*/
exports.allbefore = function (source, operator) {
var results = prepare_results(source),
*/
exports.allbefore = function(source,operator) {
const results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1) ? [] :
(operator.suffix) ? results.slice(0, index + 1) :
@@ -110,9 +108,9 @@ exports.allbefore = function (source, operator) {
/*
Appends the items listed in the operand array to the tail of the current list
*/
exports.append = function (source, operator) {
var append = $tw.utils.parseStringArray(operator.operand, "true"),
*/
exports.append = function(source,operator) {
const append = $tw.utils.parseStringArray(operator.operand,"true"),
results = prepare_results(source),
count = parseInt(operator.suffix) || append.length;
return (append.length === 0) ? results :
@@ -122,9 +120,9 @@ exports.append = function (source, operator) {
/*
Prepends the items listed in the operand array to the head of the current list
*/
exports.prepend = function (source, operator) {
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
*/
exports.prepend = function(source,operator) {
const prepend = $tw.utils.parseStringArray(operator.operand,"true"),
results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,prepend.length);
return (prepend.length === 0) ? results :
@@ -134,21 +132,19 @@ exports.prepend = function (source, operator) {
/*
Returns all items from the current list except the items listed in the operand array
*/
exports.remove = function (source, operator) {
var array = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = parseInt(operator.suffix) || array.length,
p,
len,
index;
len = array.length - 1;
for(p = 0; p < count; ++p) {
if(operator.prefix) {
index = results.indexOf(array[len - p]);
} else {
index = results.indexOf(array[p]);
}
*/
exports.remove = function(source, operator) {
const array = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source);
if(array.length === 0) {
return results;
}
const count = parseInt(operator.suffix, 10) || array.length,
targetItems = operator.prefix ? array.slice(-count).reverse() : array.slice(0, count);
for(const item of targetItems) {
const index = results.indexOf(item);
if(index !== -1) {
results.splice(index, 1);
}
@@ -158,40 +154,38 @@ exports.remove = function (source, operator) {
/*
Returns all items from the current list sorted in the order of the items in the operand array
*/
exports.sortby = function (source, operator) {
var results = prepare_results(source);
*/
exports.sortby = function(source,operator) {
const results = prepare_results(source);
if(!results || results.length < 2) {
return results;
}
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
results.sort(function (a, b) {
return lookup.indexOf(a) - lookup.indexOf(b);
});
return results;
const lookup = $tw.utils.parseStringArray(operator.operand,"true"),
// The "end" suffix places unlisted titles last, the default is first
unlisted = operator.suffix === "end" ? lookup.length : -1,
position = (title) => {
const index = lookup.indexOf(title);
return index === -1 ? unlisted : index;
};
return results.sort((a,b) => position(a) - position(b));
};
/*
Removes all duplicate items from the current list
*/
exports.unique = function (source, operator) {
var results = prepare_results(source);
var set = results.reduce(function (a, b) {
if(a.indexOf(b) < 0) {
a.push(b);
}
return a;
}, []);
return set;
*/
exports.unique = function(source, operator) {
return Array.from(new Set(prepare_results(source)));
};
var cycleValueInArray = function(results,operands,stepSize) {
var resultsIndex,
const cycleValueInArray = function(results,operands,stepSize) {
let resultsIndex,
step = stepSize || 1,
i = 0,
opLength = operands.length,
nextOperandIndex;
for(i; i < opLength; i++) {
const opLength = operands.length;
for(; i < opLength; i++) {
resultsIndex = results.indexOf(operands[i]);
if(resultsIndex !== -1) {
break;
@@ -213,18 +207,19 @@ var cycleValueInArray = function(results,operands,stepSize) {
/*
Toggles an item in the current list.
*/
*/
exports.toggle = function(source,operator) {
return cycleValueInArray(prepare_results(source),operator.operands);
};
exports.cycle = function(source,operator) {
var results = prepare_results(source),
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
step = $tw.utils.getInt(operator.operands[1]||"",1);
const results = prepare_results(source),
operands = operator.operand.length ? $tw.utils.parseStringArray(operator.operand,"true") : [""];
let step = $tw.utils.getInt(operator.operands[1] || "",1);
if(step < 0) {
operands.reverse();
step = Math.abs(step);
}
return cycleValueInArray(results,operands,step);
};
};
+3 -2
View File
@@ -88,10 +88,11 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
var newTargets = [],
oldTargets = [],
self = this;
if(updateDescriptor.old.exists) {
// System tiddlers are never indexed as sources, matching the _init() scan
if(updateDescriptor.old.exists && !this.wiki.isSystemTiddler(updateDescriptor.old.tiddler.fields.title)) {
oldTargets = this._getTarget(updateDescriptor.old.tiddler);
}
if(updateDescriptor.new.exists) {
if(updateDescriptor.new.exists && !this.wiki.isSystemTiddler(updateDescriptor.new.tiddler.fields.title)) {
newTargets = this._getTarget(updateDescriptor.new.tiddler);
}
+151 -114
View File
@@ -107,7 +107,7 @@ exports.parseStringLiteral = function(source,pos) {
type: "string",
start: pos
};
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[((?:[^\]]|\](?!\]))*)\]\]/g;
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[((?:[^\]]|\](?!\]))*)\]\]/y;
reString.lastIndex = pos;
var match = reString.exec(source);
if(match && match.index === pos) {
@@ -221,7 +221,7 @@ exports.parseMacroInvocationAsTransclusion = function(source,pos) {
orderedAttributes: []
};
// Define our regexps
var reVarName = /([^\s>"'=:]+)/g;
var reVarName = /([^\s>"'=]+)/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double opening angle bracket
@@ -237,9 +237,11 @@ exports.parseMacroInvocationAsTransclusion = function(source,pos) {
}
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
pos = token.end;
// Check that the tag is terminated by a space or >>
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
return null;
// Check that the tag is terminated by a space or >>, and that there is a closing >> somewhere ahead
if(!(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
if(source.indexOf(">>",pos) === -1) {
return null;
}
}
// Process attributes
pos = $tw.utils.parseMacroParametersAsAttributes(node,source,pos);
@@ -267,7 +269,7 @@ exports.parseMVVReferenceAsTransclusion = function(source,pos) {
orderedAttributes: []
};
// Define our regexps
var reVarName = /([^\s>"'=:)]+)/g;
var reVarName = /([^\s>"'=)]+)/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double opening parenthesis
@@ -323,18 +325,24 @@ exports.parseMacroParameterAsAttribute = function(source,pos) {
start: pos
};
// Define our regexps
var reAttributeName = /([^\/\s>"'`=:]+)/g,
reUnquotedAttribute = /((?:(?:>(?!>))|[^\s>"'])+)/g,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
var reAttributeName = /([^\/\s>"'`=:]+)/y,
reStrictIdentifier = /^[A-Za-z0-9\-_]+$/,
reUnquotedAttribute = /(?!<<)((?:(?:>(?!>))|[^\s>"'])+)/y,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
reIndirectValue = /\{\{([^\}]+)\}\}/y,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the attribute name and the separator token
var nameToken = $tw.utils.parseTokenRegExp(source,pos,reAttributeName),
namePos = nameToken && $tw.utils.skipWhiteSpace(source,nameToken.end),
separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/g),
separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/y),
isNewStyleSeparator = false; // If there is no separator then we don't allow new style values
// Colon separator requires a strict identifier name to avoid mis-parsing values like $:/foo
if(nameToken && separatorToken && separatorToken.match[0] === ":" && !reStrictIdentifier.test(nameToken.match[1])) {
nameToken = null;
separatorToken = null;
}
// If we have a name and a separator then we have a named attribute
if(nameToken && separatorToken) {
node.name = nameToken.match[1];
@@ -345,64 +353,78 @@ exports.parseMacroParameterAsAttribute = function(source,pos) {
}
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
// Mark the value as having been quoted in the source
node.quoted = true;
} else {
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue && isNewStyleSeparator) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
} else {
do {
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
// Mark the value as having been quoted in the source
node.quoted = true;
break;
}
if(isNewStyleSeparator) {
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
break;
}
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue && isNewStyleSeparator) {
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation && isNewStyleSeparator) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference && isNewStyleSeparator) {
pos = mvvReference.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
} else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue && isNewStyleSeparator) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
}
}
}
}
break;
}
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
break;
}
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference) {
pos = mvvReference.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
break;
}
// Look for a substituted value
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
break;
}
}
}
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
break; // redundant, but leaving for consistency
}
} while(false);
// Bail if we don't have a value
if(!node.type) {
return null;
@@ -506,64 +528,79 @@ exports.parseAttribute = function(source,pos) {
pos = token.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
} else {
do {
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
break;
}
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
} else {
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference) {
pos = mvvReference.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
} else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
node.type = "string";
node.value = "true";
}
}
}
}
}
break;
}
}
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
break;
}
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
break;
}
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference) {
pos = mvvReference.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
break;
}
// Look for a substituted value
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
break;
}
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
break;
}
if(source.charAt(pos) === "<" && source.charAt(pos + 1) === "<" && source.indexOf(">>",pos) !== -1) {
// Value looks like a macro invocation (starts with << with a closing >> ahead) but does not parse as one. Return null so the enclosing tag fails to parse rather than silently binding the attribute to "true" and treating the remainder as further attributes (restores v5.3.8 behaviour)
return null;
}
node.type = "string";
node.value = "true";
} while(false);
} else {
// If there is no equals sign or colon, then this is an attribute with no value, defaulting to "true"
node.type = "string";
@@ -25,7 +25,7 @@ exports.init = function(parser) {
};
exports.parse = function() {
var reEnd = /(\r?\n```$)/mg;
var reEnd = /(^|\r?\n)```$/mg;
var languageStart = this.parser.pos + 3,
languageEnd = languageStart + this.match[1].length;
// Move past the match
@@ -31,13 +31,16 @@ exports.parse = function() {
reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source),
text,
start = this.parser.pos;
start = this.parser.pos,
textEnd;
// Process the text
if(match) {
text = this.parser.source.substring(this.parser.pos,match.index);
textEnd = match.index;
this.parser.pos = match.index + match[0].length;
} else {
text = this.parser.source.substr(this.parser.pos);
textEnd = this.parser.sourceLength;
this.parser.pos = this.parser.sourceLength;
}
return [{
@@ -47,7 +50,7 @@ exports.parse = function() {
type: "text",
text: text,
start: start,
end: this.parser.pos
end: textEnd
}]
}];
};
@@ -32,7 +32,8 @@ exports.parse = function() {
this.parser.pos = this.matchRegExp.lastIndex;
// Create the link unless it is suppressed
if(this.match[0].substr(0,1) === "~") {
return [{type: "text", text: this.match[0].substr(1), start: start, end: this.parser.pos}];
// Start after the suppressing "~" so the span matches the plain text
return [{type: "text", text: this.match[0].substr(1), start: start + 1, end: this.parser.pos}];
} else {
return [{
type: "element",
@@ -34,7 +34,7 @@ exports.parse = function() {
// Parse the filter terminated by a line break
var reMatch = /(.*)(?:$|\r?\n)/mg;
reMatch.lastIndex = this.parser.pos;
var filterStart = this.parser.source;
var filterStart = this.parser.pos;
var match = reMatch.exec(this.parser.source);
this.parser.pos = reMatch.lastIndex;
// Parse tree nodes to return
@@ -27,9 +27,11 @@ Parse the most recent match
*/
exports.parse = function() {
// Get the details of the match
var linkText = this.match[0];
var linkText = this.match[0],
// Start after the suppressing "~" so the span matches the plain text
start = this.parser.pos + 1;
// Move past the wikilink
this.parser.pos = this.matchRegExp.lastIndex;
// Return the link without unwikilink character as plain text
return [{type: "text", text: linkText.substr(1)}];
return [{type: "text", text: linkText.substr(1), start: start, end: this.parser.pos}];
};
+54
View File
@@ -0,0 +1,54 @@
/*\
title: $:/core/modules/relinkers/tiddlers.js
type: application/javascript
module-type: relinker
Relinks the tags and list fields of tiddlers.
Calls a tw-relinking-tiddler hook for every altered tiddler.
\*/
exports.name = "tiddlers";
exports.relink = function(wiki,fromTitle,toTitle,options) {
wiki.each(function(tiddler,title) {
var type = tiddler.fields.type || "";
// Don't touch plugins or JavaScript modules
if(!tiddler.fields["plugin-type"] && type !== "application/javascript") {
var tags = tiddler.fields.tags ? tiddler.fields.tags.slice(0) : undefined,
list = tiddler.fields.list ? tiddler.fields.list.slice(0) : undefined,
isModified = false,
processList = function(listField) {
if(listField && listField.indexOf(fromTitle) !== -1) {
// Remove any existing instances of the toTitle
var p = listField.indexOf(toTitle);
while(p !== -1) {
listField.splice(p,1);
p = listField.indexOf(toTitle);
}
// Replace the fromTitle with toTitle
$tw.utils.each(listField,function (title,index) {
if(title === fromTitle) {
listField[index] = toTitle;
isModified = true;
}
});
}
};
if(!options.dontRenameInTags) {
// Rename tags
processList(tags);
}
if(!options.dontRenameInLists) {
// Rename lists
processList(list);
}
if(isModified) {
var newTiddler = new $tw.Tiddler(tiddler,{tags: tags, list: list},wiki.getModificationFields());
newTiddler = $tw.hooks.invokeHook("th-relinking-tiddler",newTiddler,tiddler);
wiki.addTiddler(newTiddler);
}
}
});
};
+29 -9
View File
@@ -4,7 +4,6 @@ type: application/javascript
module-type: startup
Browser message handling
\*/
"use strict";
@@ -18,6 +17,20 @@ exports.synchronous = true;
/*
Load a specified url as an iframe and call the callback when it is loaded. If the url is already loaded then the existing iframe instance is used
*/
// Ensure the callback fires once, whether by PLUGIN-LIBRARY-READY or onload (legacy)
function flushCallbacks(iframeInfo, err) {
if(iframeInfo.status !== "loaded") {
iframeInfo.status = err ? "error" : "loaded";
saveIFrameInfoTiddler(iframeInfo);
var cb;
while((cb = iframeInfo.callbacks.shift())) {
cb(err, iframeInfo);
}
}
}
function loadIFrame(url,callback) {
// Check if iframe already exists
var iframeInfo = $tw.browserMessaging.iframeInfoMap[url];
@@ -30,7 +43,8 @@ function loadIFrame(url,callback) {
iframeInfo = {
url: url,
status: "loading",
domNode: iframe
domNode: iframe,
callbacks: [callback]
};
$tw.browserMessaging.iframeInfoMap[url] = iframeInfo;
saveIFrameInfoTiddler(iframeInfo);
@@ -38,19 +52,18 @@ function loadIFrame(url,callback) {
iframe.style.display = "none";
iframe.setAttribute("library","true");
document.body.appendChild(iframe);
// Set up onload
// Set up onload. Legacy fallback: if PLUGIN-LIBRARY-READY never arrives, onload triggers the flush later
iframe.onload = function() {
iframeInfo.status = "loaded";
saveIFrameInfoTiddler(iframeInfo);
callback(null,iframeInfo);
flushCallbacks(iframeInfo);
};
iframe.onerror = function() {
callback("Cannot load iframe");
flushCallbacks(iframeInfo, "Cannot load iframe");
};
try {
iframe.src = url;
} catch(ex) {
callback(ex);
flushCallbacks(iframeInfo, ex);
}
}
}
@@ -60,7 +73,7 @@ Unload library iframe for given url
*/
function unloadIFrame(url){
var iframes = document.getElementsByTagName("iframe");
for(var t=iframes.length-1; t--; t>=0) {
for(var t = iframes.length - 1; t >= 0; t--) {
var iframe = iframes[t];
if(iframe.getAttribute("library") === "true" &&
iframe.getAttribute("src") === url) {
@@ -147,6 +160,13 @@ exports.startup = function() {
// console.log("browser-messaging: Received message from",event.origin);
// console.log("browser-messaging: Message content",event.data);
switch(event.data.verb) {
case "PLUGIN-LIBRARY-READY":
$tw.utils.each($tw.browserMessaging.iframeInfoMap, function(info) {
if(info && info.domNode && info.domNode.contentWindow === event.source) {
flushCallbacks(info);
}
});
break;
case "GET-RESPONSE":
if(event.data.status.charAt(0) === "2") {
if(event.data.cookies) {
+2 -2
View File
@@ -40,6 +40,8 @@ exports.startup = function() {
// The rest of the startup process here is not strictly to do with loading modules, but are needed before other startup
// modules are executed. It is easier to put them here than to introduce a new startup module
// --------------------------
// Set up the performance framework
$tw.perf = new $tw.Performance($tw.wiki.getTiddlerText(PERFORMANCE_INSTRUMENTATION_CONFIG_TITLE,"no") === "yes");
// Create a root widget for attaching event handlers. By using it as the parentWidget for another widget tree, one can reuse the event handlers
$tw.rootWidget = new widget.widget({
type: "widget",
@@ -48,8 +50,6 @@ exports.startup = function() {
wiki: $tw.wiki,
document: $tw.browser ? document : $tw.fakeDocument
});
// Set up the performance framework
$tw.perf = new $tw.Performance($tw.wiki.getTiddlerText(PERFORMANCE_INSTRUMENTATION_CONFIG_TITLE,"no") === "yes");
// Kick off the filter tracker
$tw.filterTracker = new $tw.FilterTracker($tw.wiki);
$tw.wiki.addEventListener("change",function(changes) {
+1 -1
View File
@@ -221,7 +221,7 @@ function updateLocationHash(options) {
$tw.utils.copyToClipboard(url,{successNotification: options.successNotification, failureNotification: options.failureNotification});
}
// Only change the location hash if we must, thus avoiding unnecessary onhashchange events
if($tw.utils.getLocationHash() !== $tw.locationHash && !$tw.safeMode) {
if($tw.utils.getLocationHash() !== $tw.locationHash) {
if(options.updateHistory === "yes") {
// Assign the location hash so that history is updated
window.location.hash = $tw.locationHash;
+2 -1
View File
@@ -15,7 +15,8 @@ var getCellInfo = function(text, start, length, SEPARATOR) {
var isCellQuoted = text.charAt(start) === QUOTE;
var cellStart = isCellQuoted ? start + 1 : start;
if(text.charAt(i) === SEPARATOR) {
// A quote licenses a separator inside the cell, so only an unquoted cell reads an immediate separator as empty
if(!isCellQuoted && text.charAt(cellStart) === SEPARATOR) {
return [cellStart, cellStart, false];
}
+60 -11
View File
@@ -3,18 +3,43 @@ title: $:/core/modules/utils/deprecated.js
type: application/javascript
module-type: utils
Deprecated util functions
Deprecated util functions. These preserve the pre-5.4.0 signatures and
behaviour for backwards compatibility with plugins and external scripts.
Prefer modern alternatives in new code (Array.prototype methods, classList,
Math.sign, String.prototype.repeat, etc.).
\*/
exports.logTable = (data) => console.table(data);
exports.repeat = (str,count) => str.repeat(count);
/*
Repeats a string
*/
exports.repeat = function(str,count) {
var result = "";
for(var t=0;t<count;t++) {
result += str;
}
return result;
};
exports.startsWith = (str,search) => str.startsWith(search);
/*
Check if a string starts with another string
*/
exports.startsWith = function(str,search) {
return str.substring(0, search.length) === search;
};
exports.endsWith = (str,search) => str.endsWith(search);
/*
Check if a string ends with another string
*/
exports.endsWith = function(str,search) {
return str.substring(str.length - search.length) === search;
};
/*
Trim whitespace from the start and end of a string
*/
exports.trim = function(str) {
if(typeof str === "string") {
return str.trim();
@@ -29,30 +54,54 @@ exports.sign = Math.sign;
exports.strEndsWith = (str,ending,position) => str.endsWith(ending,position);
exports.stringifyNumber = (num) => num.toString();
exports.stringifyNumber = function(num) {
return num + "";
};
// Returns the fully escaped CSS selector for a tag, e.g.
// "$:/tags/Stylesheet" -> "tc-tagged-\%24\%3A\%2Ftags\%2FStylesheet"
exports.tagToCssSelector = function(tagName) {
return "tc-tagged-" + encodeURIComponent(tagName).replace(/[!"#$%&'()*+,\-./:;<=>?@[\\\]^`{\|}~,]/mg,function(c) {
return "\\" + c;
});
};
exports.domContains = (a,b) => a.compareDocumentPosition(b) & 16;
/*
Determines whether element 'a' contains element 'b'.
Returns false when a === b (matches the original John Resig semantics).
*/
exports.domContains = function(a,b) {
return a !== b && a.contains(b);
};
exports.domMatchesSelector = (node,selector) => node.matches(selector);
exports.hasClass = (el,className) => el.classList && el.classList.contains(className);
exports.hasClass = function(el,className) {
return !!(el && el.classList && el.classList.contains(className));
};
// addClass/removeClass/toggleClass split on whitespace to preserve the
// original setAttribute("class", ...) acceptance of "foo bar" as two
// classes. Regressed in #9251.
function splitClasses(className) {
return (typeof className === "string" && className.match(/\S+/g)) || [];
}
exports.addClass = function(el,className) {
el.classList && className && el.classList.add(className);
if(!el.classList) return;
splitClasses(className).forEach(function(c) { el.classList.add(c); });
};
exports.removeClass = function(el,className) {
el.classList && className && el.classList.remove(className);
if(!el.classList) return;
splitClasses(className).forEach(function(c) { el.classList.remove(c); });
};
exports.toggleClass = function(el,className,status) {
el.classList && className && el.classList.toggle(className, status);
if(!el.classList) return;
splitClasses(className).forEach(function(c) { el.classList.toggle(c,status); });
};
exports.getLocationPath = () => window.location.origin + window.location.pathname;
exports.getLocationPath = function() {
return window.location.toString().split("#")[0];
};
+19 -5
View File
@@ -77,10 +77,23 @@ exports.resizeTextAreaToFit = function(domNode,minHeight) {
// Measure the specified minimum height
domNode.style.height = minHeight;
var measuredHeight = domNode.offsetHeight || parseInt(minHeight,10);
// Temporarily force rows=1 during auto-measurement so the intrinsic floor
// is one row rather than the HTML default of two; restore afterwards
var hadRowsAttr = domNode.hasAttribute("rows"),
savedRows = hadRowsAttr ? domNode.getAttribute("rows") : null;
if(!hadRowsAttr) {
domNode.setAttribute("rows","1");
}
// Set its height to auto so that it snaps to the correct height
domNode.style.height = "auto";
// Calculate the revised height
var newHeight = Math.max(domNode.scrollHeight + domNode.offsetHeight - domNode.clientHeight,measuredHeight);
// Restore the original rows attribute state
if(!hadRowsAttr) {
domNode.removeAttribute("rows");
} else {
domNode.setAttribute("rows",savedRows);
}
// Only try to change the height if it has changed
if(newHeight !== domNode.offsetHeight) {
domNode.style.height = newHeight + "px";
@@ -151,15 +164,16 @@ exports.forceLayout = function(element) {
Pulse an element for debugging purposes
*/
exports.pulseElement = function(element) {
var eventName = $tw.utils.convertEventName("animationEnd");
// Event handler to remove the class at the end
element.addEventListener($tw.browser.animationEnd,function handler(event) {
element.removeEventListener($tw.browser.animationEnd,handler,false);
$tw.utils.removeClass(element,"pulse");
element.addEventListener(eventName,function handler(event) {
element.removeEventListener(eventName,handler,false);
$tw.utils.removeClass(element,"tc-pulse");
},false);
// Apply the pulse class
$tw.utils.removeClass(element,"pulse");
$tw.utils.removeClass(element,"tc-pulse");
$tw.utils.forceLayout(element);
$tw.utils.addClass(element,"pulse");
$tw.utils.addClass(element,"tc-pulse");
};
/*
+22 -2
View File
@@ -82,6 +82,11 @@ var TW_Style = function(el) {
// Return a Proxy to handle direct access to individual style properties
return new Proxy(styleObject, {
get: function(target, property) {
// Real CSSStyleDeclaration returns undefined for non-string keys.
// Guards against crashes when consumers probe Symbol.toPrimitive etc.
if(typeof property !== "string") {
return undefined;
}
// If the property exists on styleObject, return it (get, set, setProperty methods)
if(property in target) {
return target[property];
@@ -90,6 +95,10 @@ var TW_Style = function(el) {
return el._style[$tw.utils.convertStyleNameToPropertyName(property)] || "";
},
set: function(target, property, value) {
// Mirror the get trap: ignore non-string keys instead of crashing.
if(typeof property !== "string") {
return true;
}
// Set the property in _style
el._style[$tw.utils.convertStyleNameToPropertyName(property)] = value;
return true;
@@ -106,7 +115,9 @@ var TW_Element = function(tag, namespace) {
this.children = [];
this._style = {}; // Internal style object
this.style = new TW_Style(this); // Proxy for style management
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
// createElementNS with empty-string or null normalises to null (no namespace) per spec.
// https://dom.spec.whatwg.org/#dom-document-createelementns
this.namespaceURI = namespace !== undefined ? (namespace || null) : "http://www.w3.org/1999/xhtml";
};
@@ -197,7 +208,16 @@ TW_Element.prototype.addEventListener = function(type,listener,useCapture) {
Object.defineProperty(TW_Element.prototype, "tagName", {
get: function() {
return this.tag || "";
if(!this.tag) {
return "";
}
// HTML elements report uppercase tagName per DOM spec. Other namespaces
// preserve case. Fakedom only models HTML documents.
// https://dom.spec.whatwg.org/#dom-element-tagname
if(this.namespaceURI === "http://www.w3.org/1999/xhtml") {
return this.tag.toUpperCase();
}
return this.tag;
}
});
+27 -7
View File
@@ -243,8 +243,28 @@ exports.slowInSlowOut = function(t) {
};
exports.copyObjectPropertiesSafe = function(object) {
const seen = new Set(),
isDOMElement = (value) => value instanceof Node || value instanceof Window;
const seen = new Set();
function isDOMElement(value) {
if(!value || typeof value !== "object") {
return false;
}
// Cross-realm DOM nodes
if(typeof value.nodeType === "number" &&
typeof value.nodeName === "string") {
return true;
}
// Cross-realm Window objects
if(value.window === value &&
value.document &&
value.location) {
return true;
}
return false;
}
function safeCopy(obj) {
// skip circular references
@@ -255,10 +275,6 @@ exports.copyObjectPropertiesSafe = function(object) {
if(typeof obj !== "object" || obj === null) {
return obj;
}
// skip DOM elements
if(isDOMElement(obj)) {
return undefined;
}
// copy arrays, preserving positions
if(Array.isArray(obj)) {
return obj.map((item) => {
@@ -266,7 +282,11 @@ exports.copyObjectPropertiesSafe = function(object) {
return value === undefined ? null : value;
});
}
// skip DOM elements
if(isDOMElement(obj)) {
return undefined;
}
seen.add(obj);
const copy = {};
let key,
+2 -2
View File
@@ -61,7 +61,7 @@ LogWidget.prototype.log = function() {
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
if(name.substring(0,2) !== "$$") {
var resultList = self.computeAttribute(attribute,{asList: true});
if(resultList.length <= 1) {
if(resultList && resultList.length <= 1) {
data[name] = resultList[0] || "";
} else {
data[name] = resultList;
@@ -75,7 +75,7 @@ LogWidget.prototype.log = function() {
allVars[v] = variable.value;
} else {
var variableInfo = this.getVariableInfo(v);
allVars[v] = variableInfo.resultList.length > 1 ? variableInfo.resultList : variableInfo.text;
allVars[v] = variableInfo && variableInfo.resultList && variableInfo.resultList.length > 1 ? variableInfo.resultList : variableInfo.text;
}
}
if(this.filter) {
+19 -5
View File
@@ -151,10 +151,24 @@ ButtonWidget.prototype.getBoundingClientRect = function() {
};
ButtonWidget.prototype.isSelected = function() {
return this.setTitle ? (this.setField ? this.wiki.getTiddler(this.setTitle).getFieldString(this.setField) === this.setTo :
(this.setIndex ? this.wiki.extractTiddlerDataItem(this.setTitle,this.setIndex) === this.setTo :
this.wiki.getTiddlerText(this.setTitle))) || this.defaultSetValue || this.getVariable("currentTiddler") :
this.wiki.getTextReference(this.set,this.defaultSetValue,this.getVariable("currentTiddler")) === this.setTo;
var currentValue;
if(this.setTitle) {
if(this.setField) {
// The state tiddler usually does not exist until the button is first clicked
var tiddler = this.wiki.getTiddler(this.setTitle);
currentValue = tiddler ? tiddler.getFieldString(this.setField) : undefined;
} else if(this.setIndex) {
currentValue = this.wiki.extractTiddlerDataItem(this.setTitle,this.setIndex);
} else {
currentValue = this.wiki.getTiddlerText(this.setTitle);
}
if(!currentValue) {
currentValue = this.defaultSetValue || this.getVariable("currentTiddler");
}
} else {
currentValue = this.wiki.getTextReference(this.set,this.defaultSetValue,this.getVariable("currentTiddler"));
}
return currentValue === this.setTo;
};
ButtonWidget.prototype.isPoppedUp = function() {
@@ -267,7 +281,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
ButtonWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tooltip || changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
if(changedAttributes.tooltip || changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.setTitle && changedTiddlers[this.setTitle]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
this.refreshSelf();
return true;
} else {
+1 -1
View File
@@ -22,7 +22,7 @@ Inherit from the base widget class
DiffTextWidget.prototype = new Widget();
DiffTextWidget.prototype.invisibleCharacters = {
"\n": "↩︎\n",
"\n": "\n",
"\r": "⇠",
"\t": "⇥\t"
};
+2 -1
View File
@@ -99,7 +99,8 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
wikiLinkText = this.wiki.filterTiddlers(wikilinkTransformFilter,this,function(iterator) {
iterator(self.wiki.getTiddler(self.to),self.to);
})[0];
} else {
}
if(!wikiLinkText) {
// Expand the tv-wikilink-template variable to construct the href
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$";
+3 -4
View File
@@ -125,13 +125,12 @@ SelectWidget.prototype.setSelectValue = function() {
values = Array.isArray(value) ? value : $tw.utils.parseStringArray(value);
for(var i=0; i < select.children.length; i++){
child=select.children[i];
if(child.children.length === 0){
child.selected = values.indexOf(child.value) !== -1;
} else {
// grouped options
if(child.tagName && child.tagName.toUpperCase() === "OPTGROUP"){
for(var y=0; y < child.children.length; y++){
child.children[y].selected = values.indexOf(child.children[y].value) !== -1;
}
} else {
child.selected = values.indexOf(child.value) !== -1;
}
}
} else {
+2 -2
View File
@@ -189,7 +189,7 @@ Widget.prototype.getVariableInfo = function(name,options) {
}
return {
text: text,
resultList: [text]
resultList: text === undefined ? text : [text]
};
};
@@ -338,7 +338,7 @@ Widget.prototype.makeFakeWidgetWithVariables = function(vars = {}) {
const value = vars[name];
return Array.isArray(value)
? { text: value[0], resultList: value }
: { text: value, resultList: [value] };
: { text: value, resultList: value === undefined ? value : [value] };
}
opts = opts || {};
opts.variables = Object.assign({}, vars, opts.variables || {});
+4 -40
View File
@@ -9,6 +9,7 @@ Bulk tiddler operations such as rename.
"use strict";
var relinkers = $tw.modules.getModulesByTypeAsHashmap("relinker");
/*
Rename a tiddler, and relink any tags or lists that reference it.
*/
@@ -32,50 +33,13 @@ function renameTiddler(fromTitle,toTitle,options) {
Relink any tags or lists that reference a given tiddler
*/
function relinkTiddler(fromTitle,toTitle,options) {
var self = this;
fromTitle = (fromTitle || "").trim();
toTitle = (toTitle || "").trim();
options = options || {};
if(fromTitle && toTitle && fromTitle !== toTitle) {
this.each(function(tiddler,title) {
var type = tiddler.fields.type || "";
// Don't touch plugins or JavaScript modules
if(!tiddler.fields["plugin-type"] && type !== "application/javascript") {
var tags = tiddler.fields.tags ? tiddler.fields.tags.slice(0) : undefined,
list = tiddler.fields.list ? tiddler.fields.list.slice(0) : undefined,
isModified = false,
processList = function(listField) {
if(listField && listField.indexOf(fromTitle) !== -1) {
// Remove any existing instances of the toTitle
var p = listField.indexOf(toTitle);
while(p !== -1) {
listField.splice(p,1);
p = listField.indexOf(toTitle);
}
// Replace the fromTitle with toTitle
$tw.utils.each(listField,function (title,index) {
if(title === fromTitle) {
listField[index] = toTitle;
isModified = true;
}
});
}
};
if(!options.dontRenameInTags) {
// Rename tags
processList(tags);
}
if(!options.dontRenameInLists) {
// Rename lists
processList(list);
}
if(isModified) {
var newTiddler = new $tw.Tiddler(tiddler,{tags: tags, list: list},self.getModificationFields());
newTiddler = $tw.hooks.invokeHook("th-relinking-tiddler",newTiddler,tiddler);
self.addTiddler(newTiddler);
}
}
});
for(var name in relinkers) {
relinkers[name].relink(this,fromTitle,toTitle,options);
}
}
};
+37 -10
View File
@@ -369,16 +369,31 @@ Sort an array of tiddler titles by a specified field
isDescending: true if the sort should be descending
isCaseSensitive: true if the sort should consider upper and lower case letters to be different
*/
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric,locale) {
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric) {
var self = this;
if(sortField === "title") {
if(!isNumeric && !isAlphaNumeric) {
const sorter = new Intl.Collator(locale, { sensitivity: isCaseSensitive ? "variant" : "accent" });
if(isDescending) {
titles.sort((a,b) => sorter.compare(b, a));
if(isCaseSensitive) {
if(isDescending) {
titles.sort(function(a,b) {
return b.localeCompare(a);
});
} else {
titles.sort(function(a,b) {
return a.localeCompare(b);
});
}
} else {
titles.sort((a,b) => sorter.compare(a, b));
}
if(isDescending) {
titles.sort(function(a,b) {
return b.toLowerCase().localeCompare(a.toLowerCase());
});
} else {
titles.sort(function(a,b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
}
}
} else {
titles.sort(function(a,b) {
var x,y;
@@ -399,8 +414,14 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
}
}
}
const sorter = new Intl.Collator(locale, { numeric: isAlphaNumeric, sensitivity: isAlphaNumeric ? "base" : isCaseSensitive ? "variant" : "accent" });
return isDescending ? sorter.compare(b, a) : sorter.compare(a, b);
if(isAlphaNumeric) {
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
}
if(!isCaseSensitive) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
});
}
} else {
@@ -442,8 +463,14 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
}
a = String(a);
b = String(b);
const sorter = new Intl.Collator(locale, { numeric: isAlphaNumeric, sensitivity: isAlphaNumeric ? "base" : isCaseSensitive ? "variant" : "accent" });
return isDescending ? sorter.compare(b, a) : sorter.compare(a, b);
if(isAlphaNumeric) {
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
}
if(!isCaseSensitive) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
});
}
};
+3 -3
View File
@@ -1,6 +1,6 @@
title: $:/core/stylesheets/custom-properties
\rules only transcludeinline macrocallinline html transcludeblock
\rules only transcludeinline macrocallinline html transcludeblock filteredtranscludeinline
/* Tiddlywiki's CSS properties */
@@ -21,10 +21,10 @@ title: $:/core/stylesheets/custom-properties
--tp-story-left: {{$:/themes/tiddlywiki/vanilla/metrics/storyleft}};
--tp-story-top: {{$:/themes/tiddlywiki/vanilla/metrics/storytop}};
--tp-story-right: {{$:/themes/tiddlywiki/vanilla/metrics/storyright}};
--tp-story-width: {{$:/themes/tiddlywiki/vanilla/metrics/storyrwidth}};
--tp-story-width: {{$:/themes/tiddlywiki/vanilla/metrics/storywidth}};
--tp-tiddler-width: {{$:/themes/tiddlywiki/vanilla/metrics/tiddlerwidth}};
--tp-sidebar-breakpoint: {{$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint}};
--tp-sidebar-width: {{$:/themes/tiddlywiki/vanilla/metrics/sidebarwidth}};
--tp-animation-duration: {{{ [{$:/config/AnimationDuration}addsuffix[ms]] }}};
}
}
+3
View File
@@ -0,0 +1,3 @@
title: $:/core/templates/plain-text
<$text text=<<text>>/>
+3
View File
@@ -0,0 +1,3 @@
title: $:/core/templates/rendered-text
<<text>>
+5 -3
View File
@@ -4,13 +4,15 @@ description: create a new journal tiddler
\whitespace trim
\function get-tags() [<textFieldTags>] [<tagsFieldTags>] +[join[ ]]
<$let journalTitleTemplate={{$:/config/NewJournal/Title}} textFieldTags={{$:/config/NewJournal/Tags}} tagsFieldTags={{$:/config/NewJournal/Tags!!tags}} journalText={{$:/config/NewJournal/Text}}>
<$wikify name="journalTitle" text="<$transclude $variable='now' format=<<journalTitleTemplate>>/>">
<$let journalTitle=<<now format={{$:/config/NewJournal/Title}}>>
textFieldTags={{$:/config/NewJournal/Tags}}
tagsFieldTags={{$:/config/NewJournal/Tags!!tags}}
journalText={{$:/config/NewJournal/Text}}
>
<$reveal type="nomatch" state=<<journalTitle>> text="">
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=<<get-tags>> text={{{ [<journalTitle>get[]] }}}/>
</$reveal>
<$reveal type="match" state=<<journalTitle>> text="">
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=<<get-tags>> text=<<journalText>>/>
</$reveal>
</$wikify>
</$let>
@@ -1,5 +1,7 @@
title: $:/core/ui/EditTemplate/body/toolbar/button
\whitespace trim
\define toolbar-button-icon()
<$list
+3 -3
View File
@@ -108,10 +108,10 @@ tags: $:/tags/EditTemplate
storeTitle=<<newFieldNameInputTiddler>>
searchListState=<<newFieldNameSelectionTiddler>>
>
<div class="tc-edit-field-add-name-wrapper">
<div class=`tc-edit-field-add-name-wrapper ${ [<newFieldNameTiddler>get[text]] :intersection[<storyTiddler>fields[]] :then[[tc-edit-field-exists]] }$`>
<$transclude $variable="keyboard-driven-input"
cancelPopups="yes"
class=`tc-edit-texteditor tc-popup-handle ${ [<newFieldNameTiddler>get[text]] :intersection[<storyTiddler>fields[]] :then[[tc-edit-field-exists]] }$`
class="tc-edit-texteditor tc-popup-handle"
configTiddlerFilter="[[$:/config/EditMode/fieldname-filter]]"
default=""
focus={{{ [{!!draft.of}is[tiddler]then{$:/config/AutoFocusEdit}match[fields]then[true]] :else[{$:/config/AutoFocus}match[fields]then[true]] :else[[false]] }}}
@@ -178,4 +178,4 @@ tags: $:/tags/EditTemplate
</$let>
</$let>
</div>
</$let>
</$let>
+18 -21
View File
@@ -6,28 +6,25 @@ tags: $:/tags/EditTemplate
\procedure lingo-base() $:/language/EditTemplate/
\procedure tag-body-inner(colour,fallbackTarget,colourA,colourB,icon,tagField:"tags")
<$wikify name="foregroundColor"
text="""<$macrocall $name="contrastcolour"
target=<<colour>>
fallbackTarget=<<fallbackTarget>>
colourA=<<colourA>>
colourB=<<colourB>>/>
"""
>
<$let backgroundColor=<<colour>> >
<span class="tc-tag-label tc-tag-list-item tc-small-gap-right"
data-tag-title=<<currentTiddler>>
style=`color:$(foregroundColor)$; background-color:$(backgroundColor)$; --tp-remove-tag-button-color:$(foregroundColor)$`
<$let foregroundColor=<<contrastcolour target=<<colour>> fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>> >>
backgroundColor=<<colour>>
>
<span class="tc-tag-label tc-tag-list-item tc-small-gap-right"
data-tag-title=<<currentTiddler>>
style=`color:$(foregroundColor)$; fill:$(foregroundColor)$; background-color:$(backgroundColor)$;`
>
<$transclude tiddler=<<icon>>/>
<$view field="title" format="text"/>
<$button class="tc-btn-invisible tc-remove-tag-button"
style.fill=<<foregroundColor>>
>
<$transclude tiddler=<<icon>>/>
<$view field="title" format="text"/>
<$button class="tc-btn-invisible tc-remove-tag-button">
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter="-[{!!title}]"/>
{{$:/core/images/close-button}}
</$button>
</span>
</$let>
</$wikify>
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter="-[{!!title}]"/>
<!-- Touch a temp tiddler so that the tag remove animation fires instantly. Otherwise it's delayed by the typing timeout duration -->
<$action-setfield $tiddler="$:/temp/tags-edit-refresh" text=<<currentTiddler>>/>
{{$:/core/images/close-button}}
</$button>
</span>
</$let>
\end
\procedure tag-body(colour,palette,icon,tagField:"tags")
-5
View File
@@ -1,5 +0,0 @@
title: $:/Manager/ItemMain/Editor
tags: $:/tags/Manager/ItemMain
caption: {{$:/language/Manager/Item/Editor}}
<$edit-text tag="textarea" class="tc-edit-texteditor tc-edit-texteditor-body tc-max-width"/>
-5
View File
@@ -13,8 +13,3 @@ caption: {{$:/language/Manager/Item/Tools}}
{{$:/core/images/edit-button}}&#32;edit
</$button>
</p>
<p>
<$button message="tm-delete-tiddler" param=<<currentTiddler>>>
{{$:/core/images/delete-button}}&#32;delete
</$button>
</p>
-37
View File
@@ -1,37 +0,0 @@
title: $:/core/ui/SafeLayout
tags: $:/tags/Layout
name: Safe Mode Layout
description: Safe Mode Layout
icon: $:/core/images/list
\whitespace trim
\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
\define tv-config-toolbar-class() tc-btn-invisible
\define tv-config-toolbar-icons() yes
\define tv-config-toolbar-text() no
<div style="margin: 1em;">
<$navigator story="$:/StoryList" history="$:/HistoryList">
<h2>Layout</h2>
{{$:/snippets/LayoutSwitcher}}
<h2>Controls</h2>
<div class="tc-page-controls">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/PageControls]!has[draft.of]]">
<$transclude mode="inline"/>
</$list>
</div>
<h2>Tiddlers</h2>
<$transclude tiddler="$:/Manager" mode="block"/>
</$navigator>
</div>
+2 -4
View File
@@ -16,15 +16,13 @@ title: $:/core/ui/TagPickerTagTemplate
<$set name="backgroundColor"
value={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}
>
<$wikify name="foregroundColor"
text="""<$macrocall $name="contrastcolour" target=<<backgroundColor>> fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>>/>"""
>
<$let foregroundColor=<<contrastcolour target=<<backgroundColor>> fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>> >> >
<span class="tc-tag-label tc-btn-invisible"
style=<<tag-pill-styles>>
data-tag-title=<<currentTiddler>>
>
{{||$:/core/ui/TiddlerIcon}}<$view field="title" format="text"/>
</span>
</$wikify>
</$let>
</$set>
</$button>
+1 -1
View File
@@ -2,7 +2,7 @@ title: $:/core/ui/ViewTemplate/title
tags: $:/tags/ViewTemplate
\whitespace trim
\define title-styles() color:$(foregroundColor)$;
\define title-styles() fill:$(foregroundColor)$;
<div class="tc-tiddler-title tc-clearfix">
<div class="tc-titlebar">
+4 -3
View File
@@ -6,7 +6,6 @@ description: {{$:/language/Buttons/NewJournalHere/Hint}}
\whitespace trim
\procedure journalButton()
<$button tooltip={{$:/language/Buttons/NewJournalHere/Hint}} aria-label={{$:/language/Buttons/NewJournalHere/Caption}} class=<<tv-config-toolbar-class>>>
<$wikify name="journalTitle" text="""<$transclude $variable="now" format=<<journalTitleTemplate>>/>""">
<$action-sendmessage $message="tm-new-tiddler" title=<<journalTitle>> tags=`[[$(currentTiddlerTag)$]] $(journalTags)$`/>
<%if [<tv-config-toolbar-icons>match[yes]] %>
{{$:/core/images/new-journal-button}}
@@ -16,9 +15,11 @@ description: {{$:/language/Buttons/NewJournalHere/Hint}}
<$text text={{$:/language/Buttons/NewJournalHere/Caption}}/>
</span>
<%endif%>
</$wikify>
</$button>
\end
<$let journalTitleTemplate={{$:/config/NewJournal/Title}} journalTags={{$:/config/NewJournal/Tags}} currentTiddlerTag=<<currentTiddler>>>
<$let journalTitle=<<now format={{$:/config/NewJournal/Title}}>>
journalTags={{$:/config/NewJournal/Tags}}
currentTiddlerTag=<<currentTiddler>>
>
<<journalButton>>
</$let>
+5 -1
View File
@@ -17,6 +17,10 @@ This page summarises high level information about the configuration of this ~Tid
Drag this link to copy this tool to another wiki
\end intrinsic-lingo-Drag/Caption
\procedure intrinsic-lingo-Generate/Caption()
Click to generate wiki information report
\end intrinsic-lingo-Generate/Caption
\procedure lingo(title,mode:"inline")
<%if [<title>addprefix<lingo-base>is[shadow]] %>
<$transclude $tiddler={{{ [<title>addprefix<lingo-base>] }}} $mode=<<mode>>/>
@@ -105,7 +109,7 @@ Drag this link to copy this tool to another wiki
<$button>
<<display-wiki-info-modal>>
Click to generate wiki information report
<<lingo title:"Generate/Caption">>
</$button>
<$link to="$:/core/ui/ControlPanel/WikiInformation">
+1 -2
View File
@@ -1,4 +1,3 @@
title: $:/state/popup/manager/item/$:/Manager/
ItemMain/RawText: hide
ItemMain/Editor: hide
ItemMain/RawText: hide
+1 -1
View File
@@ -1,6 +1,6 @@
title: $:/config/OfficialPluginLibrary
tags: $:/tags/PluginLibrary
url: https://tiddlywiki.com/library/v5.4.0/index.html
url: https://tiddlywiki.com/library/v5.5.0/index.html
caption: {{$:/language/OfficialPluginLibrary}}
{{$:/language/OfficialPluginLibrary/Hint}}
+1
View File
@@ -3,6 +3,7 @@ tags: $:/tags/Macro
\define tag-pill-styles()
background-color:$(backgroundColor)$;
fill:$(foregroundColor)$;
color:$(foregroundColor)$;
\end
+1 -1
View File
@@ -21,7 +21,7 @@ tags: $:/tags/Macro
style="width:$width$px;height:$height$px;background-color:$background-color$;"
></$reveal></div><div
class="tc-thumbnail-icon"
style="color:$color$;"
style="fill:$color$;color:$color$;"
>$icon$</div><div class="tc-thumbnail-caption">$caption$</div></div></$link>
\end
@@ -8,9 +8,8 @@ type: text/vnd.tiddlywiki
# Ensure the new release banner image is up to date
# Update ''master'' with changes from ''tiddlywiki-com''
# Verify the version numbers in [[$:/config/OfficialPluginLibrary]] in `core/wiki/config/OfficialPluginLibrary.tid`
# Move the latest release note from the prerelease edition into the tw5.com edition
# Adjust the release date and the ''released'' field of the latest release tiddler (eg, [[Release 5.1.3]])
# Also adjust the github.com comparison link to point to the tag for the new release
# Adjust the release date and the ''released'' field of the release tiddler (eg, [[Release 5.1.3]])
# Update the ''release-introduction'' definition with the new release text, and if necessary the ''description'' field of the release tiddler
# Adjust the tiddler [[TiddlyWiki Archive]] to include the new version number
# Ensure [[TiddlyWiki Releases]] has the new version as the default tab
# Adjust the modified time of HelloThere
@@ -19,10 +18,10 @@ type: text/vnd.tiddlywiki
!! Update Readmes and release note
# Edit `package.json` to the new version number
# Run `npm install` to update the `package-lock.json` file
# Run `./bin/readme-bld.sh` to build the readme files
# Commit the new readme files to ''master''
# Restore `package.json` to the previous version number
# Adjust the link for "GitHub for detailed change history of this release" in the release note
# Add the credits for the new release banner to the release note, including a link to the GitHub instance of the image from the commit history
!! Make New Release
@@ -6,4 +6,4 @@ title: Data Management during Runtime
During the runtime the data of Tiddlywiki is stored in javascript objects. These objects are synchronized with the DOM-Representation of Tiddlywiki. This means every change of the original data of a Tiddler, fires an event which changes all DOM-Representations of the Tiddler and the javascript object. The bare-bones Wiki store is created during the boot process and is kept in a object called \$tw.Wiki. This object contains amongst others a hashmap of the different Tiddlers of Tiddlywiki. The Hashmap is used to store the javascript object representation of the different Tiddlers. Furthermore this object is used to manage the tiddlers during runtime, it provides methods for adding tiddlers, search tiddlers by name and delete tiddlers.
As shown in the picture below, every change at the DOM triggers an event which changes the corresponding widget which again changes the store of the tiddlers. The whole image shows how WikiText is parsed by a set of rules into the parse tree and this parse tree is rendered as a tree of widgets. This Rendertree is synchronised to the DOM. Every modification on the Rendertree provokes a start of the rendering-pipeline. As well as every change on the wikiText triggers an event at the RenderTree. This Process uses a selective updating so that only the changed parts are updated. This means only widgets which have to change the DOM in consequence of a changed tiddler are refreshed.
{{TiddlyWikiArchitecture.svg}}
{{TiddlyWiki Architecture.svg}}
@@ -1,6 +0,0 @@
title: $:/editions/dev/github-fork-ribbon
tags: $:/tags/PageTemplate
caption: ~GitHub ribbon
description: ~GitHub ribbon for tw5.com/dev
<div class="github-fork-ribbon-wrapper right" style><div class="github-fork-ribbon" style="background-color:#DF4848;"><a href="https://github.com/TiddlyWiki/TiddlyWiki5" target="_blank" rel="noopener noreferrer">Find me on ~GitHub</a></div></div>
-1
View File
@@ -2,7 +2,6 @@
"description": "Developer documentation from https://tiddlywiki.com/dev/",
"plugins": [
"tiddlywiki/highlight",
"tiddlywiki/nodewebkitsaver",
"tiddlywiki/github-fork-ribbon",
"tiddlywiki/menubar",
"tiddlywiki/internals",
-1
View File
@@ -1,7 +1,6 @@
{
"description": "A step by step introduction to TiddlyWiki",
"plugins": [
"tiddlywiki/cecily",
"tiddlywiki/codemirror",
"tiddlywiki/highlight",
"tiddlywiki/katex"
@@ -0,0 +1,15 @@
created: 20251021142729667
modified: 20260327113434425
original-modified: 20251021142729667
tags:
title: Concatenating a text reference to create a URL
ja-title: テキスト参照を連結してURL作成
type: text/vnd.tiddlywiki
!! 変数とテキスト参照を連結してURLを作成する
<$macrocall $name=wikitext-example src="""<$let hash={{{ [<currentTiddler>encodeuricomponent[]] }}}>
<a href=`${ [{!!base-url}] }$#$(hash)$`>これはtiddlywiki.comのTiddlerです</a>
</$let>"""/>
参照: [[置換属性値|Substituted Attribute Values]]
@@ -0,0 +1,15 @@
created: 20251021142733998
modified: 20260327113417322
original-modified: 20251021142733998
tags:
title: Concatenating variables to create a URL
ja-title: 変数を連結してURL作成
type: text/vnd.tiddlywiki
!! 文字列と変数を連結してURLを作成する
<$macrocall $name=wikitext-example src="""<$let hash={{{ [<currentTiddler>encodeuricomponent[]] }}}>
<a href=`http://tiddlywiki.com/#$(hash)$`>これはtiddlywiki.comのTiddlerです</a>
</$let>"""/>
参照: [[置換属性値|Substituted Attribute Values]]
@@ -0,0 +1,91 @@
code-body: yes
created: 20150117184156000
modified: 20260217110459190
original-modified: 20240716181836632
tags: $:/tags/Macro
title: $:/editions/tw5.com/wikitext-macros
ja-title: $:/editions/tw5.com/wikitext-macros
type: text/vnd.tiddlywiki
\whitespace trim
\procedure activatePluginTab()
<$action-setfield $tiddler="$:/state/tab-1749438307" text="$:/core/ui/ControlPanel/Plugins"/>
<$action-navigate $to="$:/ControlPanel"/>
\end
\procedure activateTiddlerWindow()
<$action-sendmessage $message="tm-open-window" $param=<<currentTiddler>> windowTitle="Side by Side View" width="800" height="600" />
\end
\procedure controlPanel-plugin-link()
<$button actions=<<activatePluginTab>> class="tc-btn-invisible tc-tiddlylink">
{{$:/core/images/options-button}} ~ControlPanel
</$button>
\end
\procedure open-tiddler-in-window()
\whitespace notrim
<$button actions=<<activateTiddlerWindow>> class="tc-btn-invisible tc-tiddlylink">
''この''Tiddlerを新しいウィンドウで開く
</$button>
\end
\procedure activateEditionWindow(url)
<$action-sendmessage $message="tm-open-external-window" $param=<<url>> windowName="_edition" windowFeatures="width=800 height=600" />
\end
\procedure open-external-window(url)
\whitespace notrim
<$button actions=<<activateEditionWindow <<url>> class="tc-btn-invisible tc-tiddlylink">
''サンプル''を新しいウィンドウで開く
</$button>
\end
\procedure wikitext-example(src)
<div class="doc-example">
<$macrocall $name="copy-to-clipboard-above-right" src=<<src>>/>
<$codeblock code=<<src>>/>
<p>
次のように表示されます:
</p>
<$transclude $variable="src" $mode="block"/>
<p>
... そして、土台となるHTMLは次のようになります:
</p>
<$wikify name="html" text=<<src>> output="html">
<$codeblock code=<<html>>/>
</$wikify>
</div>
\end
\procedure wikitext-example-without-html(src)
<div class="doc-example">
<$macrocall $name="copy-to-clipboard-above-right" src=<<src>>/>
<$codeblock code=<<src>>/>
<p>
次のように表示されます:
</p>
<$transclude $variable="src" $mode="block"/>
</div>
\end
\procedure wikitext-example-table-header() <thead><tr><th/><th>wiki text</th><th>renders as</th></tr></thead>
\procedure wikitext-example-table-row(id, code)
<tr>
<th><<id>></th>
<td><$codeblock code=<<code>>/></td>
<td><$transclude $variable="code" $mode="block"/></td>
</tr>
\end
\procedure tw-code(tiddler)
<$codeblock language={{{ [<tiddler>get[type]] }}} code={{{ [<tiddler>get[text]] }}}/>
\end
\procedure tw-code-link(tiddler)
<$link to=<<tiddler>>/>:
<$transclude $variable=tw-code tiddler=<<tiddler>> />
\end
@@ -11,6 +11,7 @@ ja-title: TiddlyWikiアーカイブ
5.1.20 5.1.21 5.1.22 5.1.23
5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7
5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8
5.4.0
\end
TiddlyWikiの古いバージョンは[[アーカイブ|https://github.com/TiddlyWiki/tiddlywiki.com-gh-pages/tree/master/archive]]で入手できます:
@@ -0,0 +1,17 @@
title: Donations
ja-title: 寄付
tags: About HelloThere
modified: 20260406043554401
original-modified: 20260403103452943
created: 20260403103452943
<a href="https://opencollective.com/tiddlywiki" class="tc-btn-invisible" target="_blank">
{{TiddlyWiki Donation Graphic}}
</a>
TiddlyWikiは無料のオープンソースプロジェクトであり、ホスティング費用を賄い、プロジェクトの継続的な成長を支えるために、皆様からの寛大なご寄付に頼っています。
こちらから寄付できます:
https://opencollective.com/tiddlywiki
TiddlyWikiの資金調達に関する詳細情報や、プロジェクトを支援する方法については、[[TiddlyWikiへの資金提供|Funding TiddlyWiki]]をご覧ください。
+9 -15
View File
@@ -1,5 +1,5 @@
created: 20140721121924384
modified: 20241002115027813
modified: 20260406052319609
original-modified: 20240925113748341
tags: Community
title: Forums
@@ -7,19 +7,17 @@ ja-title: フォーラム
caption: フォーラム
type: text/vnd.tiddlywiki
!!! ユーザー
! ユーザーフォーラム
TiddlyWiki公式フォーラムは、~TiddlyWikiについて話し合う場です。ヘルプのリクエスト、新しいリリースやプラグインの[[アナウンス|https://talk.tiddlywiki.org/c/announcements/20]]、新機能の議論、または単にエクスペリエンスを共有するなどできます。関連するWebサイトから参加することも、電子メールで購読することもできます。
!! Talk ~TiddlyWiki
公式~TiddlyWikiフォーラムとして、Talk ~TiddlyWikiは、~TiddlyWikiについて話し合う場です: ヘルプのリクエスト、新しいリリースやプラグインの[[アナウンス|https://talk.tiddlywiki.org/c/announcements/20]]、新機能の議論、または単にエクスペリエンスを共有するなどできます。関連するWebサイトから参加することも、電子メールで購読することもできます。
https://talk.tiddlywiki.org/
その他のフォーラム:
!! Googleグループ
!!! Googleグループ
<<<
既存ユーザーの便宜を図るため、オリジナルの~TiddlyWikiグループ(2005年からGoogleグループでホストされている)も引き続き運営しています。: https://groups.google.com/group/TiddlyWiki
<<<
既存ユーザーの便宜を図るため、オリジナルの~TiddlyWikiグループ(2005年からGoogleグループでホストされている)も引き続き運営しています: https://groups.google.com/group/TiddlyWiki
! 開発者フォーラム
@@ -27,9 +25,5 @@ https://talk.tiddlywiki.org/
! その他のフォーラム
* [[TiddlyWikiサブレディット|https://www.reddit.com/r/TiddlyWiki5/]]
* https://discord.gg/HFFZVQ8 でDiscordでチャット
!! 開発者
{{Developers}}
* TiddlyWikiサブレディット: [[/r/TiddlyWiki5|https://www.reddit.com/r/TiddlyWiki5/]]
* https://discord.gg/HFFZVQ8 でDiscordでチャット
@@ -0,0 +1,20 @@
created: 20140107114355828
modified: 20260406000640400
original-modified: 20150220160920000
tags: Concepts
title: TemplateTiddlers
ja-title: テンプレートTiddler
type: text/vnd.tiddlywiki
テンプレートTiddlerは、実際にはTiddlerの一種ではなく、Tiddlerが使用される役割の一つです。
テンプレートは、[[Wikiテキスト|WikiText]]の断片を再利用する方法です。
テンプレートを介したトランスクルージョンは、2つのTiddlerを組み合わせることで、[[トランスクルージョン|Transclusion]]の基本機能を拡張します:
* 表示する[[Wikiテキスト|WikiText]]を含むテンプレートTiddler。[[現在のTiddler|Current Tiddler]]内のフィールドを参照するトランスクルージョンを含めることができます。
* フィールドへの参照を解決する際に、現在のTiddlerとして扱われるターゲットTiddler
テンプレートの最も優れた例は、TiddlyWikiのメインストーリーリバーです。ストーリーリバー内の各Tiddlerは、各フィールドのレンダリング方法を指定するViewTemplateを介してレンダリングされます。
詳細については、[[テンプレートを使用したトランスクルージョン|Transclusion with Templates]]を参照してください。
@@ -0,0 +1,36 @@
created: 20130827075900000
modified: 20260406013639263
original-modified: 20230321130421587
tags: Concepts
title: TextReference
ja-title: テキスト参照
type: text/vnd.tiddlywiki
[[テキスト参照|TextReference]]は、テキストの断片をTiddlerのフィールドや[[データTiddler|DataTiddlers]]内のインデックスとして記述するための汎用的な方法です。
状況に応じて、テキスト参照を使用して値を取得したり、変更すべき値を指定したりすることができます。
[[テキスト参照|TextReference]]はいくつかのパーツから構成されます:
* 対象Tiddlerのタイトル。省略した場合、デフォルトで[[現在のTiddler|Current Tiddler]]が使用されます
* 以下のいずれか:
** フィールド名(`!!`でマークされます)
** [[データTiddler|DataTiddlers]]内のインデックス名(`##`でマークされます)
* フィールドとインデックスの両方が省略された場合、textフィールドがデフォルトとして使用されます
テキスト参照のほとんどのパーツは省略可能です:
* `tiddlerTitle` - 指定したTiddlerのtitle[[フィールド|TiddlerFields]]
* `tiddlerTitle!!field` - [[Tiddlerのフィールド|TiddlerFields]] (例: `modified`、`modifier`、`type` など)
* `!!field` - 現在のTiddlerの[[フィールド|TiddlerFields]]
* `tiddlerTitle##propertyIndex` - DataTiddlersから名前付きプロパティを抽出
テキスト参照は、以下の場所で使用できます:
* [[フィルタ|Filters]]内の[[間接パラメータ|Filter Parameter]]として (例: `<$list filter="[tag{MyTag!!name}]"/>`)
* 要素やウィジェットの[[間接属性|HTML in WikiText]]として (例: `<$widget attrib={{Title!!description}}/>`)
* トランスクルージョンショートカットのパラメータとして (例: `{{MyTiddler!!title}}`)
* [[Revealウィジェット|RevealWidget]]と[[LinkCatcherウィジェット|LinkCatcherWidget]]の`state`属性として
<$macrocall $name=".tip" _="""`foo!!bar`のようなテキスト参照と`{{foo!!bar}}`のようなテキスト参照のトランスクルージョンの違いに注意してください"""/>
@@ -0,0 +1,31 @@
created: 20141129194651420
modified: 20260406001216888
original-modified: 20240621074019077
tags: Concepts Definitions
title: Transclusion
ja-title: トランスクルージョン
! 定義
<<< Wikipedia: [[トランスクルージョン|https://ja.wikipedia.org/wiki/%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B9%E3%82%AF%E3%83%AB%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3]]
コンピュータ科学において、トランスクルージョンとは、ハイパーテキストを介した参照によって、電子文書の一部または全部を他の1つまたは複数の文書に組み込むことを指します。
<<<
~TiddlyWikiでは、''トランスクルージョン''とは、あるTiddler "A"を別のTiddler "B"から参照するプロセスであり、"A"の内容が"B"の一部であるかのように見せかけるものです。
コンテンツをコピー&ペーストすると、同じコンテンツが複数の場所に複製されてしまいます。一方、トランスクルージョンでは、単一のコピーと、Tiddler "A"からコンテンツを挿入する位置を示す特別な指示が"B"に記述されるだけで済みます。
"A"の内容が変更されると、"B"にも自動的に変更内容が反映されることに注意してください。これにより、コンテンツを1か所に記述し、複数の場所から閲覧できるため、繰り返し使用するコンテンツの管理が容易になります。
トランスクルージョンの概念は、小さなコンテンツを組み合わせる主要な方法であるため、[[Tiddlerの哲学|Philosophy of Tiddlers]]において重要な役割を果たしています。
詳細はこちらをご覧ください:
* [[Wikiテキストでのトランスクルージョン|Transclusion in WikiText]]
* [[トランスクルージョンの基本的な使用法|Transclusion Basic Usage]]
* [[テンプレートを使用したトランスクルージョン|Transclusion with Templates]]
* [[トランスクルージョンと置換|Transclusion and Substitution]]
* [[テキスト参照|TextReference]]
* [[テンプレートTiddler|TemplateTiddlers]]
* [[Transcludeウィジェット|TranscludeWidget]]
* [[ハードトランスクルージョンとソフトトランスクルージョン|Hard and Soft Transclusions]]
@@ -0,0 +1,17 @@
created: 20131205155227468
modified: 20260216114242627
original-modified: 20230303214711802
tags: Concepts Reference
title: WikiText
ja-title: Wikiテキスト
type: text/vnd.tiddlywiki
WikiTextは、広範囲のテキストフォーマット、ハイパーテキスト、インタラクティブ機能を入力するための簡潔で表現力豊かな方法です。複雑なユーザーインターフェイスに邪魔されることなく、執筆に集中できます。[[マークダウン|Markdown]]のユーザーにとって使いやすいように設計されていますが、リンクとインタラクティブ機能に重点が置かれています
[[エディターツールバー|Editor toolbar]]ボタンを使用して、Wikiテキストをテキストフィールドに挿入することもできます
Wikiテキストの概要については、[[Wikiテキストのフォーマット|Formatting in WikiText]]と[[TiddlyWikiのテキストフォーマット|Formatting text in TiddlyWiki]]を参照してください
次の要素のWikiテキスト構文がコアに組み込まれています:
<<list-links filter:"[tag[WikiText]]" class:"multi-columns">>
@@ -0,0 +1,9 @@
created: 20150221180826000
modified: 20260406063958939
original-modified: 20150221181700000
tags: Definitions
title: Base64
ja-title: Base64
type: text/vnd.tiddlywiki
<<.dlink-ex Base64 "https://en.wikipedia.org/wiki/Base64">>は、画像などのバイナリデータをテキスト文字列として表現する方法です
@@ -0,0 +1,9 @@
created: 20150221120651000
modified: 20260406064757649
original-modified: 20150221181705000
tags: Definitions
title: Cascading Style Sheets
ja-title: カスケーディングスタイルシート(CSS)
type: text/vnd.tiddlywiki
<<.dlink-ex CSS "https://en.wikipedia.org/wiki/Cascading_Style_Sheets">>は、Webページ上のさまざまな要素の表示スタイルを定義するために使用される標準プレーンテキスト形式です
@@ -0,0 +1,12 @@
color: #7bb95d
created: 20130825145100000
modified: 20260406064409034
original-modified: 20250104111522881
title: Definitions
ja-title: 定義
tags: Reference
type: text/vnd.tiddlywiki
これらは、このドキュメントで使用される技術的なワードやフレーズの定義です(TiddlyWiki自体を構成する[[コンセプト|Concepts]]とは異なります)
<<list-links "[tag[Definitions]]" class:"multi-columns">>
@@ -0,0 +1,13 @@
created: 20230410105035569
modified: 20260406065237731
original-modified: 20230410105035569
tags: Definitions
title: Tiddlyhost
ja-title: Tiddlyhost
type: text/vnd.tiddlywiki
<span style="float:right;">[img width=140 [Tiddlyhost Logo]]</span>
[[Tiddlyhost.com|https://tiddlyhost.com/]]は、Simon Bairdによって作成されたTiddlyWikiのホスティングサービスです。サインアップして電子メールを確認すると、オンライン保存をサポートする"サイト"(つまり、~TiddlyWiki)を作成できます。サイトはプライベートやパブリックにすることができ、オプションでタグ付け可能で検索可能な[[Tiddlyhostハブ|https://tiddlyhost.com/hub]]にサイトをリストし、他のユーザーが見付けられるようにすることもできます。
[[TiddlySpot|Saving on TiddlySpot]]とは異なり、[[Tiddlyhost|https://tiddlyhost.com]]は安全でオープンソースであり、TiddlyWiki5を適切にサポートしています。また、既存の~TiddlyWikiファイルをアップロードしたり、TiddlyWikiClassicをサポートしたり、~TiddlySpotサイトの所有権を主張したりすることもできます。詳細については、[[FAQ|https://github.com/simonbaird/tiddlyhost/wiki/FAQ]]と[[About|https://tiddlyhost.com/about]]ページをご覧ください。
@@ -21,3 +21,5 @@ type: text/vnd.tiddlywiki
<<.tip """上に示したように、図に開始線と終了線が1つある場合は、リンクされた上位レベルにさらに情報があることを意味します。パンくずリストはナビゲーションに使用できます""">>
<<.tip """下位レベルで使用されているように、図に開始点と終了点がない場合は、読みやすさと単純さを高めるために、上位レベルのシンタックス要素が削除されていることを意味します。パンくずリストはナビゲーションに使用できます""">>
<<.note """フィルタ式の再帰深度は最大300です。この制限を超えて自身を再帰的に呼び出すフィルタ(例えば、<<.olink subfilter>>や<<.olink filter>>演算子を使ったもの)は、エラーメッセージ`/**-- Excessive filter recursion --**/`を返します。これは無限ループを防ぐためです。""">>
@@ -14,6 +14,8 @@ type: text/vnd.tiddlywiki
"{" [: <-"間接"-> /"}以外"/] "}"
|
"<" [: <-"変数"-> /">以外"/] ">"
|
"(" [: <-"複数値変数"-> /")以外"/ ] ")" /"v5.4.0"/
)
"""/>
@@ -22,6 +24,7 @@ type: text/vnd.tiddlywiki
;<<.def ハード>>
: `[パラメータ例]`
: パラメータは、角括弧内のテキストそのものです。
;<<.def ソフト>>
: <<.def 間接>>
:: `{パラメータ例}`
@@ -30,6 +33,9 @@ type: text/vnd.tiddlywiki
:: `<パラメータ例>`
:: パラメータは、山括弧内の[[変数|Variables]]の現在値です。マクロパラメータは、v5.2.0まではサポートされて<<.em いません>>。
::<<.from-version "5.2.0">> リテラルマクロパラメータがサポートされています。例: `[<now [UTC]YYYY0MM0DD0hh0mm0ssXXX>]`。
: <<.def "複数値変数">>
:: `(パラメータ例)`
:: <<.from-version "5.4.0">> このパラメータは、丸括弧で囲まれた名前の[[複数値変数|Multi-Valued Variables]]に格納されている値のリスト全体に展開されます。このようにアクセスすると、フィルタ演算子は最初の値だけでなく、すべての値を受け取ります。詳細については、[[複数値変数|Multi-Valued Variables]]を参照してください。
<<.note """すべての[[フィルタオペレータ|filter Operator]]の後にはパラメータ式が続く必要があります。[[パラメータの無いオペレータ|Operators without parameters]]の場合、その式は空になります(`[<currentTiddler>links[]]`のフィルタオペレータ<<.olink links>>と同様)。""">>
@@ -37,4 +43,8 @@ type: text/vnd.tiddlywiki
<<.from-version "5.1.23">> [[フィルタステップ|Filter Step]]では、`,`文字で区切られた複数のパラメータがサポートされます。
例えば: `[param1],[param2]`や`<param1>,{param2}`
例えば: `[param1],[param2]`や`<param1>,{param2}`、 `[param1],(param2)`
---
<<.warning """`/regexp/(flags)`オペランド構文は非推奨であり、ブラウザのコンソールに警告が表示されます。代わりに<<.olink regexp>>演算子を使用してください。""">>
@@ -6,7 +6,6 @@ title: Filter Run Prefix
ja-title: フィルタランプレフィックス
type: text/vnd.tiddlywiki
There are 2 types of filter run prefixes that are interchangeable; [[named prefixes|Named Filter Run Prefix]] and [[shortcut prefixes|Shortcut Filter Run Prefix]].
交換可能なフィルタランプレフィックスには、[[名前付きプレフィックス|Named Filter Run Prefix]]と[[ショートカットプレフィックス|Shortcut Filter Run Prefix]]の2種類があります。
<$railroad text="""

Some files were not shown because too many files have changed in this diff Show More