Compare commits

..
Author SHA1 Message Date
Keiran Harcombe b40b68fa1d Made some changes 2026-04-05 18:18:20 +01: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 32a3a3e478 [DOCS] Clean up Forums tiddler (#9780) 2026-04-04 08:49:55 +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 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
Mario PietschandGitHub 65fcded29f Fix name clashes - definition tiddlers with images (#9759) 2026-03-20 07:54:03 +00:00
HimmelandGitHub ec27a4bf20 Add new contributor Himmel to CLA (#9755) 2026-03-19 07:12:33 +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
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
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 a3acbaa2f1 Update road map 2026-02-20 09:30:25 +00:00
IchijikuIchigoandGitHub 8cd6bbc075 [ja_JP] Japanese translation update - 'Community' section of tiddlywiki.com (#9662)
* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 381388f, 4dc89f6, 5fa1098

* [ja_JP] Japanese translation update from commit: 3c1d658

* [ja_JP] Japanese translation update from commit: 3c1d658

* [ja_JP] Japanese translation update from commit: 29a567f, 6aee5eb

* [ja_JP] Japanese translation update from commit: 0ac2b6c

* [ja_JP] Japanese translation update from commit: 1994574

* [ja_JP] Japanese translation update from commit: 5dfdbc8

* [ja_JP] Japanese translation update from commit: 1994574

* [ja_JP] Japanese translation update from commit: 81d8d67

* [ja_JP] Japanese translation update from commit: 81d8d67

* [ja_JP] Japanese translation update from commit: 4196d96

* [ja_JP] Japanese translation update from commit: 1994574

* [ja_JP] Japanese translation update from commit: 1994574

* [ja-JP] Japanese translation of 'community\project\TiddlyWiki Project.tid'

* [ja-JP] Japanese translation of 'community\docs\Community Cards Caveats.tid'

* [ja-JP] Japanese translation of 'community\project\TiddlyWiki People.tid'

* [ja-JP] Japanese translation of 'community\project\Vacant Positions.tid'

* [ja-JP] Japanese translation of 'community\docs\Community Cards.tid'

* [ja-JP] Japanese translation of 'community\docs\Displaying Community Cards.tid'

* [ja-JP] Japanese translation of 'community\docs\Submitting a Community Card.tid'

* [ja-JP] Japanese translation of 'community\tools\cards\Procedures.tid'

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

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

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Community Links Aggregator.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\TiddlyWiki Newsletter.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\marketplace\TiddlyWiki Marketplace.tid'

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

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Improving TiddlyWiki Documentation.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Translate TiddlyWiki into your language.tid'

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

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

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\Tidme by oflg.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\_Cardo-A Task and Project Management Wiki_ by David_Szego.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\Drift by Tony K.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\Stroll by David Gifford.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\plugins\GSD5.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\plugins\TiddlyWiki for Scholars.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\_TiddlyStudy_ by Kebi.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\resources\Wikilabs by PMario.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\resources\Projectify by Nicolas Petton.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\plugins\TW5-Graph by Flibbles.tid'

* [ja-JP] Japanese translation has been modified to display the ja-title.

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_A free, open source wiki revisited_ by Mark Gibbs, NetworkWorld.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_Notizen mit TiddlyWiki systemubergreifend nutzen_ by Michael Sonntag.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_Setting Up a Personal TiddlyWiki Server on OS X_ by Kris Johnson.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_TiddlyWiki 5 im Betatest_ by besim.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_TiddlyWiki_ by Sander de Boer.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\resources\TiddlyWiki Posts.tid'

* [ja-JP] A little correction to the Japanese translation
2026-02-15 11:56:40 +01:00
Mario PietschandGitHub 6fc65c1560 [DOCS] Slightly Improve "How to create keyboard shortcuts" Readability (#9478) 2026-02-05 17:01:40 +01:00
Mario PietschandGitHub ab29f17d35 [DOCS] Add Repo-link to "Installing official plugins on Node.js" (#9483)
* [DOCS] Add Repo-link to "Installing official plugins on Node.js"

* Update Installing official plugins on Node.js.tid
2026-02-04 21:26:48 +01:00
IchijikuIchigoandGitHub 5ae4770317 [ja_JP] Update of Japanese translations (#9581)
* [ja_JP] Japanese translation update from commit: 5ff4e02

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hire-jeremy\Hire Jeremy Sidebar Segment.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hire-jeremy\Hire Jeremy Sidebar Segment.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hire-jeremy\HireJeremy.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hellothere\thumbnails\HelloThumbnail - Community Survey.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hellothere\thumbnails\HelloThumbnail - TW5-Graph.tid'

* [ja_JP] Japanese translation update from commit: e3af967

* [ja_JP] Japanese translation update from commit: bdc0fe1

* [ja_JP] Japanese translation update from commit: e3af967

* [ja_JP] Japanese translation update from commit: bdc0fe1, e3af967

* [ja_JP] Japanese translation update from commit: fdafdba, e3af967, ecba671, 935e89b

* [ja_JP] Japanese translation update from commit: bdc0fe1, e3af967

* [ja_JP] Japanese translation update from commit: 0763ee5

* [ja_JP] Japanese translation update from commit: bdc0fe1

* [ja_JP] Japanese translation update from commit: b0d950f, 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: b0d950f, 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: b0d950f

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

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

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

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

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

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

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

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

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

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

* [ja-JP] Japanese translation of 'editions\ja-JP\tiddlers\commands\ListenCommand.tid'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\ServerCommand.tid'
2026-02-04 21:24:55 +01:00
Mario PietschandGitHub 70b4557738 [DOCS] Add link to "TiddlyWiki Archive" tiddler to the TiddlyWiki Releases info (#9613) 2026-01-25 16:59:54 +01:00
Mario PietschandGitHub efe58e41bc [DOCS] Fix some typos in "days Operator (Examples)" (#9479)
* [DOCS] Fix some typos in "days Operator (Examples)"

* Remove created and modified fields from days.tid

Remove created and modified fields from days.tid
2026-01-21 09:09:14 +01:00
Mario PietschandGitHub 79e3d14698 [DOCS] Make TaskManagementExamples more "hackable" (#9482)
* [DOCS] Make TaskManagementExamples more "hackable"

* Update modified date in TaskManagementExample.tid

* Fix modified date in TaskManagementExampleDraggable
2026-01-20 13:23:17 +01:00
superuser-doesandGitHub 763d717a13 Improvements to DateFormat tiddler (#9583) 2026-01-20 13:18:24 +01:00
419fe68ee2 [Docs] Improve tag-pill documentation and examples (#9580)
* [Docs] Improve tag-pill documentation and examples

* Apply suggestion from @saqimtiaz

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
2026-01-14 14:04:34 +01:00
yaisogandGitHub 47ab3476f6 Improve LogWidget and ActionLogWidget documentation (#9550) 2026-01-05 14:31:11 +01:00
Mario PietschandGitHub f0e64660f2 [DOCS] Add multi-columns class to Widgets in Wikitext (#9516) 2026-01-04 21:45:19 +00:00
Mario PietschandGitHub 7cb422242a DOCS - Fix typo in Date Fields (#9518) 2026-01-04 21:36:57 +00:00
superuser-doesandGitHub 5fa1098c03 tw5.com: remove duplicate text from Forums tiddler (#9523) 2026-01-04 18:15:37 +00:00
superuser-doesandGitHub 92dc927c7b docs: savetiddlers extension is now Firefox-only (#9524)
* tw5.com: removed Chrome browser from savetiddlers

Was deprecated in early 2025, and is now Firefox-only

Additional changes:
* Lowercased buggyj in line with how the name is used elsewhere on tw5.com and the rest of the internet
* Pulled url from the url field (following the example of Timimi resource tiddler)
* Changed formatting of title to match other community resources

* tw5.com: update French & Japanese savetiddlers plugin docs to note it is now Firefox-only

Please note this update was validated using machine translation
2026-01-04 18:12:56 +00:00
superuser-doesandGitHub f3fa69e229 Docs: rename 'definition lists' to 'description lists' (#9535)
* docs: Definition Lists to definition lists

* tw5.com: rename Definition Lists to Description Lists throught tiddler

* apply recommendations by @pmario on #9535
2026-01-04 17:37:54 +00:00
7fb8560908 Signing CLA (#9534)
Co-authored-by: Jeremy Ruston <jeremy@jermolene.com>
2026-01-04 13:30:54 +00:00
Jeremy Ruston ff7814360e Cleanup whitespace in CLA 2026-01-04 13:19:24 +00:00
hsteve11andGitHub 2d9303c6ff Signing CLA (#9539) 2026-01-04 13:18:46 +00:00
Mario PietschandGitHub 6aee5eb0c7 Add Filter Syntax History link to Filters tiddler (#9541) 2026-01-04 13:16:54 +00:00
XLBillyandGitHub 4196d96adc [DOCS] Update docs about saving via WebDAV (#9543) 2026-01-02 09:42:58 +01:00
wiki-tutorandGitHub 838fad916d Signing CLA (#9527) 2025-12-28 18:30:51 +00:00
Jeremy Ruston 935e89bd93 Tweak HelloThere thumbnail ordering 2025-12-20 09:25:25 +00:00
Jeremy Ruston ecba671bcf Update Newsletter links and editorial 2025-12-19 09:12:06 +00:00
IchijikuIchigoandGitHub 4b824795c8 [ja_JP] Update of Japanese translations (#9499)
* [ja_JP] Japanese translation update from commit: c625e3c, ac83b46, 314ce12

* [ja_JP] Japanese translation update from commit: b0d950f, 381388f, 4dc89f6, 6a39a4e

* [ja_JP] Japanese translation update from commit: 29a567f, 3597e65, 3378497

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: b0d950f, 381388f

* [ja_JP] Japanese translation update from commit: 614ba84

* [ja_JP] Japanese translation update from commit: 23a23d9

* [ja_JP] Japanese translation update from commit: 8993572

* [ja_JP] Japanese translation update from commit: 8993572, 697171a, 75e89a1, ee55ab6, a73e03c, ac83b46

* [ja_JP] Japanese translation update from commit: 8993572

* [ja_JP] Japanese translation update from commit: 8993572

* [ja_JP] Japanese translation update from commit: 81862b5

* [ja_JP] Japanese translation update from commit: 81d8d67

* [ja_JP] Japanese translation update from commit: 899a498

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

* [ja_JP] Japanese translation update from commit: d63a189

* [ja_JP] Japanese translation update from commit: 789d64f

* [ja_JP] Japanese translation update from commit: 5490b78

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

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

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

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

* [ja_JP] Japanese translation update from commit: 29a567f
2025-12-18 16:13:07 +00:00
Christian ByronandGitHub fc74219c0b Add CeebeeTree comunity card (#9501) 2025-12-17 14:28:23 +00:00
Jeremy Ruston ffde2da16c Add @CeeBeeTree to the comunity card for the Newsletter team 2025-12-16 09:20:51 +00:00
4bb0bc5527 Signing CLA (#9307)
Co-authored-by: Jeremy Ruston <jeremy@jermolene.com>
2025-11-23 18:32:43 +00:00
Jeremy Ruston 3378497816 Add link to launch archive 2025-11-22 17:48:28 +00:00
Jeremy Ruston d81204c6ab Add Community Card for QA team
@Leilei332 I hope you don't mind, but I've nominated you to be the lead of the QA team. If you're happy to take the role, please could you submit a community card?
2025-11-12 13:03:14 +00:00
lin onetwoandGitHub e001c21bf5 Adds commuinity card for LinOnetwo (#9426)
(cherry picked from commit 98ecbf7441)
2025-11-12 12:26:27 +01:00
Mario PietschandGitHub 102c236267 Create PMario community card (#9417) 2025-11-11 16:43:59 +00:00
Saq ImtiazandGitHub 06a2923adf Adds edit.tiddlywiki.com to infrastructure team responsibilities (#9419) 2025-11-11 16:37:45 +00:00
Jeremy Ruston 54e5ef7489 Fix link 2025-11-11 11:41:27 +00:00
Jeremy Ruston 6f306d1ed6 Community Team Card for the Developer Experience Team
@pmario this is a starter list of, please do suggest improvements
2025-11-10 10:21:58 +00:00
Mario PietschandGitHub 5dfdbc8ea0 [DOCS] Slightly improve the substitution documentation (#9357) 2025-11-07 19:27:20 +00:00
4d4d9d9995 [DOCS] Add docs about deprecated classes (#9345)
* Add docs about deprecated classes

* Add Core classes tag

* Deprecate `tc-language-*` class

* Update deprecation warning

* 更新 Deprecated Core Classes.tid

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

* Apply suggestion from @saqimtiaz

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
2025-11-04 13:03:38 +01:00
494 changed files with 6656 additions and 3515 deletions
+3 -3
View File
@@ -10,7 +10,7 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
@@ -30,7 +30,7 @@ jobs:
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
TW5_BUILD_OUTPUT: "./output/prerelease"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
@@ -62,7 +62,7 @@ jobs:
TW5_BUILD_OUTPUT: "./output"
TW5_BUILD_ARCHIVE: "./output"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "${{ env.NODE_VERSION }}"
-40
View File
@@ -1,40 +0,0 @@
name: ESLint
on:
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
concurrency:
group: lint-${{ github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
# Needed for GitHub Checks API
checks: write
jobs:
eslint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm install --include=dev
- name: Run ESLint with reviewdog (GitHub Checks)
uses: reviewdog/action-eslint@v1
with:
eslint_flags: '.'
reporter: github-pr-check
fail_level: error
level: error
tool_name: ESLint PR code
+23 -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.3.8
fi
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
@@ -73,8 +73,10 @@ rm $TW5_BUILD_OUTPUT/dev/static/*
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
@@ -299,6 +301,26 @@ node $TW5_BUILD_TIDDLYWIKI \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/tahoelafs \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/d3demo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
node $TW5_BUILD_TIDDLYWIKI \
+18 -51
View File
@@ -641,7 +641,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
// Call the function and return the exports
return fn.apply(null,contextValues);
};
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
/*
Run code in a sandbox with only the specified context variables in scope
*/
@@ -799,13 +799,12 @@ the password, and to encrypt/decrypt a block of text
$tw.utils.Crypto = function() {
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
currentPassword = null,
callSjcl = function(method,inputText,password,options) {
options = options || {};
callSjcl = function(method,inputText,password) {
password = password || currentPassword;
var outputText;
try {
if(password) {
outputText = sjcl[method](password,inputText,options);
outputText = sjcl[method](password,inputText);
}
} catch(ex) {
console.log("Crypto error:" + ex);
@@ -831,8 +830,7 @@ $tw.utils.Crypto = function() {
return !!currentPassword;
}
this.encrypt = function(text,password) {
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
return callSjcl("encrypt",text,password);
};
this.decrypt = function(text,password) {
return callSjcl("decrypt",text,password);
@@ -1435,7 +1433,7 @@ $tw.Wiki = function(options) {
checkTiddler = function(tiddler,title) {
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
if(title === "$:/core" || title === "$:/core-server" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
if(title === "$:/core" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
pluginTiddlers.push(tiddler);
registeredTitles.push(tiddler.fields.title);
@@ -1532,8 +1530,7 @@ Define all modules stored in ordinary tiddlers
*/
$tw.Wiki.prototype.defineTiddlerModules = function() {
this.each(function(tiddler,title) {
// Modules in draft tiddlers are disabled
if(tiddler.hasField("module-type") && (!tiddler.hasField("draft.of"))) {
if(tiddler.hasField("module-type")) {
switch(tiddler.fields.type) {
case "application/javascript":
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
@@ -1560,11 +1557,6 @@ $tw.Wiki.prototype.defineShadowModules = function() {
this.eachShadow(function(tiddler,title) {
// Don't define the module if it is overidden by an ordinary tiddler
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
if(tiddler.hasField("draft.of")) {
// Report a fundamental problem
console.warn(`TiddlyWiki: Plugins should not contain tiddlers with a 'draft.of' field: ${tiddler.fields.title}`);
return;
}
// Define the module
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
}
@@ -1913,7 +1905,7 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
fileSize = fs.statSync(filepath).size,
data;
if(fileSize > $tw.config.maxEditFileSize) {
data = "File " + filepath + " not loaded because it is too large";
data = "File " + filepath + "not loaded because it is too large";
console.log("Warning: " + data);
ext = ".txt";
} else {
@@ -1984,41 +1976,22 @@ filepath: pathname of the directory containing the specification file
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
var tiddlers = [];
// Read the specification
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"), function(e) {
console.log("Warning: tiddlywiki.files in " + filepath + " invalid: " + e.message);
return {};
});
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
// Helper to process a file
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
type = (extInfo || {}).type || fields.type || "text/plain",
typeInfo = $tw.config.contentTypeInfo[type] || {},
pathname = path.resolve(filepath,filename),
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
metadata = $tw.loadMetadataForFile(pathname) || {},
fileTooLarge = false,
text, fileTiddlers;
if("_canonical_uri" in fields) {
text = "";
} else if(fs.statSync(pathname).size > $tw.config.maxEditFileSize) {
var msg = "File " + pathname + " not loaded because it is too large";
console.log("Warning: " + msg);
fileTooLarge = true;
text = isTiddlerFile ? msg : "";
} else {
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8");
}
fileTiddlers;
if(isTiddlerFile) {
fileTiddlers = $tw.wiki.deserializeTiddlers(fileTooLarge ? ".txt" : path.extname(pathname),text,metadata) || [];
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
} else {
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
}
var combinedFields = $tw.utils.extend({},fields,metadata);
if(fileTooLarge && isTiddlerFile) {
delete combinedFields.type; // type altered
}
$tw.utils.each(fileTiddlers,function(tiddler) {
$tw.utils.each(combinedFields,function(fieldInfo,name) {
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
@@ -2093,7 +2066,6 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
} else if(tidInfo.suffix) {
tidInfo.fields.text = {suffix: tidInfo.suffix};
}
tidInfo.fields = tidInfo.fields || {};
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
});
// Process any listed directories
@@ -2115,7 +2087,6 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
var thisPath = path.relative(filepath, files[t]),
filename = path.basename(thisPath);
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
dirSpec.fields = dirSpec.fields || {};
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
}
}
@@ -2379,7 +2350,6 @@ $tw.loadTiddlersNode = function() {
});
// Load the core tiddlers
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.coreServerPath));
// Load any extra plugins
$tw.utils.each($tw.boot.extraPlugins,function(name) {
if(name.charAt(0) === "+") { // Relative path to plugin
@@ -2453,7 +2423,6 @@ $tw.boot.initStartup = function(options) {
// System paths and filenames
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
$tw.boot.coreServerPath = path.resolve($tw.boot.bootPath,"../core-server");
// If there's no arguments then default to `--help`
if($tw.boot.argv.length === 0) {
$tw.boot.argv = ["--help"];
@@ -2578,10 +2547,10 @@ $tw.boot.execStartup = function(options){
if($tw.safeMode) {
$tw.wiki.processSafeMode();
}
// Register typed modules from the tiddlers we've just loaded and any modules within plugins
// Tiddlers should appear last so that they may overwrite shadows during module registration
$tw.wiki.defineShadowModules();
// Register typed modules from the tiddlers we've just loaded
$tw.wiki.defineTiddlerModules();
// And any modules within plugins
$tw.wiki.defineShadowModules();
// Make sure the crypto state tiddler is up to date
if($tw.crypto) {
$tw.crypto.updateCryptoStateTiddler();
@@ -2650,13 +2619,11 @@ $tw.boot.executeNextStartupTask = function(callback) {
$tw.boot.log(s.join(" "));
// Execute task
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
const thenable = task.startup();
if(thenable && typeof thenable.then === "function"){
thenable.then(asyncTaskCallback);
return true;
} else {
return asyncTaskCallback();
task.startup();
if(task.name) {
$tw.boot.executedStartupModules[task.name] = true;
}
return $tw.boot.executeNextStartupTask(callback);
} else {
task.startup(asyncTaskCallback);
return true;
+14
View File
@@ -0,0 +1,14 @@
title: @Christian_Byron
tags: Community/Person
fullname: Christian Byron
talk.tiddlywiki.org: Christian_Byron
github: ceebeetree
linkedin: www.linkedin.com/in/christian-byron-b84a594/
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEBAAMBAAAAAAAAAAAAAAAHBgEDBQQBAAMBAAAAAAAAAAAAAAAAAAABAwX/2gAMAwEAAhADEAAAADv2xtJlY03sqePW3ARS1RSydIhcH//EACcQAAICAgIBAgYDAAAAAAAAAAECAwQFEQASMRMhBhBBk8HRIzJx/9oACAEBAAE/AMFQxs+NExqJLMCwYE+SOT4bF3qr+hAIpRsDQ6lWH0Yco4S/eVniRVQHXZzrZ5dwGQpQtNII2RfJVvHMRl5cbKxC94n/ALp+RxfiKpNcgMMUqPIwjcnWip/I5XtUowaL3Ujir/xt79Glb6/4OZ7MV5oEpUzuIa7MPB14A5jpoYLsEsydo1bbLre+CWEEEYab7Uf74ZYSSThpvtR/vmRmhnuzywp1jZtquta+VPM49qlcy24lf017At7g8uZnHrUsGK3Ez+m3UBvcnXy//8QAHhEAAgEFAAMAAAAAAAAAAAAAAQIDAAQRIkEyUaH/2gAIAQIBAT8AmiuVlZkLEeQOflJPcvMAF0z65V+h0YIW52rBDuxUrztf/8QAIxEBAAEDAwMFAAAAAAAAAAAAAgEAAxEEBSMSQcEiMVJxof/aAAgBAwEBPwC/Z1ZvNBOYz1Gc/lDUat3ySPRM/H2P3W4hcbIldpxnxW3BcjQk9oznzX//2Q==
Hello ~TiddlyWikiers - I have been a long time fan, recent contributor to the TW community.
Recently I have volunteered to run the [[TiddlyWiki Newsletter|https://tiddlywiki.substack.com/]] to spread the great news about TW.
I have been in the IT industry for about thirty years, mostly as a consultant and technical arcitect.
More recently I went back to study a masters in IT focussing on AI and data science.
Now my partner and I have started our own business ([[Sphere Innovations|https://sphere-innovations.com.au]]) - in consulting and building web applications for small to medium size businesses here in Australia.
+19
View File
@@ -0,0 +1,19 @@
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEAAwEBAAAAAAAAAAAAAAAGAwQHAgUBAAMBAAAAAAAAAAAAAAAAAAACAwT/2gAMAwEAAhADEAAAAOfCWAMdKKetM4wOvY5OcvZnrYf/xAApEAACAQQBBAECBwAAAAAAAAABAgMABAURQQYSIVETFCIxMkJicYKh/9oACAEBAAE/AEtysaStr7mPaPeuazWdMM4gEnfPryW8hBUuZvou2RXRxyreBWPmgyNqs8f8MOQalhdY7Vz+R4/s/qfP+1edNi/zl7HDcFbmS3E8CcMR4INP0PkBhklIm+sZNtFtQiV0nj57Owl+dSrSTFgD6/CtH4VV9lU3oAbPngAVY389lc5URuUZkMxhnR4pvW0VwDqsP1FNmLWYqCpikMbngmliJNY+aKzyTxXS6lRAyg/u5rq+5x2RsuyTa3MQMlvKniRGThTUd1JYXUdzAwDvqVxGdRXMbfrVOD7HBrG3mNEsU8z98TRhl9eRzX//xAAcEQACAgIDAAAAAAAAAAAAAAABAgARAzESIVH/2gAIAQIBAT8ARuXZPsul3Eoje5lBQWBP/8QAGREAAwEBAQAAAAAAAAAAAAAAAAECEiER/9oACAEDAQE/AM98Lk7LJe20z//Z
created: 20251110102157310
first-sighting: 2019-03-01
fullname: Lin Onetwo
github: linonetwo
homepage: https://wiki.onetwo.website/
modified: 20251111184556193
tags: Community/Person Community/Team/Contributors
talk.tiddlywiki.org: linonetwo
title: @linonetwo
type: text/vnd.tiddlywiki
Since 2014, when I started college, I've been on a quest for a lifelong PKM tool. I cherish my life and all my experiences, and I dont want to forget any of them. When Im deeply focused on a task, its easy to lose sight of other important parts of my life—so I needed a system to help me stay balanced.
Early on, I tried TiddlyWiki several times, but I was initially put off by its save mechanism and markup editing. That changed when I discovered an auto-backup script, which gave me the confidence to fully commit. Over time, I improved the script and eventually transitioned to using TidGi-Desktop and TidGi-Mobile.
Today, my TiddlyWiki holds all my game design ideas and progress logs—it has truly become my second brain. With the help of LLM-powered programming tools, Ive enhanced it with numerous plugins, allowing me to manage my mind in a more programmable and structured way. As a game developer, TiddlyWiki isn't the core of my professional work; But I've invested so much time because it's fundamentally about upgrading my mind.
Most of my notes are open by default and shared publicly on my homepage as a digital garden.
+25
View File
@@ -0,0 +1,25 @@
avatar: UklGRiwIAABXRUJQVlA4WAoAAAAwAAAAPwAAPwAASUNDUCACAAAAAAIgbGNtcwRAAABtbnRyR1JBWVhZWiAH6QALAAoACwADAAZhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkZXNjAAAAzAAAAG5jcHJ0AAABPAAAADZ3dHB0AAABdAAAABRrVFJDAAABiAAAACBkbW5kAAABqAAAACRkbWRkAAABzAAAAFJtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFIAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA81EAAQAAAAEWzHBhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbbWx1YwAAAAAAAAABAAAADGVuVVMAAAAIAAAAHABHAEkATQBQbWx1YwAAAAAAAAABAAAADGVuVVMAAAA2AAAAHABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAVlA4TOYFAAAvP8APEDWGgbRtWv+yt/0WImICOBvWn1C4dFi1bStbvpY8Qg2ePANNNAMh3N2db/7A91/7CHBvBBRr25ZFH+4k98ihkqi2CP4tsANvX8a+8y8Ct04dn0nuUt39ZiBJkowqt911M+MJ1G3bNiZJr1iP0DZ+2bbdadsqprOjAqmoUIX9hf3Fl5/uPYV7I3OMeoFzIvrvwG0kRUr3zPLdYMMXaqrMMsp0K4fufKO6c2hFV5Zh7kRROZX0PSCmB/3KWQwpuiekWelSRZDW94d0q750NrxavpFn1eLNQ9EV8nWlmAET6Q8lrCRTcjFLlLImluK3iXJW/hT47KGklS8OlzWUtXLFYDRCSS74ojUjxggqKMoxd6A1lTCyvsvyzC5/d7BsCHb7yIcHyrX2yR/NPnsAdRT2i0Pwp/o0Il6ix8hsRAuJmQgcr4KREfAiMgUVm9KqmfSxL5pOJspVwwTiV6jiIAg1RMhHpERhbvwgGI34Hc49T7UeKZtXwEqJ+BAaoBneperJH0POs1u4dufwv8Gf+qcOfjyvX6ZIVgxE0Rw87YF3BSc9c7jsXfdjOBG7FwmSb39pfGRwu8IuvUjJNoTpFzkEvDg6W3Qt/9nf99ZXPy8HM43IweTKyNR+WVatXcWWyakBksj9cqW+QetplcjsKElvZH/zuOO/PrCx//tL3/6x/O/C1PZZvSKuulLcS4l8M1ewGPR6ef5sllXW2eGQZ7hVSEZiPmcqrSS8e2ElX8o7t1fvB9LFetmEx5hx1Xuye2PpfjZnSjj7QfKTB3bZZo05Zvh6YuivX24cpc8+ddvADWG9odrSwFalVurxUiidDHmTiaoNkkh2gjbcpxMiAbd39aVP119/N9k4+euNKfcNjwaPhZEuUupUsJrHchw1LkPrRC9bQKa3M8Mj/xx903drdnHMpbirj1ENsUre0oo3N+7gat+2ZctKdsIUYc21sRu+Ucdhn+P7DyarftW00iu3Tmbv+hTfdCTmyaIPT4PrYZDFtBN2W8S9m4oTB5Z2P3Oe7weKjVBq86kXX/r0+WuvTAzfjqm1hsYRPWlbxm4n3IaeGOJEizv8orH9w5ejjmSrfOuEq/HxT6eDemtsZ/HTvvG1/8iVspxZILrlkz/cdsIbIroOgJileFSty2xiHNW5t9fbHJ3ze87bp5T9vc8RuqMB0ReDSt464R/BJxspvgpEsrVAJMTsYg2QovPTOHrvQ9et/S2Xx+40z7dY4JBX0Pz/ElH/T73U2DkK8EiqC9hM/zV3frQfzjaAqO16s1l6xCUXnBFlYxyIer3eEdth7u5xsHKxWoGLqzY3wIULt9G3K6soei9jZ+UcF+Ka3M/II9EUWrJ/LLxy+Q9xIh0vOl3NZCrVnBsuFUTOSnJnSioRWZ9q4g+ZDk5XVORoW2qX2hbIkna3JOrdR3jmpHVLovUkLES6grRO010u0GkDlX7SpH1DQ64Wl2zaSUJv1Mtti2G7kx5IyftWMhfDlGClcxvIUhP5crhp9LIb1Vne187oSAWxelcR/kXjYQTZboW+Oj1pqF0gmfZhSDD6bSgzGWrw3s7QLNtCV+2uatYrd/aFtjDI8R52e/DdyKgRKXBhEak3Ev50+GCUA9EFUor39htVMxmWvW8AM6ptG416rZvdWn+MarIEyH5r6ruZSrx8XrWDP370vbfTjqpmZGIbiFPFoihc4jcrlYi9p3ndSuymZ+XLaKza/P/HUWHn5Axdkd9OjBskY0+pIlz4AlFPFs+aStK5PBIRR4MVVJDihsy4JdEA4pVcrVqMZDyL2/8aYocikEAR9Xjc1BNG9zEiJG7n/cGyrtnblkClBhEgMW4Kx21BEBGJjLa0hcOGmTK64KsKLfKr9QyQELclxY3hqowTIZKdZNTSS5BWiBPlKxDWBVSS41bOepkhTkhGDajLfLyUBOKlkMHPgOhx3JoRN/cEiRgSWdgF2yCyDQu4IcbNo8ftTzxveOJ5y+h509h52+h549h569h587/M20f/b1AB
created: 20251110102157310
first-sighting: 2009-11-14
fullname: Mario Pietsch
github: pmario
homepage: https://wikilabs.github.io/
modified: 20251110124935183
tags: Community/Person Community/Team/Contributors
talk.tiddlywiki.org: pmario
title: @pmario
type: text/vnd.tiddlywiki
youtube: https://www.youtube.com/@pmario
''Hi, My name is Mario Pietsch''. Back in 2009 I was ''searching'' for ''a simple presentation tool'' and discovered ~TiddlyWiki Classic, Monkey Pirate ~TiddlyWiki ([[MPTW|https://mptw.tiddlyspot.com/]]) with ~TagglyTagging, Eric Shulman's ~TiddlyTools, Saq Imtiaz's navigation macros, and more. --- ''I was captivated''.
After a deep dive, I combined these elements into my own "Presentation Manager", along [[3 step by step tutorials|https://groups.google.com/g/tiddlywiki/c/qG_tZ1x0MEU/m/-vLA0luMicYJ]] to help others build it.
Thanks to ''the positive spirit'' of the ~TiddlyWiki community, I am proud to be part of it since 2009.
When Jeremy started developing ~TiddlyWiki 5 on ~GitHub, I joined in—opening [[issue no. 1|https://github.com/TiddlyWiki/TiddlyWiki5/issues/1]] all the way up to 13. For what thats good ;) Since then, I have submitted nearly 600 pull requests and more than 500 issues, many of which have been merged or resolved.
My ~TiddlyWiki 5 "laboratory" is at https://wikilabs.github.io, and I also share content on my ''~YouTube'' channel: https://www.youtube.com/@pmario
Have fun!<br>
Mario
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
title: Developer Experience Team
tags: Community/Team
modified: 20251109200632671
created: 20251109200632671
leader: @pmario
team: @saqimtiaz
The Developer Experience Team improves the experience of software contributors to the TiddlyWiki project. This includes enhancing documentation, streamlining contribution processes, and providing tools and resources to help developers effectively contribute to TiddlyWiki.
Tools and resources managed by the Developer Experience Team include:
* Advising and assisting contributors, particularly new developers
* Maintenance of developer-focused documentation on the https://tiddlywiki.com/dev/ site, including:
** Development environment setup guides
** Code review processes and best practices
** Contribution guidelines and documentation
* Continuous integration and deployment scripts providing feedback on pull requests
* Devising and implementing labelling systems for issues and pull requests
* Automation scripts to simplify common development tasks
@@ -1,8 +1,9 @@
title: Infrastructure Team
tags: Community/Team
modified: 20250909171928024
created: 20250909171928024
modified: 20251110133437795
tags: Community/Team
leader: @kjharcombe
team: @MotovunJack
title: Infrastructure Team
The Infrastructure Team is responsible for maintaining and improving the infrastructure that supports the TiddlyWiki project. This includes the hosting, deployment, and management of the TiddlyWiki websites and services, as well as the tools and systems used by the TiddlyWiki community.
@@ -12,3 +13,4 @@ The infrastructure includes:
* github.com/TiddlyWiki
* tiddlywiki.com DNS
* Netlify account for PR previews
* edit.tiddlywiki.com
@@ -1,6 +0,0 @@
title: Newsletter Team
tags: Community/Team
modified: 20250909171928024
created: 20250909171928024
The Newsletter Team is responsible for producing the TiddlyWiki Newsletter, a monthly email newsletter that highlights news, updates, and community contributions related to TiddlyWiki.
@@ -0,0 +1,11 @@
title: Quality Assurance Team
created: 20251112125742296
modified: 20251112125742296
tags: Community/Team
team:
leader: @Leilei332
title: Quality Assurance Team
The Quality Assurance Team is responsible for ensuring the quality and reliability of TiddlyWiki releases. This includes reviewing code submissions, testing new features, identifying bugs, and verifying that fixes are effective.
@@ -0,0 +1,15 @@
title: TiddlyWiki Newsletter Team
tags: Community/Team
modified: 20251219090709874
created: 20250909171928024
leader: @Christian_Byron
The Newsletter Team is responsible for producing the [[TiddlyWiki Newsletter]]. We would love to have your help if you would like to get involved.
! Audience
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
Subscribing to the newsletter is intended to give people confidence that they will not miss any important developments.
+1 -1
View File
@@ -1,5 +1,5 @@
title: Community/Team
modified: 20250909171928024
created: 20250909171928024
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Infrastructure Team]] [[Succession Team]]
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
-11
View File
@@ -1,11 +0,0 @@
{
"title": "$:/core-server",
"name": "Core Server Components",
"description": "TiddlyWiki5 core server components",
"author": "JeremyRuston",
"core-version": ">=5.0.0",
"platform": "server",
"plugin-priority": "0",
"list": "readme",
"stability": "STABILITY_2_STABLE"
}
-7
View File
@@ -1,7 +0,0 @@
title: $:/core-server/readme
This plugin contains TiddlyWiki's core components that are only needed on the server, comprising:
* Commands
* HTTP server code
* Utility functions for server
-73
View File
@@ -1,73 +0,0 @@
/*\
title: $:/core/modules/server/routes/get-file.js
type: application/javascript
module-type: route
GET /files/:filepath
\*/
"use strict";
exports.methods = ["GET"];
exports.path = /^\/files\/(.+)$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var path = require("path"),
fs = require("fs"),
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
baseFilename = path.resolve(state.boot.wikiPath,"files"),
filename = path.resolve(baseFilename,suppliedFilename),
extension = path.extname(filename);
// Check that the filename is inside the wiki files folder
if(path.relative(baseFilename,filename).indexOf("..") === 0) {
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
}
fs.stat(filename, function(err, stats) {
if(err) {
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
} else {
var type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream"),
responseHeaders = {
"Content-Type": type,
"Accept-Ranges": "bytes"
};
var rangeHeader = request.headers.range,
stream;
if(rangeHeader) {
// Handle range requests
var parts = rangeHeader.replace(/bytes=/, "").split("-"),
start = parseInt(parts[0], 10),
end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
// Validate start and end
if(isNaN(start) || isNaN(end) || start < 0 || end < start || end >= stats.size) {
responseHeaders["Content-Range"] = "bytes */" + stats.size;
return response.writeHead(416, responseHeaders).end();
}
var chunksize = (end - start) + 1;
responseHeaders["Content-Range"] = "bytes " + start + "-" + end + "/" + stats.size;
responseHeaders["Content-Length"] = chunksize;
response.writeHead(206, responseHeaders);
stream = fs.createReadStream(filename, {start: start, end: end});
} else {
responseHeaders["Content-Length"] = stats.size;
response.writeHead(200, responseHeaders);
stream = fs.createReadStream(filename);
}
// Common stream error handling
stream.on("error", function(err) {
if(!response.headersSent) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.end("Read error");
} else {
response.destroy();
}
});
stream.pipe(response);
}
});
};
+1 -1
View File
@@ -147,7 +147,7 @@ Settings/AutoSave/Disabled/Description: Do not save changes automatically
Settings/AutoSave/Enabled/Description: Save changes automatically
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
Settings/CamelCase/Caption: Camel Case Wiki Links
Settings/CamelCase/Hint: Requires reload to take effect
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
Settings/Caption: Settings
Settings/EditorToolbar/Caption: Editor Toolbar
@@ -99,18 +99,16 @@ Commander.prototype.executeNextCommand = function() {
}
}
if(command.info.synchronous) {
// Synchronous command (await thenables)
// Synchronous command
c = new command.Command(params,this);
err = c.execute();
if(err && typeof err.then === "function") {
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
} else if(err) {
if(err) {
this.callback(err);
} else {
this.executeNextCommand();
}
} else {
// Asynchronous command (await thenables)
// Asynchronous command
c = new command.Command(params,this,function(err) {
if(err) {
self.callback(err);
@@ -119,9 +117,7 @@ Commander.prototype.executeNextCommand = function() {
}
});
err = c.execute();
if(err && typeof err.then === "function") {
err.then(e => { if(e) this.callback(e); });
} else if(err) {
if(err) {
this.callback(err);
}
}
@@ -76,7 +76,6 @@ WikiFolderMaker.prototype.tiddlersToIgnore = [
"$:/boot/boot.js",
"$:/boot/bootprefix.js",
"$:/core",
"$:/core-server",
"$:/library/sjcl.js",
"$:/temp/info-plugin"
];
+1 -1
View File
@@ -34,7 +34,7 @@ function FramedEngine(options) {
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
this.iframeDoc.open();
this.iframeDoc.write("<!DOCTYPE html><html><head><meta name='color-scheme' content='" + colorScheme + "'></head><body></body></html>");
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
this.iframeDoc.close();
// Style the iframe
this.iframeNode.className = this.dummyTextArea.className;
+1 -1
View File
@@ -68,7 +68,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
// Fix height
this.engine.fixHeight();
// Focus if required
if($tw.browser && (this.editFocus === "true" || this.editFocus === "yes") && !$tw.utils.hasClass(this.parentDomNode.ownerDocument.activeElement,"tc-keep-focus")) {
if(this.editFocus === "true" || this.editFocus === "yes") {
this.engine.focus();
}
// Add widget message listeners
-4
View File
@@ -217,10 +217,6 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
source(function(tiddler,title) {
result.push($tw.utils.parseNumber(title));
});
// We return an empty array if there are no input titles
if(result.length === 0) {
return [];
}
var value = result.reduce(function(accumulator,currentValue) {
return fnCalc(accumulator,currentValue);
},initialValue);
-86
View File
@@ -1,86 +0,0 @@
/*\
title: $:/core/modules/info/windowdimensions.js
type: application/javascript
module-type: info
\*/
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
if(!$tw.browser) {
return [];
}
class WindowDimensionsTracker {
constructor(updateCallback) {
this.updateCallback = updateCallback;
this.resizeHandlers = new Map();
this.dimensionsInfo = [
["outer/width", win => win.outerWidth],
["outer/height", win => win.outerHeight],
["inner/width", win => win.innerWidth],
["inner/height", win => win.innerHeight],
["client/width", win => win.document.documentElement.clientWidth],
["client/height", win => win.document.documentElement.clientHeight]
];
}
buildTiddlers(win,windowId) {
const prefix = `$:/info/browser/window/${windowId}/`;
return this.dimensionsInfo.map(([suffix, getter]) => ({
title: prefix + suffix,
text: String(getter(win))
}));
}
clearTiddlers(windowId) {
const prefix = `$:/info/browser/window/${windowId}/`,
deletions = this.dimensionsInfo.map(([suffix]) => prefix + suffix);
this.updateCallback([], deletions);
}
getUpdateHandler(win,windowId) {
let scheduled = false;
return () => {
if(!scheduled) {
scheduled = true;
requestAnimationFrame(() => {
this.updateCallback(this.buildTiddlers(win,windowId), []);
scheduled = false;
});
}
};
}
trackWindow(win,windowId) {
const handler = this.getUpdateHandler(win, windowId);
handler(); // initial update
win.addEventListener("resize",handler,{passive:true});
this.resizeHandlers.set(windowId,{win, handler});
}
untrackWindow(windowId) {
const entry = this.resizeHandlers.get(windowId);
if(entry) {
entry.win.removeEventListener("resize", entry.handler);
this.resizeHandlers.delete(windowId);
}
this.clearTiddlers(windowId);
}
}
const tracker = new WindowDimensionsTracker(updateInfoTiddlersCallback);
// Track main window
tracker.trackWindow(window,"system/main");
// Hook into event bus for user windows
if($tw.eventBus) {
$tw.eventBus.on("window:opened", ({window: win, windowID}) => {
tracker.trackWindow(win, "user/" + windowID);
});
$tw.eventBus.on("window:closed", ({windowID}) => {
tracker.untrackWindow("user/" + windowID);
});
}
return [];
};
+3 -15
View File
@@ -7,34 +7,23 @@ The audio parser parses an audio tiddler into an embeddable HTML element
\*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var AudioParser = function(type,text,options) {
var element = {
type: "element",
tag: "$audio", // Using $audio to enable widget interception
tag: "audio",
attributes: {
controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"}
}
};
// Pass through source information
},
src;
if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri};
element.attributes.type = {type: "string", value: type};
} else if(text) {
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
element.attributes.type = {type: "string", value: type};
}
// Pass through tiddler title if available
if(options.title) {
element.attributes.tiddler = {type: "string", value: options.title};
}
this.tree = [element];
this.source = text;
this.type = type;
@@ -44,4 +33,3 @@ exports["audio/ogg"] = AudioParser;
exports["audio/mpeg"] = AudioParser;
exports["audio/mp3"] = AudioParser;
exports["audio/mp4"] = AudioParser;
+8 -9
View File
@@ -82,7 +82,6 @@ exports.parseTokenString = function(source,pos,token) {
/*
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
Use the "Y" (sticky) flag to avoid searching the entire rest of the string
*/
exports.parseTokenRegExp = function(source,pos,reToken) {
var node = {
@@ -173,7 +172,7 @@ exports.parseMacroParameter = function(source,pos) {
start: pos
};
// Define our regexp
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the parameter
@@ -241,7 +240,7 @@ exports.parseMacroInvocation = function(source,pos) {
params: []
};
// Define our regexps
const reMacroName = /([^\s>"'=]+)/y;
var reMacroName = /([^\s>"'=]+)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double less than sign
@@ -278,7 +277,7 @@ exports.parseFilterVariable = function(source) {
params: [],
},
pos = 0,
reName = /([^\s"']+)/y;
reName = /([^\s"']+)/g;
// If there is no whitespace or it is an empty string then there are no macro parameters
if(/^\S*$/.test(source)) {
node.name = source;
@@ -303,11 +302,11 @@ exports.parseAttribute = function(source,pos) {
start: pos
};
// Define our regexps
const reAttributeName = /([^\/\s>"'`=]+)/y,
reUnquotedAttribute = /([^\/\s<>"'`=]+)/y,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
reIndirectValue = /\{\{([^\}]+)\}\}/y,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
var reAttributeName = /([^\/\s>"'`=]+)/g,
reUnquotedAttribute = /([^\/\s<>"'`=]+)/g,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the attribute name
@@ -39,7 +39,7 @@ exports.parse = function() {
// Return the classed span
return [{
type: "element",
tag: "s",
tag: "strike",
children: tree
}];
};
@@ -49,7 +49,7 @@ exports.parse = function() {
// Advance the parser position to past the tag
this.parser.pos = tag.end;
// Check for an immediately following double linebreak
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
// Set whether we're in block mode
tag.isBlock = this.is.block || hasLineBreak;
// Parse the body if we need to
@@ -100,7 +100,7 @@ exports.parseTag = function(source,pos,options) {
orderedAttributes: []
};
// Define our regexps
const reTagName = /([a-zA-Z0-9\-\$\.]+)/y;
var reTagName = /([a-zA-Z0-9\-\$\.]+)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a less than sign
@@ -148,7 +148,7 @@ exports.parseTag = function(source,pos,options) {
pos = token.end;
// Check for a required line break
if(options.requireLineBreak) {
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
if(!token) {
return null;
}
@@ -113,7 +113,7 @@ exports.parseImage = function(source,pos) {
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the source up to the terminating `]]`
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/y);
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
if(!token) {
return null;
}
@@ -23,27 +23,6 @@ exports.init = function(parser) {
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg;
};
/*
Reject the match if we don't have a template or text reference
*/
exports.findNextMatch = function(startPos) {
this.matchRegExp.lastIndex = startPos;
this.match = this.matchRegExp.exec(this.parser.source);
if(this.match) {
var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]);
// Bail if we don't have a template or text reference
if(!template && !textRef) {
return undefined;
} else {
return this.match.index;
}
} else {
return undefined;
}
return this.match ? this.match.index : undefined;
};
exports.parse = function() {
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
@@ -23,27 +23,6 @@ exports.init = function(parser) {
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg;
};
/*
Reject the match if we don't have a template or text reference
*/
exports.findNextMatch = function(startPos) {
this.matchRegExp.lastIndex = startPos;
this.match = this.matchRegExp.exec(this.parser.source);
if(this.match) {
var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]);
// Bail if we don't have a template or text reference
if(!template && !textRef) {
return undefined;
} else {
return this.match.index;
}
} else {
return undefined;
}
return this.match ? this.match.index : undefined;
};
exports.parse = function() {
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
+1 -3
View File
@@ -35,9 +35,7 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
}
// Set up the link
var link = document.createElement("a");
// We prefer Blobs if they're available, unless we're dealing with a tiddler type declaring itself full of base64 encoded content.
// Then we use data urls, because browsers will know to decode the stream and download the actual binary file as intended.
if(Blob !== undefined && !type.includes(";base64")) {
if(Blob !== undefined) {
var blob = new Blob([text], {type: type});
link.setAttribute("href", URL.createObjectURL(blob));
} else {
-66
View File
@@ -1,66 +0,0 @@
/*\
title: $:/core/modules/savers/postmessage.js
type: application/javascript
module-type: saver
Handles saving changes via window.postMessage() to the window.parent
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Select the appropriate saver module and set it up
*/
var PostMessageSaver = function(wiki) {
this.publisher = new $tw.utils.BrowserMessagingPublisher({type: "SAVE"});
};
PostMessageSaver.prototype.save = function(text,method,callback,options) {
// Fail if the publisher hasn't been fully initialised
if(!this.publisher.canSend()) {
return false;
}
// Send the save request
this.publisher.send({
verb: "SAVE",
body: text
},function(err) {
if(err) {
callback("PostMessageSaver Error: " + err);
} else {
callback(null);
}
});
// Indicate that we handled the save
return true;
};
/*
Information about this saver
*/
PostMessageSaver.prototype.info = {
name: "postmessage",
capabilities: ["save", "autosave"],
priority: 100
};
/*
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
// Provisionally say that we can save
return true;
};
/*
Create an instance of this saver
*/
exports.create = function(wiki) {
return new PostMessageSaver(wiki);
};
})();
@@ -8,14 +8,10 @@ DELETE /recipes/default/tiddlers/:title
\*/
"use strict";
exports.methods = ["DELETE"];
exports.method = "DELETE";
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
state.wiki.deleteTiddler(title);
@@ -8,14 +8,10 @@ GET /favicon.ico
\*/
"use strict";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/favicon.ico$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
+42
View File
@@ -0,0 +1,42 @@
/*\
title: $:/core/modules/server/routes/get-file.js
type: application/javascript
module-type: route
GET /files/:filepath
\*/
"use strict";
exports.method = "GET";
exports.path = /^\/files\/(.+)$/;
exports.handler = function(request,response,state) {
var path = require("path"),
fs = require("fs"),
util = require("util"),
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
baseFilename = path.resolve(state.boot.wikiPath,"files"),
filename = path.resolve(baseFilename,suppliedFilename),
extension = path.extname(filename);
// Check that the filename is inside the wiki files folder
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
// Send the file
fs.readFile(filename,function(err,content) {
var status,content,type = "text/plain";
if(err) {
console.log("Error accessing file " + filename + ": " + err.toString());
status = 404;
content = "File '" + suppliedFilename + "' not found";
} else {
status = 200;
content = content;
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
}
state.sendResponse(status,{"Content-Type": type},content);
});
} else {
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
}
};
@@ -8,14 +8,10 @@ GET /
\*/
"use strict";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
responseHeaders = {
@@ -8,14 +8,10 @@ GET /login-basic -- force a Basic Authentication challenge
\*/
"use strict";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/login-basic$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
if(!state.authenticatedUsername) {
// Challenge if there's no username
@@ -8,14 +8,10 @@ GET /status
\*/
"use strict";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/status$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var text = JSON.stringify({
username: state.authenticatedUsername || state.server.get("anon-username") || "",
@@ -8,14 +8,10 @@ GET /:title
\*/
"use strict";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/([^\/]+)$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
tiddler = state.wiki.getTiddler(title);
@@ -8,14 +8,10 @@ GET /recipes/default/tiddlers/:title
\*/
"use strict";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
tiddler = state.wiki.getTiddler(title),
@@ -10,14 +10,10 @@ GET /recipes/default/tiddlers.json?filter=<filter>
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
exports.methods = ["GET"];
exports.method = "GET";
exports.path = /^\/recipes\/default\/tiddlers.json$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var filter = state.queryParameters.filter || DEFAULT_FILTER;
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
@@ -8,14 +8,10 @@ PUT /recipes/default/tiddlers/:title
\*/
"use strict";
exports.methods = ["PUT"];
exports.method = "PUT";
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
exports.info = {
priority: 100
};
exports.handler = function(request,response,state) {
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
fields = $tw.utils.parseJSONSafe(state.data);
@@ -74,11 +74,6 @@ function Server(options) {
// console.log("Loading server route " + title);
self.addRoute(routeDefinition);
});
this.routes.sort((a, b) => {
const priorityA = a.info?.priority ?? 100,
priorityB = b.info?.priority ?? 100;
return priorityB - priorityA;
});
// Initialise the http vs https
this.listenOptions = null;
this.protocol = "http";
@@ -222,7 +217,7 @@ Server.prototype.findMatchingRoute = function(request,state) {
} else {
match = potentialRoute.path.exec(pathname);
}
if(match && (potentialRoute.methods?.includes(request.method) || potentialRoute.method === request.method)) {
if(match && request.method === potentialRoute.method) {
state.params = [];
for(var p=1; p<match.length; p++) {
state.params.push(match[p]);
-46
View File
@@ -1,46 +0,0 @@
/*\
title: $:/core/modules/startup/eventbus.js
type: application/javascript
module-type: startup
Event bus for cross module communication
\*/
exports.name = "eventbus";
exports.platforms = ["browser"];
exports.before = ["windows"];
exports.synchronous = true;
$tw.eventBus = {
listenersMap: new Map(),
on(event,handler) {
if(!this.listenersMap.has(event)) {
this.listenersMap.set(event,new Set());
}
const listeners = this.listenersMap.get(event);
listeners.add(handler);
},
off(event,handler) {
const listeners = this.listenersMap.get(event);
if(listeners) {
listeners.delete(handler);
}
},
once(event,handler) {
const wrapper = (...args) => {
handler(...args);
this.off(event, wrapper);
};
this.on(event, wrapper);
},
emit(event,data) {
const listeners = this.listenersMap.get(event);
if(listeners) {
listeners.forEach(fn => fn(data));
}
}
};
+8 -10
View File
@@ -19,16 +19,6 @@ exports.synchronous = true;
var FAVICON_TITLE = "$:/favicon.ico";
exports.startup = function() {
var setFavicon = function() {
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
if(tiddler) {
var faviconLink = document.getElementById("faviconLink"),
dataURI = $tw.utils.makeDataUri(tiddler.fields.text,tiddler.fields.type,tiddler.fields._canonical_uri);
faviconLink.setAttribute("href",dataURI);
$tw.faviconPublisher.send({verb: "FAVICON",body: dataURI});
}
}
$tw.faviconPublisher = new $tw.utils.BrowserMessagingPublisher({type: "FAVICON", onsubscribe: setFavicon});
// Set up the favicon
setFavicon();
// Reset the favicon when the tiddler changes
@@ -38,3 +28,11 @@ exports.startup = function() {
}
});
};
function setFavicon() {
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
if(tiddler) {
var faviconLink = document.getElementById("faviconLink");
faviconLink.setAttribute("href",$tw.utils.makeDataUri(tiddler.fields.text,tiddler.fields.type,tiddler.fields._canonical_uri));
}
}
+4 -10
View File
@@ -19,17 +19,11 @@ var TITLE_INFO_PLUGIN = "$:/temp/info-plugin";
exports.startup = function() {
// Function to bake the info plugin with new tiddlers
// additions: array of tiddler field objects
// removals: array of titles to remove
var updateInfoPlugin = function(additions = [], removals = []) {
var updateInfoPlugin = function(tiddlerFieldsArray) {
// Get the existing tiddlers
var json = $tw.wiki.getTiddlerData(TITLE_INFO_PLUGIN,{tiddlers: {}});
$tw.utils.each(removals,function(title) {
if(json.tiddlers[title]) {
delete json.tiddlers[title];
}
});
$tw.utils.each(additions,function(fields) {
// Add the new ones
$tw.utils.each(tiddlerFieldsArray,function(fields) {
if(fields && fields.title) {
json.tiddlers[fields.title] = fields;
}
@@ -53,7 +47,7 @@ exports.startup = function() {
}
});
updateInfoPlugin(tiddlerFieldsArray);
$tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
var changes = $tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
$tw.wiki.registerPluginTiddlers("info",[TITLE_INFO_PLUGIN]);
$tw.wiki.unpackPluginTiddlers();
};
+1 -3
View File
@@ -31,7 +31,5 @@ exports.startup = function() {
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
$tw.wiki.initParsers();
if($tw.node) {
$tw.Commander.initCommands();
}
$tw.Commander.initCommands();
};
+2 -7
View File
@@ -33,15 +33,10 @@ exports.startup = function() {
});
$tw.titleContainer = $tw.fakeDocument.createElement("div");
$tw.titleWidgetNode.render($tw.titleContainer,null);
var publishTitle = function() {
$tw.titlePublisher.send({verb: "PAGETITLE",body: document.title});
document.title = $tw.titleContainer.textContent;
};
$tw.titlePublisher = new $tw.utils.BrowserMessagingPublisher({type: "PAGETITLE", onsubscribe: publishTitle});
publishTitle();
document.title = $tw.titleContainer.textContent;
$tw.wiki.addEventListener("change",function(changes) {
if($tw.titleWidgetNode.refresh(changes,$tw.titleContainer,null)) {
publishTitle();
document.title = $tw.titleContainer.textContent;
}
});
// Set up the styles
-2
View File
@@ -56,11 +56,9 @@ exports.startup = function() {
srcDocument.write("<!DOCTYPE html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
srcDocument.close();
srcDocument.title = windowTitle;
$tw.eventBus.emit("window:opened",{windowID, window: srcWindow});
srcWindow.addEventListener("beforeunload",function(event) {
delete $tw.windows[windowID];
$tw.wiki.removeEventListener("change",refreshHandler);
$tw.eventBus.emit("window:closed",{windowID});
},false);
// Set up the styles
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
+7 -5
View File
@@ -47,16 +47,16 @@ ClassicStoryView.prototype.insert = function(widget) {
// Reset the margin once the transition is over
setTimeout(function() {
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: ""}
]);
$tw.utils.removeStyle(targetElement, "transition");
},duration);
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
$tw.utils.removeStyle(targetElement, "transition");
$tw.utils.forceLayout(targetElement);
// Transition to the final position
$tw.utils.setStyle(targetElement,[
@@ -64,7 +64,7 @@ ClassicStoryView.prototype.insert = function(widget) {
"margin-bottom " + duration + "ms " + easing},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
]);
]);
}
};
@@ -94,9 +94,11 @@ ClassicStoryView.prototype.remove = function(widget) {
setTimeout(removeElement,duration);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "translateX(0px)"},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
]);
$tw.utils.removeStyles(targetElement, ["transition", "transform", "opacity"]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
@@ -111,4 +113,4 @@ ClassicStoryView.prototype.remove = function(widget) {
}
};
exports.classic = ClassicStoryView;
exports.classic = ClassicStoryView;
+11 -7
View File
@@ -37,7 +37,10 @@ PopStoryView.prototype.insert = function(widget) {
}
// Reset once the transition is over
setTimeout(function() {
$tw.utils.removeStyles(targetElement, ["transition", "transform"]);
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "none"}
]);
$tw.utils.setStyle(widget.document.body,[
{"overflow-x": ""}
]);
@@ -48,10 +51,10 @@ PopStoryView.prototype.insert = function(widget) {
]);
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "scale(2)"},
{opacity: "0.0"}
]);
$tw.utils.removeStyle(targetElement, "transition");
$tw.utils.forceLayout(targetElement);
// Transition to the final position
$tw.utils.setStyle(targetElement,[
@@ -60,9 +63,6 @@ PopStoryView.prototype.insert = function(widget) {
{transform: "scale(1)"},
{opacity: "1.0"}
]);
setTimeout(function() {
$tw.utils.removeStyles(targetElement, ["transition", "transform", "opactity"]);
}, duration)
};
PopStoryView.prototype.remove = function(widget) {
@@ -81,7 +81,11 @@ PopStoryView.prototype.remove = function(widget) {
// Remove the element at the end of the transition
setTimeout(removeElement,duration);
// Animate the closure
$tw.utils.removeStyles(targetElement, ["transition", "transform", "opacity"]);
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "scale(1)"},
{opacity: "1.0"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms ease-in-out, " +
@@ -91,4 +95,4 @@ PopStoryView.prototype.remove = function(widget) {
]);
};
exports.pop = PopStoryView;
exports.pop = PopStoryView;
+1 -7
View File
@@ -96,9 +96,6 @@ ZoominListView.prototype.navigateTo = function(historyInfo) {
{transform: "translateX(0px) translateY(0px) scale(1)"},
{zIndex: "500"},
]);
setTimeout(function() {
$tw.utils.removeStyles(targetElement, ["transition", "opacity", "transform", "zIndex"]);
}, duration);
// Transform the previous tiddler out of the way and then hide it
if(prevCurrentTiddler && prevCurrentTiddler !== targetElement) {
scale = zoomBounds.width / sourceBounds.width;
@@ -210,9 +207,6 @@ ZoominListView.prototype.remove = function(widget) {
{opacity: "0"},
{zIndex: "0"}
]);
setTimeout(function() {
$tw.utils.removeStyles(toWidgetDomNode, ["transformOrigin", "transform", "transition", "opacity", "zIndex"]);
}, duration);
setTimeout(removeElement,duration);
// Now the tiddler we're going back to
if(toWidgetDomNode) {
@@ -228,4 +222,4 @@ ZoominListView.prototype.logTextNodeRoot = function(node) {
this.textNodeLogger.log($tw.language.getString("Error/ZoominTextNode") + " " + node.textContent);
};
exports.zoomin = ZoominListView;
exports.zoomin = ZoominListView;
@@ -0,0 +1,142 @@
// From https://gist.github.com/Nijikokun/5192472
//
// UTF8 Module
//
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
//
// copyright: MIT
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
(function (name, definition, context, dependencies) {
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
else { context[name] = definition.apply(context); }
})('utf8', function () {
return {
encode: function (string) {
if (typeof string !== 'string') return string;
else string = string.replace(/\r\n/g, "\n");
var output = "", i = 0, charCode;
for (i; i < string.length; i++) {
charCode = string.charCodeAt(i);
if (charCode < 128) {
output += String.fromCharCode(charCode);
} else if ((charCode > 127) && (charCode < 2048)) {
output += String.fromCharCode((charCode >> 6) | 192);
output += String.fromCharCode((charCode & 63) | 128);
} else if ((charCode > 55295) && (charCode < 57344) && string.length > i+1) {
// Surrogate pair
var hiSurrogate = charCode;
var loSurrogate = string.charCodeAt(i+1);
i++; // Skip the low surrogate on the next loop pass
var codePoint = (((hiSurrogate - 55296) << 10) | (loSurrogate - 56320)) + 65536;
output += String.fromCharCode((codePoint >> 18) | 240);
output += String.fromCharCode(((codePoint >> 12) & 63) | 128);
output += String.fromCharCode(((codePoint >> 6) & 63) | 128);
output += String.fromCharCode((codePoint & 63) | 128);
} else {
// Not a surrogate pair, or a dangling surrogate without its partner that we'll just encode as-is
output += String.fromCharCode((charCode >> 12) | 224);
output += String.fromCharCode(((charCode >> 6) & 63) | 128);
output += String.fromCharCode((charCode & 63) | 128);
}
}
return output;
},
decode: function (string) {
if (typeof string !== 'string') return string;
var output = "", i = 0, charCode = 0;
while (i < string.length) {
charCode = string.charCodeAt(i);
if (charCode < 128) {
output += String.fromCharCode(charCode),
i++;
} else if ((charCode > 191) && (charCode < 224)) {
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63));
i += 2;
} else if ((charCode > 223) && (charCode < 240)) {
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63));
i += 3;
} else {
var codePoint = ((charCode & 7) << 18) | ((string.charCodeAt(i + 1) & 63) << 12) | ((string.charCodeAt(i + 2) & 63) << 6) | (string.charCodeAt(i + 3) & 63);
// output += String.fromCodePoint(codePoint); // Can't do this because Internet Explorer doesn't have String.fromCodePoint
output += String.fromCharCode(((codePoint - 65536) >> 10) + 55296) + String.fromCharCode(((codePoint - 65536) & 1023) + 56320); // So we do this instead
i += 4;
}
}
return output;
}
};
}, this);
// Base64 Module
//
// Cleaner, modularized and properly scoped base64 encoding and decoding module for strings.
//
// copyright: MIT
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
(function (name, definition, context, dependencies) {
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
else { context[name] = definition.apply(context); }
})('base64', function (utf8) {
var $this = this;
var $utf8 = utf8 || this.utf8;
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function (input) {
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
if (typeof input !== 'string') return input;
else input = $utf8.encode(input);
var output = "", a, b, c, d, e, f, g, i = 0;
while (i < input.length) {
a = input.charCodeAt(i++);
b = input.charCodeAt(i++);
c = input.charCodeAt(i++);
d = a >> 2;
e = ((a & 3) << 4) | (b >> 4);
f = ((b & 15) << 2) | (c >> 6);
g = c & 63;
if (isNaN(b)) f = g = 64;
else if (isNaN(c)) g = 64;
output += map.charAt(d) + map.charAt(e) + map.charAt(f) + map.charAt(g);
}
return output;
},
decode: function (input) {
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
if (typeof input !== 'string') return input;
else input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
var output = "", a, b, c, d, e, f, g, i = 0;
while (i < input.length) {
d = map.indexOf(input.charAt(i++));
e = map.indexOf(input.charAt(i++));
f = map.indexOf(input.charAt(i++));
g = map.indexOf(input.charAt(i++));
a = (d << 2) | (e >> 4);
b = ((e & 15) << 4) | (f >> 2);
c = ((f & 3) << 6) | g;
output += String.fromCharCode(a);
if (f != 64) output += String.fromCharCode(b);
if (g != 64) output += String.fromCharCode(c);
}
return $utf8.decode(output);
}
}
}, this, [ "utf8" ]);
@@ -0,0 +1,9 @@
// From https://gist.github.com/Nijikokun/5192472
//
// UTF8 Module
//
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
//
// copyright: MIT
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
!function(r,e,o,t){void 0!==o.module&&o.module.exports?o.module.exports=e.apply(o):void 0!==o.define&&"function"===o.define&&o.define.amd?define("utf8",[],e):o.utf8=e.apply(o)}(0,function(){return{encode:function(r){if("string"!=typeof r)return r;r=r.replace(/\r\n/g,"\n");for(var e,o="",t=0;t<r.length;t++)if((e=r.charCodeAt(t))<128)o+=String.fromCharCode(e);else if(e>127&&e<2048)o+=String.fromCharCode(e>>6|192),o+=String.fromCharCode(63&e|128);else if(e>55295&&e<57344&&r.length>t+1){var i=e,n=r.charCodeAt(t+1);t++;var d=65536+(i-55296<<10|n-56320);o+=String.fromCharCode(d>>18|240),o+=String.fromCharCode(d>>12&63|128),o+=String.fromCharCode(d>>6&63|128),o+=String.fromCharCode(63&d|128)}else o+=String.fromCharCode(e>>12|224),o+=String.fromCharCode(e>>6&63|128),o+=String.fromCharCode(63&e|128);return o},decode:function(r){if("string"!=typeof r)return r;for(var e="",o=0,t=0;o<r.length;)if((t=r.charCodeAt(o))<128)e+=String.fromCharCode(t),o++;else if(t>191&&t<224)e+=String.fromCharCode((31&t)<<6|63&r.charCodeAt(o+1)),o+=2;else if(t>223&&t<240)e+=String.fromCharCode((15&t)<<12|(63&r.charCodeAt(o+1))<<6|63&r.charCodeAt(o+2)),o+=3;else{var i=(7&t)<<18|(63&r.charCodeAt(o+1))<<12|(63&r.charCodeAt(o+2))<<6|63&r.charCodeAt(o+3);e+=String.fromCharCode(55296+(i-65536>>10))+String.fromCharCode(56320+(i-65536&1023)),o+=4}return e}}},this),function(r,e,o,t){if(void 0!==o.module&&o.module.exports){if(t&&o.require)for(var i=0;i<t.length;i++)o[t[i]]=o.require(t[i]);o.module.exports=e.apply(o)}else void 0!==o.define&&"function"===o.define&&o.define.amd?define("base64",t||[],e):o.base64=e.apply(o)}(0,function(r){var e=r||this.utf8,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=e.encode(r);for(var t,i,n,d,f,a,h,C="",c=0;c<r.length;)d=(t=r.charCodeAt(c++))>>2,f=(3&t)<<4|(i=r.charCodeAt(c++))>>4,a=(15&i)<<2|(n=r.charCodeAt(c++))>>6,h=63&n,isNaN(i)?a=h=64:isNaN(n)&&(h=64),C+=o.charAt(d)+o.charAt(f)+o.charAt(a)+o.charAt(h);return C},decode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(var t,i,n,d,f,a,h="",C=0;C<r.length;)t=o.indexOf(r.charAt(C++))<<2|(d=o.indexOf(r.charAt(C++)))>>4,i=(15&d)<<4|(f=o.indexOf(r.charAt(C++)))>>2,n=(3&f)<<6|(a=o.indexOf(r.charAt(C++))),h+=String.fromCharCode(t),64!=f&&(h+=String.fromCharCode(i)),64!=a&&(h+=String.fromCharCode(n));return e.decode(h)}}},this,["utf8"]);
@@ -0,0 +1,14 @@
{
"tiddlers": [
{
"file": "base64-utf8.module.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/core/modules/utils/base64-utf8/base64-utf8.module.js",
"module-type": "library"
},
"prefix": "(function(){",
"suffix": "}).call(exports);"
}
]
}
-20
View File
@@ -24,26 +24,6 @@ exports.setStyle = function(element,styles) {
}
};
/*
Remove style properties of an element
element: dom node
styleProperties: ordered array of string property names
*/
exports.removeStyles = function(element, styleProperties) {
for (var i=0; i<styleProperties.length; i++) {
element.style.removeProperty($tw.utils.convertStyleNameToPropertyName(styleProperties[i]));
}
}
/*
Remove single style property of an element
element: dom node
styleProperty: string property name
*/
exports.removeStyle = function(element, styleProperty) {
$tw.utils.removeStyles(element, [styleProperty])
}
/*
Converts a standard CSS property name into the local browser-specific equivalent. For example:
"background-color" --> "backgroundColor"
+1 -1
View File
@@ -210,7 +210,7 @@ Modal.prototype.display = function(title,options) {
bodyWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
footerWidgetNode.addEventListener("tm-close-tiddler",closeHandler,false);
// Whether to close the modal dialog when the mask (area outside the modal) is clicked
if(tiddler.fields && (tiddler.fields["mask-closable"] === "yes" || tiddler.fields["mask-closable"] === "true" || tiddler.fields["mask-closable"] === "" || "mask-closable" in tiddler.fields === false)) {
if(tiddler.fields && (tiddler.fields["mask-closable"] === "yes" || tiddler.fields["mask-closable"] === "true")) {
modalBackdrop.addEventListener("click",closeHandler,false);
}
// Set the initial styles for the message
-126
View File
@@ -1,126 +0,0 @@
/*\
title: $:/core/modules/utils/messaging.js
type: application/javascript
module-type: utils-browser
Messaging utilities for use with window.postMessage() etc.
This module intentionally has no dependencies so that it can be included in non-TiddlyWiki projects
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var RESPONSE_TIMEOUT = 2 * 1000;
/*
Class to handle subscribing to publishers
target: Target window (eg iframe.contentWindow)
type: String indicating type of item for which subscriptions are being provided (eg "SAVING")
onsubscribe: Function to be invoked with err parameter when the subscription is established, or there is a timeout
onmessage: Function to be invoked when a new message arrives, invoked with (data,callback). The callback is invoked with the argument (response)
*/
function BrowserMessagingSubscriber(options) {
var self = this;
this.target = options.target;
this.type = options.type;
this.onsubscribe = options.onsubscribe || function() {};
this.onmessage = options.onmessage;
this.hasConfirmed = false;
this.channel = new MessageChannel();
this.channel.port1.addEventListener("message",function(event) {
if(this.timerID) {
clearTimeout(this.timerID);
this.timerID = null;
}
if(event.data) {
if(event.data.verb === "SUBSCRIBED") {
self.hasConfirmed = true;
self.onsubscribe(null);
} else if(event.data.verb === self.type) {
self.onmessage(event.data,function(response) {
// Send the response back on the supplied port, and then close it
event.ports[0].postMessage(response);
event.ports[0].close();
});
}
}
});
// Set a timer so that if we don't hear from the iframe before a timeout we alert the user
this.timerID = setTimeout(function() {
if(!self.hasConfirmed) {
self.onsubscribe("NO_RESPONSE");
}
},RESPONSE_TIMEOUT);
this.channel.port1.start();
this.target.postMessage({verb: "SUBSCRIBE",to: self.type},"*",[this.channel.port2]);
}
exports.BrowserMessagingSubscriber = BrowserMessagingSubscriber;
/*
Class to handle publishing subscriptions
type: String indicating type of item for which subscriptions are being provided (eg "SAVING")
onsubscribe: Function to be invoked when a subscription occurs
*/
function BrowserMessagingPublisher(options) {
var self = this;
this.type = options.type;
this.hostIsListening = false;
this.port = null;
// Listen to connection requests from the host
window.addEventListener("message",function(event) {
if(event.data && event.data.verb === "SUBSCRIBE" && event.data.to === self.type) {
self.hostIsListening = true;
// Acknowledge
self.port = event.ports[0];
self.port.postMessage({verb: "SUBSCRIBED", to: self.type});
if(options.onsubscribe) {
options.onsubscribe(event.data);
}
}
});
}
BrowserMessagingPublisher.prototype.canSend = function() {
return !!this.hostIsListening && !!this.port;
};
BrowserMessagingPublisher.prototype.send = function(data,callback) {
var self = this;
callback = callback || function() {};
// Check that we've been initialised by the host
if(!this.hostIsListening || !this.port) {
return false;
}
// Create a channel for the confirmation
var channel = new MessageChannel();
channel.port1.addEventListener("message",function(event) {
if(event.data && event.data.verb === "OK") {
callback(null);
} else {
callback("BrowserMessagingPublisher for " + self.type + " error: " + (event.data || {}).verb);
}
channel.port1.close();
});
channel.port1.start();
// Send the save request with the port for the response
this.port.postMessage(data,[channel.port2]);
};
BrowserMessagingPublisher.prototype.close = function() {
if(this.port) {
this.port.close();
this.hostIsListening = false;
this.port = null;
}
};
exports.BrowserMessagingPublisher = BrowserMessagingPublisher;
})();
+7 -33
View File
@@ -9,6 +9,8 @@ Various static utility functions.
"use strict";
var base64utf8 = require("$:/core/modules/utils/base64-utf8/base64-utf8.module.js");
/*
Display a message, in colour if we're on a terminal
*/
@@ -840,50 +842,22 @@ if(typeof window !== 'undefined') {
}
}
exports.base64ToBytes = function(base64) {
const binString = exports.atob(base64);
return Uint8Array.from(binString, (m) => m.codePointAt(0));
};
exports.bytesToBase64 = function(bytes) {
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
return exports.btoa(binString);
};
exports.base64EncodeUtf8 = function(str) {
if ($tw.browser) {
return exports.bytesToBase64(new TextEncoder().encode(str));
} else {
const buff = Buffer.from(str, "utf-8");
return buff.toString("base64");
}
};
exports.base64DecodeUtf8 = function(str) {
if ($tw.browser) {
return new TextDecoder().decode(exports.base64ToBytes(str));
} else {
const buff = Buffer.from(str, "base64");
return buff.toString("utf-8");
}
};
/*
Decode a base64 string
*/
exports.base64Decode = function(string64,binary,urlsafe) {
const encoded = urlsafe ? string64.replace(/_/g,'/').replace(/-/g,'+') : string64;
var encoded = urlsafe ? string64.replace(/_/g,'/').replace(/-/g,'+') : string64;
if(binary) return exports.atob(encoded)
else return exports.base64DecodeUtf8(encoded);
else return base64utf8.base64.decode.call(base64utf8,encoded);
};
/*
Encode a string to base64
*/
exports.base64Encode = function(string64,binary,urlsafe) {
let encoded;
var encoded;
if(binary) encoded = exports.btoa(string64);
else encoded = exports.base64EncodeUtf8(string64);
else encoded = base64utf8.base64.encode.call(base64utf8,string64);
if(urlsafe) {
encoded = encoded.replace(/\+/g,'-').replace(/\//g,'_');
}
@@ -1049,7 +1023,7 @@ exports.makeCompareFunction = function(type,options) {
return compare(dateA,dateB);
},
"version": function(a,b) {
return compare($tw.utils.compareVersions(a,b),0);
return $tw.utils.compareVersions(a,b);
},
"alphanumeric": function(a,b) {
if(!isCaseSensitive) {
-103
View File
@@ -1,103 +0,0 @@
/*\
title: $:/core/modules/widgets/audio.js
type: application/javascript
module-type: widget
Basic Audio widget for displaying audio files.
This is a simple implementation that can be overridden by plugins
for more advanced functionality.
\*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var AudioWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
AudioWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
AudioWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create audio element
var audioElement = this.document.createElement("audio");
audioElement.setAttribute("controls", this.getAttribute("controls", "controls"));
audioElement.setAttribute("style", this.getAttribute("style", "width: 100%; object-fit: contain"));
audioElement.className = "tw-audio-element";
// Set source
if(this.audioSource) {
if (this.audioSource.indexOf("data:") === 0) {
audioElement.setAttribute("src", this.audioSource);
} else {
var sourceElement = this.document.createElement("source");
sourceElement.setAttribute("src", this.audioSource);
if(this.audioType) {
sourceElement.setAttribute("type", this.audioType);
}
audioElement.appendChild(sourceElement);
}
}
// Insert the audio into the DOM
parent.insertBefore(audioElement, nextSibling);
this.domNodes.push(audioElement);
};
/*
Compute the internal state of the widget
*/
AudioWidget.prototype.execute = function() {
// Get the audio source and type
this.audioSource = this.getAttribute("src");
this.audioType = this.getAttribute("type");
this.audioControls = this.getAttribute("controls", "controls");
// Try to get from tiddler attribute
if(!this.audioSource && this.getAttribute("tiddler")) {
var tiddlerTitle = this.getAttribute("tiddler");
var tiddler = this.wiki.getTiddler(tiddlerTitle);
if(tiddler) {
if(tiddler.fields._canonical_uri) {
this.audioSource = tiddler.fields._canonical_uri;
this.audioType = tiddler.fields.type;
} else if(tiddler.fields.text) {
this.audioSource = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
this.audioType = tiddler.fields.type;
}
}
}
// Make sure we have a tiddler for saving timestamps
this.tiddlerTitle = this.getAttribute("tiddler");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
AudioWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.src || changedAttributes.type || changedAttributes.controls || changedAttributes.tiddler) {
this.refreshSelf();
return true;
} else {
return false;
}
};
exports.audio = AudioWidget;
+4 -8
View File
@@ -61,10 +61,6 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
sourcePrefix: "data-",
destPrefix: "data-"
});
this.assignAttributes(domNode,{
sourcePrefix: "aria-",
destPrefix: "aria-"
});
// Assign other attributes
if(this.style) {
domNode.setAttribute("style",this.style);
@@ -72,6 +68,9 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
if(this.tooltip) {
domNode.setAttribute("title",this.tooltip);
}
if(this["aria-label"]) {
domNode.setAttribute("aria-label",this["aria-label"]);
}
if (this.role) {
domNode.setAttribute("role", this.role);
}
@@ -216,6 +215,7 @@ ButtonWidget.prototype.execute = function() {
this.setTo = this.getAttribute("setTo");
this.popup = this.getAttribute("popup");
this.hover = this.getAttribute("hover");
this["aria-label"] = this.getAttribute("aria-label");
this.role = this.getAttribute("role");
this.tooltip = this.getAttribute("tooltip");
this.style = this.getAttribute("style");
@@ -271,10 +271,6 @@ ButtonWidget.prototype.refresh = function(changedTiddlers) {
sourcePrefix: "data-",
destPrefix: "data-"
});
this.assignAttributes(this.domNodes[0],{
sourcePrefix: "aria-",
destPrefix: "aria-"
});
}
return this.refreshChildren(changedTiddlers);
};
-2
View File
@@ -74,8 +74,6 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
// Create the DOM node and render children
var domNode = this.document.createElementNS(this.namespace,this.tag);
this.assignAttributes(domNode,{excludeEventAttributes: true});
// Allow hooks to manipulate the DOM node. Eg: Add debug info
$tw.hooks.invokeHook("th-dom-rendering-element", domNode, this);
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
+4 -1
View File
@@ -44,7 +44,7 @@ EventWidget.prototype.render = function(parent,nextSibling) {
domNode.addEventListener(type,function(event) {
var selector = self.getAttribute("selector"),
matchSelector = self.getAttribute("matchSelector"),
actions = self.getAttribute("$"+type),
actions = self.getAttribute("$"+type) || self.getAttribute("actions-"+type),
stopPropagation = self.getAttribute("stopPropagation","onaction"),
selectedNode = event.target,
selectedNodeRect,
@@ -122,6 +122,9 @@ EventWidget.prototype.execute = function() {
self.types.push(key.slice(1));
}
});
if(!this.types.length) {
this.types = this.getAttribute("events","").split(" ");
}
this.elementTag = this.getAttribute("tag");
// Make child widgets
this.makeChildWidgets();
+3 -13
View File
@@ -45,10 +45,6 @@ LinkWidget.prototype.render = function(parent,nextSibling) {
sourcePrefix: "data-",
destPrefix: "data-"
});
this.assignAttributes(domNode,{
sourcePrefix: "aria-",
destPrefix: "aria-"
});
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
@@ -129,13 +125,9 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
});
domNode.setAttribute("title",tooltipText);
}
if(this.role) {
domNode.setAttribute("role",this.role);
if(this["aria-label"]) {
domNode.setAttribute("aria-label",this["aria-label"]);
}
this.assignAttributes(domNode,{
sourcePrefix: "aria-",
destPrefix: "aria-"
})
// Add a click event handler
$tw.utils.addEventListeners(domNode,[
{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"},
@@ -147,8 +139,6 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
dragTiddlerFn: function() {return self.to;},
widget: this
});
} else if(this.draggable === "no") {
domNode.setAttribute("draggable","false");
}
// Assign data- attributes
this.assignAttributes(domNode,{
@@ -198,7 +188,7 @@ LinkWidget.prototype.execute = function() {
// Pick up our attributes
this.to = this.getAttribute("to",this.getVariable("currentTiddler"));
this.tooltip = this.getAttribute("tooltip");
this.role = this.getAttribute("role");
this["aria-label"] = this.getAttribute("aria-label");
this.linkClasses = this.getAttribute("class");
this.overrideClasses = this.getAttribute("overrideClass");
this.tabIndex = this.getAttribute("tabindex");
+15 -1
View File
@@ -94,6 +94,8 @@ RangeWidget.prototype.getActionVariables = function(options) {
// actionsStart
RangeWidget.prototype.handleMouseDownEvent = function(event) {
this.mouseDown = true; // TODO remove once IE is gone.
this.startValue = this.inputDomNode.value; // TODO remove this line once IE is gone!
this.handleEvent(event);
// Trigger actions
if(this.actionsMouseDown) {
@@ -104,16 +106,26 @@ RangeWidget.prototype.handleMouseDownEvent = function(event) {
// actionsStop
RangeWidget.prototype.handleMouseUpEvent = function(event) {
this.mouseDown = false; // TODO remove once IE is gone.
this.handleEvent(event);
// Trigger actions
if(this.actionsMouseUp) {
var variables = this.getActionVariables()
this.invokeActionString(this.actionsMouseUp,this,event,variables);
}
// TODO remove the following if() once IE is gone!
if ($tw.browser.isIE) {
if (this.startValue !== this.inputDomNode.value) {
this.handleChangeEvent(event);
this.startValue = this.inputDomNode.value;
}
}
}
RangeWidget.prototype.handleChangeEvent = function(event) {
this.handleInputEvent(event);
if (this.mouseDown) { // TODO refactor this function once IE is gone.
this.handleInputEvent(event);
}
};
RangeWidget.prototype.handleInputEvent = function(event) {
@@ -140,6 +152,8 @@ RangeWidget.prototype.handleEvent = function(event) {
Compute the internal state of the widget
*/
RangeWidget.prototype.execute = function() {
// TODO remove the next 1 lines once IE is gone!
this.mouseUp = true; // Needed for IE10
// Get the parameters from the attributes
this.tiddlerTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.tiddlerField = this.getAttribute("field","text");
+1 -1
View File
@@ -181,7 +181,7 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
};
ScrollableWidget.prototype.listenerFunction = function(event) {
var self = this;
self = this;
clearTimeout(this.timeout);
this.timeout = setTimeout(function() {
var existingTiddler = self.wiki.getTiddler(self.scrollableBind),
+1 -1
View File
@@ -1443,7 +1443,7 @@ exports.search = function(text,options) {
// Don't search the text field if the content type is binary
var fieldName = searchFields[fieldIndex];
if(fieldName === "text" && contentTypeInfo.encoding !== "utf8") {
continue;
break;
}
var str = tiddler.fields[fieldName],
t;

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