1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-21 01:19:53 +00:00

Compare commits

..

217 Commits

Author SHA1 Message Date
Jeremy Ruston
2dd9a2006d Impact note about wikified palettes 2026-01-30 20:57:13 +00:00
Jeremy Ruston
ebff5aa3db Make Palette be the default Appearance tab in control panel 2026-01-30 20:56:59 +00:00
Jeremy Ruston
3bc2c5fabc Remove appply filter run prefix 2026-01-30 20:56:38 +00:00
Jeremy Ruston
d423aa926e Tweak lingo 2026-01-30 20:56:14 +00:00
Jeremy Ruston
fe708eefc6 Merge branch 'master' into colour-improvements 2026-01-23 09:03:47 +00:00
Jeremy Ruston
a7525037fd Improve English 2026-01-22 12:11:45 +00:00
Jeremy Ruston
15736bceb9 Add test for invalid pragma 2026-01-21 21:49:16 +00:00
Jeremy Ruston
35b0108da6 Fix parsing bug 2026-01-21 21:45:45 +00:00
Jeremy Ruston
59d23da97c Merge branch 'default-prefix-for-subfilter' into colour-improvements 2026-01-20 16:22:01 +00:00
Jeremy Ruston
3f654bccaa Revert previous merge from #9595
This reverts commit eb8f69dd03.
2026-01-20 16:04:28 +00:00
Jeremy Ruston
a45a8723c0 Add a view template body for palettes 2026-01-19 21:20:08 +00:00
Jeremy Ruston
ae7d6da35b Add a P3 palette for testing 2026-01-19 12:54:27 +00:00
Jeremy Ruston
a8e056c88c Merge branch 'default-prefix-for-subfilter' into colour-improvements 2026-01-19 12:54:01 +00:00
Jeremy Ruston
5b0af905a2 Use the subfilter suffix to suppress deduping palette entries 2026-01-19 12:53:45 +00:00
Jeremy Ruston
eb8f69dd03 Merge subfilter fix from #9595 2026-01-19 12:52:58 +00:00
Jeremy Ruston
ef49828989 temp 2026-01-19 12:49:08 +00:00
Jeremy Ruston
9b56734451 Extend subfilter operator with suffix for specifying the default filter run prefix 2026-01-19 11:31:09 +00:00
Jeremy Ruston
2f8d53d3f7 Allow default filter run prefix to be specified for filter evaluation 2026-01-19 11:30:50 +00:00
Jeremy Ruston
5b96929f4e Fix tests 2026-01-18 12:03:59 +00:00
Jeremy Ruston
829bb61378 Merge branch 'master' into colour-improvements 2026-01-18 11:48:42 +00:00
Jeremy Ruston
421ecff30f Merge branch 'master' into colour-improvements 2026-01-17 17:52:34 +00:00
Jeremy Ruston
c7511fc99f Tweak credits for 2026 palettes 2026-01-17 17:50:27 +00:00
Jeremy Ruston
87f797b1ae Fix use of creaky old technique for setting alpha/opacity from a different base colour 2026-01-17 17:46:25 +00:00
Jeremy Ruston
8cc94d8ea7 Fix year category for new palettes 2026-01-17 17:45:12 +00:00
Jeremy Ruston
dcaff6a243 Revert linter fixes for unused function parameters 2026-01-17 17:29:28 +00:00
Jeremy Ruston
e98aed6f6e Fix remaining references to palettes-2025 plugin 2026-01-17 17:23:16 +00:00
Jeremy Ruston
d35e34b55e Remove debugging code
It was breaking colour assignment as a property, rather than in a stylesheet
2026-01-17 17:22:57 +00:00
Jeremy Ruston
bb4d57e170 More linting dancing 2026-01-17 17:00:24 +00:00
Jeremy Ruston
fd709afc37 More linting errors 2026-01-17 16:53:52 +00:00
Jeremy Ruston
93388bc3cc Fix lint errors 2026-01-17 16:05:32 +00:00
Jeremy Ruston
a8c4437587 Properly credit the new palettes 2026-01-17 15:48:16 +00:00
Jeremy Ruston
6dc83386bd Update new palettes to 2026 category 2026-01-17 15:44:42 +00:00
Jeremy Ruston
9641e6a2d0 Remove docs for apply filter run prefix 2026-01-17 15:43:45 +00:00
Jeremy Ruston
3254544eb2 Update the 2025 palette plugin to 2026 2026-01-17 15:42:09 +00:00
Jeremy Ruston
c707b9a432 Enable change note 2026-01-17 15:39:37 +00:00
Jeremy Ruston
3cab1571be Don't lint color.js 2026-01-17 15:39:19 +00:00
Jeremy Ruston
502598bd25 Switch from apply filter run to let filter run 2026-01-17 15:35:27 +00:00
Jeremy Ruston
8a18f92710 Typo 2026-01-17 13:02:54 +00:00
Jeremy Ruston
3353d0e005 Upgrade color.js 2026-01-17 12:53:41 +00:00
Jeremy Ruston
fd85842036 Merge branch 'master' into colour-improvements 2026-01-16 22:40:35 +00:00
Jeremy Ruston
b0dc46c9e9 Avoid using camel case for new docs tiddlers 2026-01-16 22:40:27 +00:00
Jeremy Ruston
5b0c923a82 Merge branch 'master' into colour-improvements 2026-01-08 11:23:43 +00:00
Jeremy Ruston
ae33a4521d Merge branch 'master' into colour-improvements 2025-09-14 17:22:59 +01:00
Jeremy Ruston
4b83e89d40 Move palettes into plugins 2025-08-06 15:13:10 +01:00
Jeremy Ruston
da41483172 Prepare to split palettes out into plugins 2025-08-06 15:07:15 +01:00
Jeremy Ruston
39488f118b Use TwentyTwenties palette by default 2025-08-06 14:39:48 +01:00
Jeremy Ruston
f9721b029e Merge branch 'master' into colour-improvements 2025-08-06 10:30:30 +01:00
Jeremy Ruston
974904588c Switch to minified version of color.js
See this discussion https://github.com/TiddlyWiki/TiddlyWiki5/pull/8702#issuecomment-3158465038
2025-08-06 10:29:04 +01:00
Jeremy Ruston
38457a4667 Add category field to palettes 2025-06-21 15:14:25 +01:00
Jeremy Ruston
96ef5c8314 Move palettes into category folders 2025-06-21 14:53:49 +01:00
Jeremy Ruston
96d24756ea Add new palettes from https://yatagarasu.tiddlyhost.com 2025-06-21 14:41:49 +01:00
Jeremy Ruston
77c99b418f Change default colour space for interpolation 2025-06-21 11:36:34 +01:00
Jeremy Ruston
7f2a47f303 Adopt more ES2017 features 2025-06-20 17:54:28 +01:00
Jeremy Ruston
dcf0f449c4 Adopt class syntax 2025-06-20 17:46:31 +01:00
Jeremy Ruston
a4c84d727c Remove function wrappers 2025-06-20 17:33:28 +01:00
Jeremy Ruston
5335ebf044 Merge branch 'master' into colour-improvements 2025-06-20 17:23:43 +01:00
Jeremy Ruston
e9d87fb551 Merge branch 'master' into colour-improvements 2025-06-19 17:13:53 +01:00
Jeremy Ruston
54382d6666 Merge branch 'master' into colour-improvements 2025-04-16 14:31:47 +01:00
Jeremy Ruston
e86eb28890 Merge branch 'master' into colour-improvements 2025-03-21 17:24:19 +00:00
Jeremy Ruston
5897b82c51 Fix tests 2025-03-07 16:34:09 +00:00
Jeremy Ruston
5e27462acf TwentyTwenties improvements 2025-03-07 16:23:29 +00:00
Jeremy Ruston
4c95ae546f Fix colour-interpolate with missing colours 2025-03-07 16:23:16 +00:00
Jeremy Ruston
d42e3d36bc Add colour-set-alpha operator 2025-03-07 16:23:00 +00:00
Jeremy Ruston
ee977def52 Include palette entry name in palette entries
Makes debugging easier, and works in CSS and as a style.prop assignment
2025-03-07 16:21:51 +00:00
Jeremy Ruston
30016967b1 Preview: Fix sidebar link colour 2025-03-07 16:21:07 +00:00
Jeremy Ruston
250ee90b07 TwentyTwenties: copy over missing palette entries
These are mostly RGB entries that were previously missing, filled in with values from Vanilla.

The goal is still not to have any direct RGB colours in the palette, just computed colours derived from the base colours
2025-03-06 21:53:45 +00:00
Jeremy Ruston
624cf95197 Fix from mismerging from master 2025-03-06 21:44:16 +00:00
Jeremy Ruston
8467fa333d Merge branch 'master' into colour-improvements 2025-03-06 21:38:49 +00:00
Jeremy Ruston
75ba08556f Merge branch 'master' into colour-improvements 2025-02-18 21:15:13 +00:00
Jeremy Ruston
93f954411b Merge branch 'master' into colour-improvements 2025-02-18 16:54:54 +00:00
Jeremy Ruston
059e439702 Merge branch 'master' into colour-improvements 2025-02-14 16:46:02 +00:00
Jeremy Ruston
2028420e3b Fixes suggested by @pmario 2025-02-14 14:11:08 +00:00
Jeremy Ruston
8b05b725aa Merge branch 'master' into colour-improvements 2025-02-14 12:01:14 +00:00
Jeremy Ruston
d7df7eddb1 Introduce tf.colour function to make palette entries more concise 2025-02-13 16:26:22 +00:00
Jeremy Ruston
0037813b39 Background action demos should require explicit enabling 2025-02-13 09:10:30 +00:00
Jeremy Ruston
377856c6a1 Add temporary guide tiddler at the top 2025-02-12 18:43:19 +00:00
Jeremy Ruston
49969a2f1e Docs for apply filter run prefix 2025-02-12 16:41:37 +00:00
Jeremy Ruston
09f8ab9962 Move from v5.3.7 -> v5.4.0 2025-02-12 12:48:35 +00:00
Jeremy Ruston
422b092eb2 Don't need consent banner anymore
Was just for testing
2025-02-12 12:48:02 +00:00
Jeremy Ruston
067a1a22c6 Move sample background item out of the core
It shouldn't be enabled by default, either, but we'll come back to that
2025-02-12 12:47:41 +00:00
Jeremy Ruston
83c6223617 Refactor the interpolate operator so it can be used with the range operator 2025-02-12 10:05:16 +00:00
Jeremy Ruston
611adadaed Add apply filter run prefix
The map filter run prefix is often used as a way to move a computed value in the input list into a variable so that it can be used as a parameter of a filter operator. The apply filter run prefix extends this idea to make the input list available as variables $1, $2 etc. Unlike the map prefix, the apply filter run is only evaluated once.
2025-02-12 10:04:46 +00:00
Jeremy Ruston
28935a5856 Add hue adjuster to colour-interpolate operator 2025-02-11 20:46:11 +00:00
Jeremy Ruston
71a144f6f9 Typo 2025-02-10 17:01:45 +00:00
Jeremy Ruston
92b7819259 Fix Codemirror colour palette fallbacks 2025-02-10 17:01:37 +00:00
Jeremy Ruston
d2204ae72e Fill in some missing palette entries 2025-02-10 13:48:02 +00:00
Jeremy Ruston
7da70ecf6a Add tabs and recent list to the sidebar 2025-02-10 13:47:41 +00:00
Jeremy Ruston
d8dfc10ea8 Typo 2025-02-09 21:54:31 +00:00
Jeremy Ruston
7df987803d Move generic tests into a background palette
These are the generic tests that should be applied to every palette
2025-02-09 21:40:15 +00:00
Jeremy Ruston
4665bab700 AutoToggle should default to light mode so that static exports are light mode 2025-02-09 14:29:12 +00:00
Jeremy Ruston
e87aaff06b Add tabs to the preview 2025-02-06 22:19:10 +00:00
Jeremy Ruston
7c4938293e Refactor the palette preview macros into a generic widget
Takes the opportunity to simplify things now that we don't have to worry about wikified palettes
2025-02-06 21:27:06 +00:00
Jeremy Ruston
eba73eebcb Missed off 961b26a984 2025-02-06 17:28:28 +00:00
Jeremy Ruston
1f4f164d5e Take advantage of compiled palettes
More robust because previously we couldn't cope with indirect palette entries in these situations
2025-02-06 12:55:45 +00:00
Jeremy Ruston
bfea62b43b The tags macros do not actually need access to the palette 2025-02-06 12:53:40 +00:00
Jeremy Ruston
4c216646a4 Introduce background palettes for plugins 2025-02-06 11:53:07 +00:00
Jeremy Ruston
4fe90a6c73 Add VanillaCherry palette 2025-02-06 11:28:24 +00:00
Jeremy Ruston
961b26a984 Get rid of palette-types...
Instead, we'll special case transforming `<<colour X>>` into `[function[colour],[x]]`

Makes everything much easier and avoids all the kerfuffle of not being able to mix palettes
2025-02-06 11:27:04 +00:00
Jeremy Ruston
0d9ab2e2f6 Remove unneeded scheme processing
Now that we're dealing with the schemes during the import process it is no longer necessary for the compilation process to worry about it.
2025-02-05 18:05:57 +00:00
Jeremy Ruston
796c33bc46 Refactor some variable names 2025-02-05 17:11:51 +00:00
Jeremy Ruston
4d06ecd535 Only allow palettes to import palettes of the same type 2025-02-04 21:18:54 +00:00
Jeremy Ruston
f9e4dd8fd3 Rename custom palette editor to custom palette settings
To avoid confusion with existing usage of "palette editor"
2025-02-04 21:08:02 +00:00
Jeremy Ruston
6e4d7aa7f1 Give the AutoToggle palette a custom editor 2025-02-04 21:03:13 +00:00
Jeremy Ruston
998d5c8d8f The lingo macro shouldn't mess with currentTiddler 2025-02-04 21:02:47 +00:00
Jeremy Ruston
38865a40ad Palette should autocompile when the palette tiddler itself changes 2025-02-04 20:00:17 +00:00
Jeremy Ruston
a5c4d90154 Refactor palette switcher a little 2025-02-04 19:59:39 +00:00
Jeremy Ruston
2e5a988bb3 Clarify comment 2025-02-04 16:44:07 +00:00
Jeremy Ruston
0ee2f286aa Set colour scheme property of root element 2025-02-04 16:40:48 +00:00
Jeremy Ruston
30a7d61e56 Easier for development if the prerelease uses the tw5.com palette 2025-02-04 16:26:46 +00:00
Jeremy Ruston
c7f9dbfc29 Compile colour scheme handling 2025-02-04 16:26:15 +00:00
Jeremy Ruston
c6bb2b51e6 Rethink palette manager
The current content of $:/PaletteManager is moved into $:/PaletteEditor, and $:/PaletteManager repurposed as the control panel palette switcher
2025-02-04 16:11:51 +00:00
Jeremy Ruston
a053f03818 Remove logging 2025-02-04 16:10:38 +00:00
Jeremy Ruston
6970ac24bf Typo 2025-02-03 18:44:58 +00:00
Jeremy Ruston
431149d20c Introduce dynamic colour scheme mechanism
Also introduces palette inheritance

This finally allows us to have a palette that automatically switches between dark and light variants. The mechanism is more flexible that that, and allows for multiple colour schemes (night, morning, day, evening, for example) with automatic switching between them.
2025-02-03 13:26:25 +00:00
Jeremy Ruston
a366d62358 Include tiddler borders in preview
Several of the core palettes have distinctive borders
2025-01-31 17:06:55 +00:00
Jeremy Ruston
a6a91d49b7 Restore accidentally deleted field 2025-01-30 18:35:58 +00:00
Jeremy Ruston
22cf3b25bd Remove infinite loop that was added for testing 2025-01-28 21:40:34 +00:00
Jeremy Ruston
139b61fff1 Proper recursion detection for palettes 2025-01-28 19:18:58 +00:00
Jeremy Ruston
c1fd82f50f Minor cleanups 2025-01-28 15:44:42 +00:00
Jeremy Ruston
effeed7ade Remove extraneous logging 2025-01-27 21:47:03 +00:00
Jeremy Ruston
546e438943 Allow background actions to be scoped by platform 2025-01-27 21:45:17 +00:00
Jeremy Ruston
efcd23993e Merge branch 'master' into colour-improvements 2025-01-27 16:55:03 +00:00
Jeremy Ruston
0c8aad49f9 Replace accumulate-palette-entries with new changecount filter
Much more direct and efficient
2025-01-27 11:09:18 +00:00
Jeremy Ruston
317e1245c8 Introduce an improved but temporary cache invalidation method for palettes 2025-01-26 17:54:47 +00:00
Jeremy Ruston
d2bbc56c78 Move modern palettes to correct directory 2025-01-25 17:28:06 +00:00
Jeremy Ruston
8957424e55 Start adding tests for palette operations 2025-01-25 17:28:00 +00:00
Jeremy Ruston
0fd5b04b9a Merge branch 'master' into colour-improvements 2025-01-25 11:05:21 +00:00
Jeremy Ruston
3ea7cd3bf7 Palette editors no longer need to manually recompile the palette 2025-01-25 11:05:13 +00:00
Jeremy Ruston
7513e4426c Allow text editor type=color for colours not in hex RGB format
See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color#value
2025-01-25 11:03:53 +00:00
Jeremy Ruston
0dfde0660a Detect darkmode at startup 2025-01-24 18:34:55 +00:00
Jeremy Ruston
8c619fd86e Compile palette at startup 2025-01-24 18:32:00 +00:00
Jeremy Ruston
407e58f837 Add a basic dark palette
Obviously some things are hardcoded at the moment
2025-01-24 11:17:55 +00:00
Jeremy Ruston
9588b7f1a3 Autocompile palettes when they change 2025-01-24 11:16:31 +00:00
Jeremy Ruston
28c1e77b60 Make sure rootwidget is available before background actions start 2025-01-24 11:15:27 +00:00
Jeremy Ruston
0baf395030 Merge background actions and media tracker from #8555
The changes in #8555 are needed in order to be able to offer the desired user experience for dark mode changes.
2025-01-23 18:16:10 +00:00
Jeremy Ruston
9681b0deda Merge branch 'master' into colour-improvements 2025-01-23 18:15:44 +00:00
Jeremy Ruston
62fb916a68 Merge branch 'master' into colour-improvements 2025-01-23 14:37:23 +00:00
Jeremy Ruston
3614236cfc Paldette and style tweaks 2025-01-21 16:36:00 +00:00
Jeremy Ruston
c75f50e99a Fix palette switcher used in the sidebar
by adding a new "thumbnails" parameter to the template
2025-01-09 14:51:48 +00:00
Jeremy Ruston
55d9e92032 Edit text widget shouldn't fully refresh when default attribute changes 2025-01-09 10:51:02 +00:00
Jeremy Ruston
2edcf0f46b Refactor TwentyTwenties editor 2025-01-09 10:50:37 +00:00
Jeremy Ruston
69363bf7ef Palette manager should recompile palette on edits 2025-01-08 21:38:08 +00:00
Jeremy Ruston
2b0c634fb8 Refactor actions for recompiling current palette 2025-01-08 21:37:44 +00:00
Jeremy Ruston
28167adc22 Add a palette that automatically switches between dark and light
Will requires #7999 to work fully; for the moment when you switch between dark and light you will see the preview change, and then next time you select the palette it will be in the correct mode
2025-01-08 16:02:05 +00:00
Jeremy Ruston
bd4b3e4107 Fix some old-style palette references 2025-01-08 16:00:29 +00:00
Jeremy Ruston
2cbd1080fa Fix more TwentyTwenties entries 2025-01-08 15:57:39 +00:00
Jeremy Ruston
a4293068bf Clarify method name 2025-01-08 14:49:19 +00:00
Jeremy Ruston
d1ce54806f Download button should use palette colours 2025-01-08 10:06:56 +00:00
Jeremy Ruston
6b39d6aa43 Fix editing colours that are not in 6 digit hex format
See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color#value
2025-01-08 09:59:04 +00:00
Jeremy Ruston
5d1cf251b9 Add best contrast operator 2025-01-07 17:40:23 +00:00
Jeremy Ruston
c02c82557b Add a primitive custom palette editor 2025-01-02 17:10:51 +00:00
Jeremy Ruston
b90b449ceb Use interpolation to derive colours 2025-01-02 17:10:29 +00:00
Jeremy Ruston
6a06df79c4 Fix palette switcher 2024-12-27 12:00:50 +00:00
Jeremy Ruston
2558dc0b10 TwentyTwenties palette: use interpolation 2024-12-22 19:20:05 +00:00
Jeremy Ruston
2eee3bfcd6 Merge branch 'master' into colour-improvements 2024-12-21 09:48:10 +00:00
Jeremy Ruston
2685fa7c4e Improvements to TwentyTwenties palettes
Still a work in progress, but getting more coherent
2024-12-15 18:55:17 +00:00
Jeremy Ruston
3c44532551 Barebones docs for colour spaces 2024-12-15 18:49:04 +00:00
Jeremy Ruston
2640406f5b Include contrast value in contrast errors 2024-12-15 18:48:48 +00:00
Jeremy Ruston
c1e36a1e5f Add colour-interpolate operator 2024-12-15 18:48:28 +00:00
Jeremy Ruston
ae1d9f5b86 Add colour-get-oklch operator 2024-12-15 13:04:33 +00:00
Jeremy Ruston
1df0ac486b Refactor colour-oklch operator to colour-set-oklch 2024-12-15 11:56:49 +00:00
Jeremy Ruston
b1fcb18d9e Refactor for clearer variable names 2024-12-15 11:49:23 +00:00
Jeremy Ruston
5a6eea7fa2 Make the alert and notification previews be optional
Via some future UI
2024-12-14 17:33:02 +00:00
Jeremy Ruston
6fe16bc71a Fix colour for site title 2024-12-14 17:32:43 +00:00
Jeremy Ruston
6a66c49261 Merge branch 'master' into colour-improvements 2024-12-14 17:12:51 +00:00
Jeremy Ruston
fc695e7a50 Merge branch 'master' into colour-improvements 2024-12-05 17:38:50 +00:00
Jeremy Ruston
9efcad9360 Display test results at the bottom of the palette switcher 2024-11-19 09:09:11 +00:00
Jeremy Ruston
cd5bbcda8d Add contrast checks to TwentyTwenties palette
I think I might be building a programming language for writing palettes...
2024-11-18 18:15:53 +00:00
Jeremy Ruston
aa69c3ae91 Add colour-contrast operator 2024-11-18 18:15:20 +00:00
Jeremy Ruston
76f2decf8b Start fixing the TwentyTwenties palettes 2024-11-18 16:40:49 +00:00
Jeremy Ruston
84bef54802 Docs for colour-oklch operator 2024-11-18 16:38:54 +00:00
Jeremy Ruston
3507b0f952 Fix filtered palette previews 2024-11-17 16:11:10 +00:00
Jeremy Ruston
b0828cc099 Add notification preview 2024-11-17 16:10:57 +00:00
Jeremy Ruston
32ac67166a Add alert preview 2024-11-17 14:45:52 +00:00
Jeremy Ruston
b2d0c22d75 Componentise more preview components 2024-11-17 14:45:41 +00:00
Jeremy Ruston
cfabc92945 Update contrastcolour macro to use color.js 2024-11-16 14:37:14 +00:00
Jeremy Ruston
809465b6e2 Merge branch 'master' into colour-improvements 2024-11-16 14:22:19 +00:00
Jeremy Ruston
8b59b6166e Palette tweaks
These filtered palettes are still just experiments with the techniques, and not yet a serious palette
2024-11-14 17:45:10 +00:00
Jeremy Ruston
3faf9bae5c Fix previews of filtered palettes 2024-11-14 17:40:58 +00:00
Jeremy Ruston
c2ee0727a5 Merge branch 'master' into colour-improvements 2024-11-12 20:57:46 +00:00
Jeremy Ruston
7de5f40884 Merge branch 'master' into colour-improvements 2024-11-12 20:37:01 +00:00
Jeremy Ruston
21cd3b86ad Merge branch 'master' into colour-improvements 2024-11-12 19:51:52 +00:00
Jeremy Ruston
ad1b0fdddd Palette tweaks 2024-11-12 19:26:20 +00:00
Jeremy Ruston
1db8cf7fe5 Merge branch 'master' into colour-improvements 2024-11-12 19:18:54 +00:00
Jeremy Ruston
46da1619af Add aria labels to palette switcher
Co-authored-by: Mario Pietsch <pmariojo@gmail.com>
2024-11-11 15:52:55 +00:00
Jeremy Ruston
bad9517153 Another fix for filtered palette previews 2024-11-10 16:52:49 +00:00
Jeremy Ruston
38d5daaf12 Improve chooser chosen item highlight 2024-11-10 16:52:23 +00:00
Jeremy Ruston
297ae7eccb Fix preview of filtered palettes 2024-11-10 09:52:43 +00:00
Jeremy Ruston
b54d56ec47 Support for imported palettes
Also consolidate the palette entries into a temporary palette before compiling them

Note that imported palettes is not currently recursive
2024-11-09 19:03:54 +00:00
Jeremy Ruston
4e2f2bebd0 Avoid redefining the colour function by adding a configuration variable 2024-11-09 17:02:00 +00:00
Jeremy Ruston
f88915728f Introduce new static palette architecture 2024-11-09 16:15:33 +00:00
Jeremy Ruston
1be89a28bf Make preview templates tag driven and extensible 2024-11-08 09:12:48 +00:00
Jeremy Ruston
250e57cd79 Remove wikify operator and refactor palette preview
The implementation of the palette preview is much less elegant like this, but it does work
2024-11-07 18:30:39 +00:00
Jeremy Ruston
a4d930322e Testing CI 2024-11-06 08:32:42 +00:00
Jeremy Ruston
c3ce9cafb7 Testing Netlify CI 2024-11-06 08:22:42 +00:00
Jeremy Ruston
348f7177a7 Remove logging 2024-11-05 22:42:46 +00:00
Jeremy Ruston
c6074402bb Restore default styling for chosen chooser item
See https://github.com/TiddlyWiki/TiddlyWiki5/pull/8702#discussion_r1816584692
2024-11-05 10:24:01 +00:00
Jeremy Ruston
23eccd1df6 Merge branch 'master' into colour-improvements 2024-11-04 19:26:16 +00:00
Jeremy Ruston
ff5c846130 Indentation for palette switcher 2024-11-04 18:12:00 +00:00
Jeremy Ruston
81b7bb4124 Merge branch 'master' into colour-improvements 2024-11-04 10:39:28 +00:00
Jeremy Ruston
a8fb07137d Add expertimental colour-oklch operator 2024-11-03 16:13:09 +00:00
Jeremy Ruston
85fa913b1c Merge branch 'master' into colour-improvements 2024-11-03 16:10:47 +00:00
Jeremy Ruston
bc0fde6853 Fix palette chooser when displayed in "Tools" dropdown 2024-10-31 18:03:50 +00:00
Jeremy Ruston
4f2754d16c Merge branch 'master' into colour-improvements 2024-10-31 17:46:30 +00:00
Jeremy Ruston
4445111a08 Merge branch 'master' into colour-improvements 2024-10-30 20:38:58 +00:00
Jeremy Ruston
151f61adc0 Palette chooser styling tweaks 2024-10-25 11:03:21 +01:00
Jeremy Ruston
fc369415e4 Improve colour palette switcher with previews 2024-10-25 09:28:33 +01:00
Jeremy Ruston
b5a22e3e9e Remove obsolete comment 2024-10-25 09:28:17 +01:00
Jeremy Ruston
d372729ed0 Add colour-lighten and colour-darken operators 2024-10-24 12:01:50 +01:00
Jeremy Ruston
96b85edfa2 Fix up the tests 2024-10-24 10:46:48 +01:00
Jeremy Ruston
4af573aaf9 Fix nested colour definitions 2024-10-23 09:39:18 +01:00
Jeremy Ruston
1e5c69eb99 Fix typo 2024-10-23 08:25:24 +01:00
Jeremy Ruston
e1e73d2aa0 Merge branch 'master' into colour-improvements 2024-10-23 08:22:01 +01:00
Jeremy Ruston
a23ee165d8 Rewrite colour macro as a function
Using the new wikify operator.

Currently has a bug whereby redirected colours (like "tiddler-background") do not work. Direct colours like "background" do work.

Note the hacks needed to makeFakeWidgetWithVariables work
2024-10-22 17:26:04 +01:00
Jeremy Ruston
467a1a47cc Introduce wikify operator
Really just syntactic sugar for the wikify widget
2024-10-22 17:24:51 +01:00
Jeremy Ruston
93d1c05ca7 Include colour.js license and mark version number 2024-10-21 17:25:56 +01:00
Jeremy Ruston
fb9c0d6a5a Replace 12 year old CSS colour parsing library
The replacement library from https://colorjs.io/ is much, much larger but I think we can develop a custom build that uses treeshaking to whittle the code down to the bits that we need. @linonetwo does that sound feasible?

I intend the explore further improvements but I wanted to start by establishing a library that can do modern P3 and OKLCH colour calculations.
2024-10-21 09:03:39 +01:00
666 changed files with 10688 additions and 8192 deletions

View File

@@ -120,6 +120,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|| exit 1
# /empty.html Empty
# /empty.hta For Internet Explorer
# /empty-external-core.html External core empty
# /tiddlywikicore-<version>.js Core plugin javascript
node $TW5_BUILD_TIDDLYWIKI \

View File

@@ -15,40 +15,40 @@ var fs = require("fs"),
{ optimize } = require("svgo"),
config = {
plugins: [
"cleanupAttrs",
"removeDoctype",
"removeXMLProcInst",
"removeComments",
"removeMetadata",
"removeTitle",
"removeDesc",
"removeUselessDefs",
"removeEditorsNSData",
"removeEmptyAttrs",
"removeHiddenElems",
"removeEmptyText",
"removeEmptyContainers",
'cleanupAttrs',
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeTitle',
'removeDesc',
'removeUselessDefs',
'removeEditorsNSData',
'removeEmptyAttrs',
'removeHiddenElems',
'removeEmptyText',
'removeEmptyContainers',
// 'removeViewBox',
"cleanupEnableBackground",
"convertStyleToAttrs",
"convertColors",
"convertPathData",
"convertTransform",
"removeUnknownsAndDefaults",
"removeNonInheritableGroupAttrs",
"removeUselessStrokeAndFill",
"removeUnusedNS",
"cleanupIDs",
"cleanupNumericValues",
"moveElemsAttrsToGroup",
"moveGroupAttrsToElems",
"collapseGroups",
'cleanupEnableBackground',
'convertStyleToAttrs',
'convertColors',
'convertPathData',
'convertTransform',
'removeUnknownsAndDefaults',
'removeNonInheritableGroupAttrs',
'removeUselessStrokeAndFill',
'removeUnusedNS',
'cleanupIDs',
'cleanupNumericValues',
'moveElemsAttrsToGroup',
'moveGroupAttrsToElems',
'collapseGroups',
// 'removeRasterImages',
"mergePaths",
"convertShapeToPath",
"sortAttrs",
'mergePaths',
'convertShapeToPath',
'sortAttrs',
//'removeDimensions',
{name: "removeAttrs", params: { attrs: "(stroke|fill)" } }
{name: 'removeAttrs', params: { attrs: '(stroke|fill)' } }
]
};
@@ -72,7 +72,7 @@ files.forEach(function(filename) {
var newSVG = header.join("\n") + "\n\n" + result.data.replace("&lt;&lt;now &quot;DD&quot;&gt;&gt;","<<now \"DD\">>");
fs.writeFileSync(filepath,newSVG);
} else {
console.log("Error " + err + " with " + filename);
console.log("Error " + err + " with " + filename)
process.exit();
};
}

View File

@@ -12,6 +12,8 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
var _boot = (function($tw) {
/*jslint node: true, browser: true */
/*global modules: false, $tw: false */
"use strict";
// Include bootprefix if we're not given module data
@@ -35,7 +37,7 @@ if($tw.node) {
$tw.boot.log = function(str) {
$tw.boot.logMessages = $tw.boot.logMessages || [];
$tw.boot.logMessages.push(str);
};
}
/*
Check if an object has a property
@@ -45,7 +47,7 @@ $tw.utils.hop = function(object,property) {
};
/** @deprecated Use Array.isArray instead */
$tw.utils.isArray = (value) => Array.isArray(value);
$tw.utils.isArray = value => Array.isArray(value);
/*
Check if an array is equal by value and by reference.
@@ -125,7 +127,7 @@ $tw.utils.pushTop = function(array,value) {
};
/** @deprecated Use instanceof Date instead */
$tw.utils.isDate = (value) => value instanceof Date;
$tw.utils.isDate = value => value instanceof Date;
/** @deprecated Use array iterative methods instead */
$tw.utils.each = function(object,callback) {
@@ -136,7 +138,7 @@ $tw.utils.each = function(object,callback) {
return next !== false;
});
} else {
Object.entries(object).every((entry) => {
Object.entries(object).every(entry => {
const next = callback(entry[1], entry[0], object);
return next !== false;
});
@@ -314,25 +316,8 @@ $tw.utils.htmlDecode = function(s) {
return s.toString().replace(/&lt;/mg,"<").replace(/&nbsp;/mg,"\xA0").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&");
};
/*
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
*/
$tw.utils.getLocationHash = function() {
const href = window.location.href,
idx = href.indexOf("#");
if(idx === -1) {
return "#";
}
const afterHash = href.substring(idx + 1);
if(afterHash.startsWith("#") || afterHash.startsWith("%23")) {
// Special case: ignore location hash if it itself starts with a #
return "#";
}
return href.substring(idx);
};
/** @deprecated Use window.location.hash instead. */
$tw.utils.getLocationHash = () => window.location.hash;
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
$tw.utils.pad = function(value,length = 2) {
@@ -563,7 +548,7 @@ using a lowercase extension only.
*/
$tw.utils.getFileExtensionInfo = function(ext) {
return ext ? $tw.config.fileExtensionInfo[ext.toLowerCase()] : null;
};
}
/*
Given an extension, get the correct encoding for that file.
@@ -586,7 +571,7 @@ var globalCheck =[
" delete Object.prototype.__temp__;",
" }",
" delete Object.prototype.__temp__;",
].join("\n");
].join('\n');
/*
Run code globally with specified context variables in scope
@@ -611,10 +596,10 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
// Compile the code into a function
var fn;
if($tw.browser) {
fn = Function("return " + code + "\n\n//# sourceURL=" + filename)(); // See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
fn = window["eval"](code + "\n\n//# sourceURL=" + filename); // eslint-disable-line no-eval -- See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
} else {
if(sandbox){
fn = vm.runInContext(code,sandbox,filename);
fn = vm.runInContext(code,sandbox,filename)
} else {
fn = vm.runInThisContext(code,filename);
}
@@ -725,7 +710,7 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
var self = this;
form.addEventListener("submit",function(event) {
// Collect the form data
var data = {};
var data = {},t;
$tw.utils.each(form.elements,function(element) {
if(element.name && element.value) {
data[element.name] = element.value;
@@ -771,7 +756,7 @@ $tw.utils.PasswordPrompt.prototype.removePrompt = function(promptInfo) {
promptInfo.form.parentNode.removeChild(promptInfo.form);
this.setWrapperDisplay();
}
};
}
/*
Crypto helper object for encrypted content. It maintains the password text in a closure, and provides methods to change
@@ -810,7 +795,7 @@ $tw.utils.Crypto = function() {
};
this.hasPassword = 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"});
@@ -828,7 +813,7 @@ Execute the module named 'moduleName'. The name can optionally be relative to th
$tw.modules.execute = function(moduleName,moduleRoot) {
var name = moduleName;
if(moduleName.charAt(0) === ".") {
name = $tw.utils.resolvePath(moduleName,moduleRoot);
name = $tw.utils.resolvePath(moduleName,moduleRoot)
}
if(!$tw.modules.titles[name]) {
if($tw.modules.titles[name + ".js"]) {
@@ -889,6 +874,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
if(!moduleInfo) {
// We could not find the module on this path
// Try to defer to browserify etc, or node
var deferredModule;
if($tw.browser) {
if(window.require) {
try {
@@ -1143,7 +1129,8 @@ enableIndexers - Array of indexer names to enable, or null to use all available
*/
$tw.Wiki = function(options) {
options = options || {};
var tiddlers = Object.create(null), // Hashmap of tiddlers
var self = this,
tiddlers = Object.create(null), // Hashmap of tiddlers
tiddlerTitles = null, // Array of tiddler titles
getTiddlerTitles = function() {
if(!tiddlerTitles) {
@@ -1197,7 +1184,7 @@ $tw.Wiki = function(options) {
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
};
}
// Save the new tiddler
tiddlers[title] = tiddler;
// Check we've got the title
@@ -1207,7 +1194,7 @@ $tw.Wiki = function(options) {
tiddler: tiddler,
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
};
}
// Update indexes
this.clearCache(title);
this.clearGlobalCache();
@@ -1232,7 +1219,7 @@ $tw.Wiki = function(options) {
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
};
}
// Delete the tiddler
delete tiddlers[title];
// Delete it from the list of titles
@@ -1247,7 +1234,7 @@ $tw.Wiki = function(options) {
tiddler: this.getTiddler(title),
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
};
}
// Update indexes
this.clearCache(title);
this.clearGlobalCache();
@@ -1435,7 +1422,8 @@ $tw.Wiki = function(options) {
// Unregister the plugin tiddlers of a particular type, or null/undefined for any type, optionally restricting unregistering to an array of tiddler titles. Returns an array of the titles affected
this.unregisterPluginTiddlers = function(pluginType,titles) {
var unregisteredTitles = [];
var self = this,
unregisteredTitles = [];
// Remove any previous registered plugins of this type
for(var t=pluginTiddlers.length-1; t>=0; t--) {
var tiddler = pluginTiddlers[t];
@@ -1449,15 +1437,16 @@ $tw.Wiki = function(options) {
// Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
this.unpackPluginTiddlers = function() {
var self = this;
// Sort the plugin titles by the `plugin-priority` field, if this field is missing, default to 1
pluginTiddlers.sort(function(a, b) {
var priorityA = "plugin-priority" in a.fields ? a.fields["plugin-priority"] : 1;
var priorityB = "plugin-priority" in b.fields ? b.fields["plugin-priority"] : 1;
if(priorityA !== priorityB) {
if (priorityA !== priorityB) {
return priorityA - priorityB;
} else if(a.fields.title < b.fields.title) {
} else if (a.fields.title < b.fields.title) {
return -1;
} else if(a.fields.title === b.fields.title) {
} else if (a.fields.title === b.fields.title) {
return 0;
} else {
return +1;
@@ -1564,7 +1553,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
// Assemble a report tiddler
var titleReportTiddler = "TiddlyWiki Safe Mode",
report = [];
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:");
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:")
// Delete the overrides
overrides.forEach(function(title) {
var tiddler = self.getTiddler(title),
@@ -1573,7 +1562,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
report.push("* [[" + title + "|" + newTitle + "]]");
});
report.push();
report.push()
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
// Set $:/DefaultTiddlers to point to our report
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
@@ -2007,7 +1996,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
value = $tw.utils.stringifyList(path.relative(rootPath, filename).split(path.sep).slice(0, -1));
break;
case "filepath":
value = path.relative(rootPath, filename).split(path.sep).join("/");
value = path.relative(rootPath, filename).split(path.sep).join('/');
break;
case "filename":
value = path.basename(filename);
@@ -2060,7 +2049,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
}
});
return arrayOfFiles;
};
}
// Process the listed tiddlers
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
if(tidInfo.prefix && tidInfo.suffix) {
@@ -2169,7 +2158,7 @@ Returns the path of the plugin folder
$tw.findLibraryItem = function(name,paths) {
var pathIndex = 0;
do {
var pluginPath = path.resolve(paths[pathIndex],"./" + name);
var pluginPath = path.resolve(paths[pathIndex],"./" + name)
if(fs.existsSync(pluginPath) && fs.statSync(pluginPath).isDirectory()) {
return pluginPath;
}
@@ -2528,7 +2517,7 @@ $tw.boot.initStartup = function(options) {
}
});
return result;
};
}
}
};
$tw.boot.loadStartup = function(options){
@@ -2545,7 +2534,7 @@ $tw.boot.loadStartup = function(options){
}
// Give hooks a chance to modify the store
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
};
}
$tw.boot.execStartup = function(options){
// Unpack plugin tiddlers
$tw.wiki.readPluginInfo();
@@ -2575,7 +2564,7 @@ $tw.boot.execStartup = function(options){
$tw.boot.disabledStartupModules = $tw.boot.disabledStartupModules || [];
// Repeatedly execute the next eligible task
$tw.boot.executeNextStartupTask(options.callback);
};
}
/*
Startup TiddlyWiki
*/
@@ -2594,7 +2583,7 @@ $tw.addUnloadTask = function(task) {
if($tw.unloadTasks.indexOf(task) === -1) {
$tw.unloadTasks.push(task);
}
};
}
/*
Execute the remaining eligible startup tasks
@@ -2641,7 +2630,7 @@ $tw.boot.executeNextStartupTask = function(callback) {
}
taskIndex++;
}
if(typeof callback === "function") {
if(typeof callback === 'function') {
callback();
}
return false;

View File

@@ -103,7 +103,7 @@ Commander.prototype.executeNextCommand = function() {
c = new command.Command(params,this);
err = c.execute();
if(err && typeof err.then === "function") {
err.then((e) => { e ? this.callback(e) : this.executeNextCommand(); });
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
} else if(err) {
this.callback(err);
} else {
@@ -120,7 +120,7 @@ Commander.prototype.executeNextCommand = function() {
});
err = c.execute();
if(err && typeof err.then === "function") {
err.then((e) => { if(e) this.callback(e); });
err.then(e => { if(e) this.callback(e); });
} else if(err) {
this.callback(err);
}

View File

@@ -25,7 +25,7 @@ Command.prototype.execute = function() {
if(!filter) {
return "No filter specified";
}
var commands = this.commander.wiki.filterTiddlers(filter);
var commands = this.commander.wiki.filterTiddlers(filter)
if(commands.length === 0) {
return "No tiddlers found for filter '" + filter + "'";
}

View File

@@ -24,7 +24,8 @@ Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filter";
}
var wiki = this.commander.wiki,
var self = this,
wiki = this.commander.wiki,
filter = this.params[0],
tiddlers = wiki.filterTiddlers(filter);
$tw.utils.each(tiddlers,function(title) {

View File

@@ -66,7 +66,7 @@ Command.prototype.fetchFiles = function(options) {
// Get the list of URLs
var urls;
if(options.url) {
urls = [options.url];
urls = [options.url]
} else if(options.urlFilter) {
urls = this.commander.wiki.filterTiddlers(options.urlFilter);
} else {
@@ -96,30 +96,30 @@ Command.prototype.fetchFile = function(url,options,callback,redirectCount) {
var self = this,
lib = url.substr(0,8) === "https://" ? require("https") : require("http");
lib.get(url).on("response",function(response) {
var type = (response.headers["content-type"] || "").split(";")[0],
data = [];
self.commander.write("Reading " + url + ": ");
response.on("data",function(chunk) {
data.push(chunk);
self.commander.write(".");
});
response.on("end",function() {
self.commander.write("\n");
if(response.statusCode === 200) {
self.processBody(Buffer.concat(data),type,options,url);
callback(null);
} else {
if(response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
return self.fetchFile(response.headers.location,options,callback,redirectCount + 1);
} else {
return callback("Error " + response.statusCode + " retrieving " + url);
}
}
});
response.on("error",function(e) {
var type = (response.headers["content-type"] || "").split(";")[0],
data = [];
self.commander.write("Reading " + url + ": ");
response.on("data",function(chunk) {
data.push(chunk);
self.commander.write(".");
});
response.on("end",function() {
self.commander.write("\n");
if(response.statusCode === 200) {
self.processBody(Buffer.concat(data),type,options,url);
callback(null);
} else {
if(response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
return self.fetchFile(response.headers.location,options,callback,redirectCount + 1);
} else {
return callback("Error " + response.statusCode + " retrieving " + url)
}
}
});
response.on("error",function(e) {
console.log("Error on GET request: " + e);
callback(e);
});
});
});
return null;
};
@@ -153,18 +153,18 @@ Command.prototype.processBody = function(body,type,options,url) {
if(options.transformFilter) {
var transformedTitle = (incomingWiki.filterTiddlers(options.transformFilter,null,self.commander.wiki.makeTiddlerIterator([title])) || [""])[0];
if(transformedTitle) {
self.commander.log("Importing " + title + " as " + transformedTitle);
self.commander.log("Importing " + title + " as " + transformedTitle)
newTiddler = new $tw.Tiddler(tiddler,{title: transformedTitle});
}
} else {
self.commander.log("Importing " + title);
self.commander.log("Importing " + title)
newTiddler = tiddler;
}
self.commander.wiki.importTiddler(newTiddler);
count++;
}
});
self.commander.log("Imported " + count + " tiddlers");
self.commander.log("Imported " + count + " tiddlers")
};
exports.Command = Command;

View File

@@ -22,7 +22,8 @@ var Command = function(params,commander,callback) {
Command.prototype.execute = function() {
var self = this,
fs = require("fs");
fs = require("fs"),
path = require("path");
if(this.params.length < 2) {
return "Missing parameters";
}

View File

@@ -20,7 +20,8 @@ var Command = function(params,commander) {
};
Command.prototype.execute = function() {
var fs = require("fs");
var fs = require("fs"),
path = require("path");
// Check that we don't already have a valid wiki folder
if($tw.boot.wikiTiddlersPath || ($tw.utils.isDirectory($tw.boot.wikiPath) && !$tw.utils.isDirectoryEmpty($tw.boot.wikiPath))) {
return "Wiki folder is not empty";

View File

@@ -19,6 +19,7 @@ exports.info = {
};
var Command = function(params,commander,callback) {
var self = this;
this.params = params;
this.commander = commander;
this.callback = callback;

View File

@@ -21,7 +21,9 @@ var Command = function(params,commander,callback) {
};
Command.prototype.execute = function() {
var self = this;
var self = this,
fs = require("fs"),
path = require("path");
if(this.params.length < 1) {
return "Missing filename";
}

View File

@@ -21,7 +21,8 @@ var Command = function(params,commander,callback) {
};
Command.prototype.execute = function() {
var path = require("path");
var fs = require("fs"),
path = require("path");
if(this.params.length < 1) {
return "Missing output path";
}

View File

@@ -7,57 +7,59 @@ Render individual tiddlers and save the results to the specified files
\*/
"use strict";
"use strict";
exports.info = {
name: "render",
synchronous: true
};
var widget = require("$:/core/modules/widgets/widget.js");
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
exports.info = {
name: "render",
synchronous: true
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing tiddler filter";
}
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
type = this.params[2] || "text/html",
template = this.params[3],
variableList = this.params.slice(4),
tiddlers = wiki.filterTiddlers(tiddlerFilter),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.utils.each(tiddlers,function(title) {
var filenameResults = wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]));
if(filenameResults.length > 0) {
var filepath = path.resolve(self.commander.outputPath,filenameResults[0]);
if(self.commander.verbose) {
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
}
var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent;
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,text,"utf8");
} else {
console.log("Not rendering \"" + title + "\" because the filename filter returned an empty result");
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing tiddler filter";
}
});
return null;
};
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
type = this.params[2] || "text/html",
template = this.params[3],
variableList = this.params.slice(4),
tiddlers = wiki.filterTiddlers(tiddlerFilter),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.utils.each(tiddlers,function(title) {
var filenameResults = wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]));
if(filenameResults.length > 0) {
var filepath = path.resolve(self.commander.outputPath,filenameResults[0]);
if(self.commander.verbose) {
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
}
var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent;
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,text,"utf8");
} else {
console.log("Not rendering \"" + title + "\" because the filename filter returned an empty result");
}
});
return null;
};
exports.Command = Command;
exports.Command = Command;

View File

@@ -9,6 +9,8 @@ Command to render several tiddlers to a folder of files
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "rendertiddlers",
synchronous: true

View File

@@ -7,56 +7,57 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
\*/
"use strict";
"use strict";
exports.info = {
name: "save",
synchronous: true
};
exports.info = {
name: "save",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
var self = this,
path = require("path"),
result = null,
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]]",
tiddlers = wiki.filterTiddlers(tiddlerFilter);
$tw.utils.each(tiddlers,function(title) {
if(!result) {
var tiddler = self.commander.wiki.getTiddler(title);
if(tiddler) {
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
directory: path.resolve(self.commander.outputPath),
pathFilters: [filenameFilter],
wiki: wiki,
fileInfo: {
overwrite: true
}
});
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
}
try {
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
} catch (err) {
result = "Error saving tiddler \"" + title + "\", to file: \"" + fileInfo.filepath + "\"";
}
} else {
result = "Tiddler '" + title + "' not found";
}
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
});
return result;
};
var self = this,
fs = require("fs"),
path = require("path"),
result = null,
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]]",
tiddlers = wiki.filterTiddlers(tiddlerFilter);
$tw.utils.each(tiddlers,function(title) {
if(!result) {
var tiddler = self.commander.wiki.getTiddler(title);
if(tiddler) {
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
directory: path.resolve(self.commander.outputPath),
pathFilters: [filenameFilter],
wiki: wiki,
fileInfo: {
overwrite: true
}
});
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
}
try {
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
} catch (err) {
result = "Error saving tiddler \"" + title + "\", to file: \"" + fileInfo.filepath + "\"";
}
} else {
result = "Tiddler '" + title + "' not found";
}
}
});
return result;
};
exports.Command = Command;
exports.Command = Command;

View File

@@ -9,6 +9,8 @@ Command to save several tiddlers to a folder of files
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "savetiddlers",
synchronous: true

View File

@@ -43,7 +43,7 @@ Command.prototype.execute = function() {
namedParames,
tiddlerFilter,
options = {};
if(regFilter.test(this.params[1])) {
if (regFilter.test(this.params[1])) {
namedParames = this.commander.extractNamedParameters(this.params.slice(1));
tiddlerFilter = namedParames.filter || "[all[tiddlers]]";
} else {
@@ -177,13 +177,13 @@ WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
$tw.utils.each(pluginTiddlers,function(tiddler,title) {
if(!tiddler.title) {
tiddler.title = title;
}
}
self.saveTiddler(directory,new $tw.Tiddler(tiddler));
});
};
WikiFolderMaker.prototype.saveTiddler = function(directory,tiddler) {
var fileInfo, pathFilters, extFilters;
var title = tiddler.fields.title, fileInfo, pathFilters, extFilters;
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")) {
pathFilters = this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n");
}

View File

@@ -17,6 +17,7 @@ exports.info = {
};
var Command = function(params,commander,callback) {
var self = this;
this.params = params;
this.commander = commander;
this.callback = callback;

View File

@@ -9,6 +9,8 @@ Command to modify selected tiddlers to set a field to the text of a template tid
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "setfield",
synchronous: true
@@ -24,7 +26,8 @@ Command.prototype.execute = function() {
if(this.params.length < 4) {
return "Missing parameters";
}
var wiki = this.commander.wiki,
var self = this,
wiki = this.commander.wiki,
filter = this.params[0],
fieldname = this.params[1] || "text",
templatetitle = this.params[2],

View File

@@ -26,7 +26,7 @@ exports.getSubdirectories = function(dirPath) {
}
});
return subdirs;
};
}
/*
Recursively (and synchronously) copy a directory and all its content
@@ -46,7 +46,8 @@ exports.copyDirectory = function(srcPath,dstPath) {
}
// Function to copy a folder full of files
var copy = function(srcPath,dstPath) {
var srcStats = fs.lstatSync(srcPath);
var srcStats = fs.lstatSync(srcPath),
dstExists = fs.existsSync(dstPath);
if(srcStats.isFile()) {
$tw.utils.copyFile(srcPath,dstPath);
} else if(srcStats.isDirectory()) {
@@ -82,7 +83,7 @@ exports.copyFile = function(srcPath,dstPath) {
dstFile = fs.openSync(dstPath,"w"),
bytesRead = 1,
pos = 0;
while(bytesRead > 0) {
while (bytesRead > 0) {
bytesRead = fs.readSync(srcFile,fileBuffer,0,FILE_BUFFER_LENGTH,pos);
fs.writeSync(dstFile,fileBuffer,0,bytesRead);
pos += bytesRead;
@@ -147,7 +148,7 @@ exports.deleteDirectory = function(dirPath) {
fs.unlinkSync(currPath);
}
}
fs.rmdirSync(dirPath);
fs.rmdirSync(dirPath);
}
return null;
};
@@ -254,7 +255,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
// Overriding to the .tid extension needs special handling
fileInfo.type = "application/x-tiddler";
fileInfo.hasMetaFile = false;
} else if(metaExt === ".json") {
} else if (metaExt === ".json") {
// Overriding to the .json extension needs special handling
fileInfo.type = "application/json";
fileInfo.hasMetaFile = false;
@@ -344,18 +345,18 @@ exports.generateTiddlerFilepath = function(title,options) {
// Replace any Windows control codes
filepath = filepath.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i,"_$1_");
// Replace any leading spaces with the same number of underscores
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_");});
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_")});
//If the path does not start with "." or ".." && a path seperator, then
if(!/^\.{1,2}[/\\]/g.test(filepath)) {
// Don't let the filename start with any dots because such files are invisible on *nix
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_");});
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_")});
}
// Replace any Unicode control codes
filepath = filepath.replace(/[\x00-\x1f\x80-\x9f]/g,"_");
// Replace any characters that can't be used in cross-platform filenames
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
// Replace any dots or spaces at the end of the extension with the same number of underscores
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_");});
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_")});
// Truncate the extension if it is too long
if(extension.length > 32) {
extension = extension.substr(0,32);
@@ -381,9 +382,9 @@ exports.generateTiddlerFilepath = function(title,options) {
}
// Add a uniquifier if the file already exists (default)
var fullPath = path.resolve(directory, filepath + extension);
if(!overwrite) {
if (!overwrite) {
var oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
count = 0;
count = 0;
do {
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
if(oldPath && oldPath == fullPath) break;
@@ -400,7 +401,7 @@ exports.generateTiddlerFilepath = function(title,options) {
writePath.indexOf(path.resolve(directory)) == 0 ||
writePath.indexOf(path.resolve($tw.boot.wikiPath)) == 0 ||
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
}
}
if(encode) {
writePath = path.resolve(directory,$tw.utils.encodeURIComponentExtended(fullPath));
}
@@ -520,12 +521,12 @@ Cleanup old files on disk, by comparing the options values:
*/
exports.cleanupTiddlerFiles = function(options,callback) {
var adaptorInfo = options.adaptorInfo || {},
bootInfo = options.bootInfo || {},
title = options.title || "undefined";
bootInfo = options.bootInfo || {},
title = options.title || "undefined";
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
$tw.utils.deleteTiddlerFile(adaptorInfo,function(err) {
if(err) {
if((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
// Error deleting the previous file on disk, should fail gracefully
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: \""+title+"\"",err);
return callback(null,bootInfo);

View File

@@ -10,7 +10,9 @@ Authenticator for WWW basic authentication
"use strict";
if($tw.node) {
var fs = require("fs"),
var util = require("util"),
fs = require("fs"),
url = require("url"),
path = require("path");
}

View File

@@ -19,7 +19,7 @@ exports.info = {
exports.handler = function(request,response,state) {
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
responseHeaders = {
"Content-Type": state.server.get("root-serve-type")
};
"Content-Type": state.server.get("root-serve-type")
};
state.sendResponse(200,responseHeaders,text);
};

View File

@@ -33,8 +33,8 @@ exports.handler = function(request,response,state) {
}
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
var headers = {"Content-Type": renderType};
state.sendResponse(200,headers,text,"utf8");
// Naughty not to set a content-type, but it's the easiest way to ensure the browser will see HTML pages as HTML, and accept plain text tiddlers as CSS or JS
state.sendResponse(200,{},text,"utf8");
} else {
response.writeHead(404);
response.end();

View File

@@ -18,7 +18,7 @@ exports.info = {
exports.handler = function(request,response,state) {
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
fields = $tw.utils.parseJSONSafe(state.data);
fields = $tw.utils.parseJSONSafe(state.data);
// Pull up any subfields in the `fields` object
if(fields.fields) {
$tw.utils.each(fields.fields,function(field,name) {

View File

@@ -9,15 +9,14 @@ Serve tiddlers over http
"use strict";
let fs, url, path, querystring, crypto, zlib;
if($tw.node) {
fs = require("fs"),
url = require("url"),
path = require("path"),
querystring = require("querystring"),
crypto = require("crypto"),
zlib = require("zlib");
var util = require("util"),
fs = require("fs"),
url = require("url"),
path = require("path"),
querystring = require("querystring"),
crypto = require("crypto"),
zlib = require("zlib");
}
/*
@@ -42,9 +41,7 @@ function Server(options) {
}
}
// Setup the default required plugins
this.requiredPlugins = this.get("required-plugins").split(",");
// Initialise CORS
this.corsEnable = this.get("cors-enable") === "yes";
this.requiredPlugins = this.get("required-plugins").split(',');
// Initialise CSRF
this.csrfDisable = this.get("csrf-disable") === "yes";
// Initialize Gzip compression
@@ -63,9 +60,9 @@ function Server(options) {
this.authorizationPrincipals = {
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
};
}
if(this.get("admin") || authorizedUserName !== "(anon)") {
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(",").map($tw.utils.trim);
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
}
// Load and initialise authenticators
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
@@ -92,7 +89,7 @@ function Server(options) {
this.listenOptions = {
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
passphrase: tlsPassphrase || ""
passphrase: tlsPassphrase || ''
};
this.protocol = "https";
}
@@ -117,7 +114,7 @@ encoding: the encoding of the data to send (passed to the end method of the resp
*/
function sendResponse(request,response,statusCode,headers,data,encoding) {
if(this.enableBrowserCache && (statusCode == 200)) {
var hash = crypto.createHash("md5");
var hash = crypto.createHash('md5');
// Put everything into the hash that could change and invalidate the data that
// the browser already stored. The headers the data and the encoding.
hash.update(data);
@@ -212,6 +209,7 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
Server.prototype.findMatchingRoute = function(request,state) {
for(var t=0; t<this.routes.length; t++) {
var potentialRoute = this.routes[t],
pathRegExp = potentialRoute.path,
pathname = state.urlInfo.pathname,
match;
if(state.pathPrefix) {
@@ -250,7 +248,7 @@ Check whether a given user is authorized for the specified authorizationType ("r
Server.prototype.isAuthorized = function(authorizationType,username) {
var principals = this.authorizationPrincipals[authorizationType] || [];
return principals.indexOf("(anon)") !== -1 || (username && (principals.indexOf("(authenticated)") !== -1 || principals.indexOf(username) !== -1));
};
}
Server.prototype.requestHandler = function(request,response,options) {
options = options || {};
@@ -263,13 +261,6 @@ Server.prototype.requestHandler = function(request,response,options) {
state.urlInfo = url.parse(request.url);
state.queryParameters = querystring.parse(state.urlInfo.query);
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
// Enable CORS
if(this.corsEnable) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Expose-Headers", "*");
}
state.sendResponse = sendResponse.bind(self,request,response);
// Get the principals authorized to access this resource
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
@@ -294,12 +285,6 @@ Server.prototype.requestHandler = function(request,response,options) {
response.end();
return;
}
// Reply to OPTIONS
if(this.corsEnable && request.method === "OPTIONS") {
response.writeHead(204);
response.end();
return;
}
// Find the route that matches this path
var route = self.findMatchingRoute(request,state);
// Optionally output debug info
@@ -337,7 +322,7 @@ Server.prototype.requestHandler = function(request,response,options) {
request.on("end",function() {
state.data = Buffer.concat(data);
route.handler(request,response,state);
});
})
} else {
response.writeHead(400,"Invalid bodyFormat " + route.bodyFormat + " in route " + route.method + " " + route.path.source);
response.end();
@@ -362,8 +347,8 @@ Server.prototype.listen = function(port,host,prefix) {
}
// Warn if required plugins are missing
var missing = [];
for(var index=0; index<this.requiredPlugins.length; index++) {
if(!this.wiki.getTiddler(this.requiredPlugins[index])) {
for (var index=0; index<this.requiredPlugins.length; index++) {
if (!this.wiki.getTiddler(this.requiredPlugins[index])) {
missing.push(this.requiredPlugins[index]);
}
}

View File

@@ -9,22 +9,22 @@ Base64 UTF-8 utlity functions.
"use strict";
const { TextEncoder, TextDecoder } = require("node:util");
const{ TextEncoder, TextDecoder } = require("node:util");
exports.btoa = (binstr) => Buffer.from(binstr, "binary").toString("base64");
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
exports.atob = (b64) => Buffer.from(b64, "base64").toString("binary");
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
function base64ToBytes(base64) {
const binString = exports.atob(base64);
return Uint8Array.from(binString, (m) => m.codePointAt(0));
return Uint8Array.from(binString, m => m.codePointAt(0));
};
function bytesToBase64(bytes) {
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
return exports.btoa(binString);
};
exports.base64EncodeUtf8 = (str) => bytesToBase64(new TextEncoder().encode(str));
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
exports.base64DecodeUtf8 = (str) => new TextDecoder().decode(base64ToBytes(str));
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));

View File

@@ -16,7 +16,8 @@ ignoreEnvironmentVariables: defaults to false
*/
exports.getAllPlugins = function(options) {
options = options || {};
var path = require("path"),
var fs = require("fs"),
path = require("path"),
tiddlers = {};
// Collect up the library plugins
var collectPlugins = function(folder) {

View File

@@ -6,7 +6,6 @@ Appearance/Caption: Appearance
Appearance/Hint: Ways to customise the appearance of your TiddlyWiki.
Basics/AnimDuration/Prompt: Animation duration
Basics/AutoFocus/Prompt: Default focus field for new tiddlers
Basics/AutoFocusEdit/Prompt: Default focus field for existing tiddlers
Basics/Caption: Basics
Basics/DefaultTiddlers/BottomHint: Use &#91;&#91;double square brackets&#93;&#93; for titles with spaces. Or you can choose to {{retain story ordering||$:/snippets/retain-story-ordering-button}}
Basics/DefaultTiddlers/Prompt: Default tiddlers
@@ -58,10 +57,11 @@ LayoutSwitcher/Caption: Layout
LoadedModules/Caption: Loaded Modules
LoadedModules/Hint: These are the currently loaded tiddler modules linked to their source tiddlers. Any italicised modules lack a source tiddler, typically because they were setup during the boot process.
Palette/Caption: Palette
Palette/CustomSettings/Prompt: Custom settings for current palette: <<palette-link>>
Palette/Editor/Clone/Caption: clone
Palette/Editor/Clone/Prompt: It is recommended that you clone this shadow palette before editing it
Palette/Editor/Delete/Hint: delete this entry from the current palette
Palette/Editor/Names/External/Show: Show color names that are not part of the current palette
Palette/Editor/Names/External/Show: Show inherited palette entries
Palette/Editor/Prompt/Modified: This shadow palette has been modified
Palette/Editor/Prompt: Editing
Palette/Editor/Reset/Caption: reset

View File

@@ -1,4 +0,0 @@
title: $:/language/Draft/
Attribution: Draft of '<<draft-title>>' by {{$:/status/UserName}}
Title: Draft of '<<draft-title>>'

View File

@@ -30,6 +30,7 @@ Error/DeserializeOperator/MissingOperand: Filter Error: Missing operand for 'des
Error/DeserializeOperator/UnknownDeserializer: Filter Error: Unknown deserializer provided as operand for the 'deserialize' operator
Error/Filter: Filter error
Error/FilterSyntax: Syntax error in filter expression
Error/FilterPragma: Filter Error: Unknown filter pragma
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
Error/IsFilterOperator: Filter Error: Unknown parameter for the 'is' filter operator
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator

View File

@@ -9,11 +9,6 @@ Advanced/ShadowInfo/NotShadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text
Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is a shadow tiddler
Advanced/ShadowInfo/Shadow/Source: It is defined in the plugin <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>
Advanced/ShadowInfo/OverriddenShadow/Hint: It is overridden by an ordinary tiddler
Advanced/CascadeInfo/Heading: Cascade Details
Advanced/CascadeInfo/Hint: These are the view template segments (tagged <<tag "$:/tags/ViewTemplate">>) using a cascade filter and their resulting template for the current tiddler.
Advanced/CascadeInfo/Detail/View: View
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Active cascade filter
Advanced/CascadeInfo/Detail/Template: Template
Fields/Caption: Fields
List/Caption: List
List/Empty: This tiddler does not have a list

View File

@@ -18,13 +18,13 @@ class BackgroundActionDispatcher {
// Track the filter for the background actions
this.filterTracker.track({
filterString: "[all[tiddlers+shadows]tag[$:/tags/BackgroundAction]!is[draft]]",
fnEnter: (title) => this.trackFilter(title),
fnEnter: title => this.trackFilter(title),
fnLeave: (title, enterValue) => this.untrackFilter(enterValue),
fnChange: (title, enterValue) => {
this.untrackFilter(enterValue);
return this.trackFilter(title);
},
fnProcess: (changes) => this.process(changes)
fnProcess: changes => this.process(changes)
});
}
@@ -75,7 +75,7 @@ class BackgroundActionTracker {
filterString: this.trackFilter,
fnEnter: () => { this.hasChanged = true; },
fnLeave: () => { this.hasChanged = true; },
fnProcess: (changes) => {
fnProcess: changes => {
if(this.hasChanged) {
this.hasChanged = false;
console.log("Processing background action", this.title);

View File

@@ -31,7 +31,7 @@ function FramedEngine(options) {
this.parentNode.insertBefore(this.iframeNode,this.nextSibling);
this.iframeDoc = this.iframeNode.contentWindow.document;
// (Firefox requires us to put some empty content in the iframe)
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette/palette-colours");
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>");
@@ -197,7 +197,7 @@ FramedEngine.prototype.handleFocusEvent = function(event) {
Handle a keydown event
*/
FramedEngine.prototype.handleKeydownEvent = function(event) {
if($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
return true;
}

View File

@@ -28,7 +28,12 @@ function SimpleEngine(options) {
if(this.widget.editTag === "textarea") {
this.domNode.appendChild(this.widget.document.createTextNode(this.value));
} else {
this.domNode.value = this.value;
if(this.widget.editType === "color") {
// The <input type="color"> element requires a six digit hex value
this.domNode.value = $tw.utils.convertCSSColorToRGBString(this.value);
} else {
this.domNode.value = this.value;
}
}
// Set the attributes
if(this.widget.editType && this.widget.editTag !== "textarea") {
@@ -83,6 +88,9 @@ Update the DomNode with the new text
*/
SimpleEngine.prototype.updateDomNodeText = function(text) {
try {
if(this.widget.editType === "color") {
text = $tw.utils.convertCSSColorToRGBString(text);
}
this.domNode.value = text;
} catch(e) {
// Ignore

View File

@@ -48,19 +48,19 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.toolbarNode = this.document.createElement("div");
this.toolbarNode.className = "tc-editor-toolbar";
parent.insertBefore(this.toolbarNode,nextSibling);
this.domNodes.push(this.toolbarNode);
this.renderChildren(this.toolbarNode,null);
this.domNodes.push(this.toolbarNode);
}
// Create our element
var editInfo = this.getEditInfo(),
Engine = this.editShowToolbar ? toolbarEngine : nonToolbarEngine;
this.engine = new Engine({
widget: this,
value: editInfo.value,
type: editInfo.type,
parentNode: parent,
nextSibling: nextSibling
});
widget: this,
value: editInfo.value,
type: editInfo.type,
parentNode: parent,
nextSibling: nextSibling
});
// Call the postRender hook
if(this.postRender) {
this.postRender();
@@ -217,12 +217,10 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
EditTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Completely rerender if any of our attributes have changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
this.refreshSelf();
return true;
} else if(changedTiddlers[this.editRefreshTitle]) {
this.engine.updateDomNodeText(this.getEditInfo().value);
} else if(changedTiddlers[this.editTitle]) {
} else if(changedAttributes["default"] || changedTiddlers[this.editRefreshTitle] || changedTiddlers[this.editTitle]) {
var editInfo = this.getEditInfo();
this.updateEditor(editInfo.value,editInfo.type);
}
@@ -274,8 +272,8 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
});
if($tw.keyboardManager.checkKeyDescriptors(event,keyInfoArray)) {
var clickEvent = this.document.createEvent("Events");
clickEvent.initEvent("click",true,false);
el.dispatchEvent(clickEvent);
clickEvent.initEvent("click",true,false);
el.dispatchEvent(clickEvent);
event.preventDefault();
event.stopPropagation();
return true;

View File

@@ -10,7 +10,7 @@ Text editor operation to excise the selection to a new tiddler
"use strict";
function isMarkdown(mediaType) {
return mediaType === "text/markdown" || mediaType === "text/x-markdown";
return mediaType === 'text/markdown' || mediaType === 'text/x-markdown';
}
exports["excise"] = function(event,operation) {

View File

@@ -19,7 +19,7 @@ exports["wrap-lines"] = function(event,operation) {
operation.cutStart = operation.selStart - (prefix.length + 1);
operation.cutEnd = operation.selEnd + suffix.length + 1;
// Also cut the following newline (if there is any)
if(operation.text[operation.cutEnd] === "\n") {
if (operation.text[operation.cutEnd] === "\n") {
operation.cutEnd++;
}
// Replace with selection

View File

@@ -44,7 +44,7 @@ exports["wrap-selection"] = function(event,operation) {
break;
}
return result;
};
}
function togglePrefixSuffix() {
if(o.text.substring(o.selStart - prefix.length, o.selStart + suffix.length) === prefix + suffix) {

View File

@@ -69,17 +69,17 @@ class FilterTracker {
if(!tracker) return;
const results = [];
// Evaluate the filter and remove duplicate results
$tw.utils.each(this.wiki.filterTiddlers(tracker.filterString), (title) => {
$tw.utils.each(this.wiki.filterTiddlers(tracker.filterString), title => {
$tw.utils.pushTop(results, title);
});
// Process the newly entered results
results.forEach((title) => {
results.forEach(title => {
if(!tracker.previousResults.includes(title) && !tracker.resultValues[title] && tracker.fnEnter) {
tracker.resultValues[title] = tracker.fnEnter(title) || true;
}
});
// Process the results that have just left
tracker.previousResults.forEach((title) => {
tracker.previousResults.forEach(title => {
if(!results.includes(title) && tracker.resultValues[title] && tracker.fnLeave) {
tracker.fnLeave(title, tracker.resultValues[title]);
delete tracker.resultValues[title];
@@ -91,7 +91,7 @@ class FilterTracker {
processChanges(changes) {
for(const tracker of this.trackers.values()) {
Object.keys(changes).forEach((title) => {
Object.keys(changes).forEach(title => {
if(title && tracker.previousResults.includes(title) && tracker.fnChange) {
tracker.resultValues[title] = tracker.fnChange(title, tracker.resultValues[title]) || tracker.resultValues[title];
}

View File

@@ -24,7 +24,7 @@ exports.cascade = function(operationSubFunction,options) {
}
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
"..currentTiddler": widget.getVariable("currentTiddler","")
}));
if(output.length !== 0) {
result = output[0];
@@ -34,5 +34,5 @@ exports.cascade = function(operationSubFunction,options) {
results.push(result);
});
}
};
}
};

View File

@@ -18,7 +18,7 @@ exports.filter = function(operationSubFunction,options) {
results.each(function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
"..currentTiddler": widget.getVariable("currentTiddler",""),
"index": "" + index,
"revIndex": "" + (results.length - 1 - index),
"length": "" + results.length
@@ -30,5 +30,5 @@ exports.filter = function(operationSubFunction,options) {
});
results.remove(resultsToRemove);
}
};
}
};

View File

@@ -7,6 +7,8 @@ Assign a value to a variable
\*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*

View File

@@ -20,7 +20,7 @@ exports.map = function(operationSubFunction,options) {
$tw.utils.each(inputTitles,function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
"..currentTiddler": widget.getVariable("currentTiddler",""),
"index": "" + index,
"revIndex": "" + (inputTitles.length - 1 - index),
"length": "" + inputTitles.length
@@ -28,12 +28,12 @@ exports.map = function(operationSubFunction,options) {
if(filtered.length && flatten) {
$tw.utils.each(filtered,function(value) {
results.push(value);
});
})
} else {
results.push(filtered[0]||"");
}
++index;
});
}
};
}
};

View File

@@ -17,7 +17,7 @@ exports.reduce = function(operationSubFunction,options) {
results.each(function(title) {
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
"..currentTiddler": widget.getVariable("currentTiddler"),
"index": "" + index,
"revIndex": "" + (results.length - 1 - index),
"length": "" + results.length,
@@ -31,5 +31,5 @@ exports.reduce = function(operationSubFunction,options) {
results.clear();
results.push(accumulator);
}
};
}
};

View File

@@ -24,7 +24,7 @@ exports.sort = function(operationSubFunction,options) {
results.each(function(title) {
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
"..currentTiddler": widget.getVariable("currentTiddler")
}));
sortKeys.push(key[0] || "");
});
@@ -36,12 +36,12 @@ exports.sort = function(operationSubFunction,options) {
// Sort the indexes
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
indexes = indexes.sort(function(a,b) {
return compareFn(sortKeys[a],sortKeys[b]);
return compareFn(sortKeys[a],sortKeys[b]);
});
// Add to results in correct order
$tw.utils.each(indexes,function(index) {
results.push(inputTitles[index]);
});
}
};
}
};

View File

@@ -43,7 +43,7 @@ function parseFilterOperation(operators,filterString,p) {
var bracket = filterString.charAt(nextBracketPos);
operator.operator = filterString.substring(p,nextBracketPos);
// Any suffix?
var colon = operator.operator.indexOf(":");
var colon = operator.operator.indexOf(':');
if(colon > -1) {
// The raw suffix for older filters
operator.suffix = operator.operator.substring(colon + 1);
@@ -67,7 +67,7 @@ function parseFilterOperation(operators,filterString,p) {
operator.operands = [];
var parseOperand = function(bracketType) {
var operand = {};
switch(bracketType) {
switch (bracketType) {
case "{": // Curly brackets
operand.indirect = true;
nextBracketPos = filterString.indexOf("}",p);
@@ -108,7 +108,7 @@ function parseFilterOperation(operators,filterString,p) {
}
operator.operands.push(operand);
p = nextBracketPos + 1;
};
}
p = nextBracketPos + 1;
parseOperand(bracket);
@@ -146,14 +146,16 @@ exports.parseFilter = function(filterString) {
match;
var whitespaceRegExp = /(\s+)/mg,
// Groups:
// 1 - entire filter run prefix
// 2 - filter run prefix itself
// 3 - filter run prefix suffixes
// 4 - opening square bracket following filter run prefix
// 5 - double quoted string following filter run prefix
// 6 - single quoted string following filter run prefix
// 7 - anything except for whitespace and square brackets
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
// 1 - pragma
// 2 - pragma suffix
// 3 - entire filter run prefix
// 4 - filter run prefix name
// 5 - filter run prefix suffixes
// 6 - opening square bracket following filter run prefix
// 7 - double quoted string following filter run prefix
// 8 - single quoted string following filter run prefix
// 9 - anything except for whitespace and square brackets
operandRegExp = /(?:::(\w+)(?:\:(\w+))?(?=\s|$)|((?:\+|\-|~|(?:=>?)|:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+)))/mg;
while(p < filterString.length) {
// Skip any whitespace
whitespaceRegExp.lastIndex = p;
@@ -170,18 +172,23 @@ exports.parseFilter = function(filterString) {
};
match = operandRegExp.exec(filterString);
if(match && match.index === p) {
// If there is a filter run prefix
if(match[1]) {
operation.prefix = match[1];
// If there is a filter pragma
operation.pragma = match[1];
operation.suffix = match[2];
p = match.index + match[0].length;
} else if(match[3]) {
// If there is a filter run prefix
operation.prefix = match[3];
p = p + operation.prefix.length;
// Name for named prefixes
if(match[2]) {
operation.namedPrefix = match[2];
if(match[4]) {
operation.namedPrefix = match[4];
}
// Suffixes for filter run prefix
if(match[3]) {
if(match[5]) {
operation.suffixes = [];
$tw.utils.each(match[3].split(":"),function(subsuffix) {
$tw.utils.each(match[5].split(":"),function(subsuffix) {
operation.suffixes.push([]);
$tw.utils.each(subsuffix.split(","),function(entry) {
entry = $tw.utils.trim(entry);
@@ -193,7 +200,7 @@ exports.parseFilter = function(filterString) {
}
}
// Opening square bracket
if(match[4]) {
if(match[6]) {
p = parseFilterOperation(operation.operators,filterString,p);
} else {
p = match.index + match[0].length;
@@ -203,9 +210,9 @@ exports.parseFilter = function(filterString) {
p = parseFilterOperation(operation.operators,filterString,p);
}
// Quoted strings and unquoted title
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
if(match[7] || match[8] || match[9]) { // Double quoted string, single quoted string or unquoted title
operation.operators.push(
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
{operator: "title", operands: [{text: match[7] || match[8] || match[9]}]}
);
}
results.push(operation);
@@ -228,25 +235,32 @@ exports.getFilterRunPrefixes = function() {
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
}
return this.filterRunPrefixes;
};
}
exports.filterTiddlers = function(filterString,widget,source) {
var fn = this.compileFilter(filterString);
return fn.call(this,source,widget);
exports.filterTiddlers = function(filterString,widget,source,options) {
var fn = this.compileFilter(filterString,options);
try {
const fnResult = fn.call(this,source,widget);
return fnResult;
} catch(e) {
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
}
};
/*
Compile a filter into a function with the signature fn(source,widget) where:
Compile a filter into a function with the signature fn(source,widget,options) where:
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
widget: an optional widget node for retrieving the current tiddler etc.
*/
exports.compileFilter = function(filterString) {
exports.compileFilter = function(filterString,options) {
var defaultFilterRunPrefix = (options || {}).defaultFilterRunPrefix || "or";
var cacheKey = filterString + "|" + defaultFilterRunPrefix;
if(!this.filterCache) {
this.filterCache = Object.create(null);
this.filterCacheCount = 0;
}
if(this.filterCache[filterString] !== undefined) {
return this.filterCache[filterString];
if(this.filterCache[cacheKey] !== undefined) {
return this.filterCache[cacheKey];
}
var filterParseTree;
try {
@@ -325,7 +339,8 @@ exports.compileFilter = function(filterString) {
regexp: operator.regexp
},{
wiki: self,
widget: widget
widget: widget,
defaultFilterRunPrefix: defaultFilterRunPrefix
});
if($tw.utils.isArray(results)) {
accumulator = self.makeTiddlerIterator(results);
@@ -346,29 +361,45 @@ exports.compileFilter = function(filterString) {
var filterRunPrefixes = self.getFilterRunPrefixes();
// Wrap the operator functions in a wrapper function that depends on the prefix
operationFunctions.push((function() {
var options = {wiki: self, suffixes: operation.suffixes || []};
switch(operation.prefix || "") {
case "": // No prefix means that the operation is unioned into the result
return filterRunPrefixes["or"](operationSubFunction, options);
case "=": // The results of the operation are pushed into the result without deduplication
return filterRunPrefixes["all"](operationSubFunction, options);
case "-": // The results of this operation are removed from the main result
return filterRunPrefixes["except"](operationSubFunction, options);
case "+": // This operation is applied to the main results so far
return filterRunPrefixes["and"](operationSubFunction, options);
case "~": // This operation is unioned into the result only if the main result so far is empty
return filterRunPrefixes["else"](operationSubFunction, options);
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
return filterRunPrefixes["let"](operationSubFunction, options);
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
} else {
if(operation.pragma) {
switch(operation.pragma) {
case "defaultprefix":
defaultFilterRunPrefix = operation.suffix || "or";
break;
default:
return function(results,source,widget) {
results.clear();
results.push($tw.language.getString("Error/FilterRunPrefix"));
results.push($tw.language.getString("Error/FilterPragma"));
};
}
}
return function(results,source,widget) {
// Dummy response
};
} else {
var options = {wiki: self, suffixes: operation.suffixes || []};
switch(operation.prefix || "") {
case "": // Use the default filter run prefix if none is specified
return filterRunPrefixes[defaultFilterRunPrefix](operationSubFunction, options);
case "=": // The results of the operation are pushed into the result without deduplication
return filterRunPrefixes["all"](operationSubFunction, options);
case "-": // The results of this operation are removed from the main result
return filterRunPrefixes["except"](operationSubFunction, options);
case "+": // This operation is applied to the main results so far
return filterRunPrefixes["and"](operationSubFunction, options);
case "~": // This operation is unioned into the result only if the main result so far is empty
return filterRunPrefixes["else"](operationSubFunction, options);
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
return filterRunPrefixes["let"](operationSubFunction, options);
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
} else {
return function(results,source,widget) {
results.clear();
results.push($tw.language.getString("Error/FilterRunPrefix"));
};
}
}
}
})());
});
@@ -407,7 +438,7 @@ exports.compileFilter = function(filterString) {
this.filterCache = Object.create(null);
this.filterCacheCount = 0;
}
this.filterCache[filterString] = fnMeasured;
this.filterCache[cacheKey] = fnMeasured;
this.filterCacheCount++;
return fnMeasured;
};

View File

@@ -0,0 +1,21 @@
/*\
title: $:/core/modules/filters/changecount.js
type: application/javascript
module-type: filteroperator
Filter operator for retrieving the changecount for each title in the list.
\*/
"use strict";
/*
Export our filter function
*/
exports.changecount = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(options.wiki.getChangeCount(title) + "");
});
return results;
};

View File

@@ -0,0 +1,140 @@
/*\
title: $:/core/modules/filters/colour-ops.js
type: application/javascript
module-type: filteroperator
Filter operators for colour operations
\*/
"use strict";
var Color = require("$:/core/modules/utils/dom/color.js").Color,
colourSpacesList = Object.keys(Color.spaces),
hueAdjustersList = ["raw","increasing","decreasing","longer","shorter"];
exports["colour-lighten"] = makeSerialColourOperator(function (colour, operator, options) {
return colour.lighten($tw.utils.parseNumber(operator.operand)).display().toString();
});
exports["colour-darken"] = makeSerialColourOperator(function (colour, operator, options) {
return colour.darken($tw.utils.parseNumber(operator.operand)).display().toString();
});
exports["colour-get-oklch"] = makeSerialColourOperator(function (colour, operator, options) {
var prop = ((operator.suffixes || [])[0] || ["l"])[0];
if(["l","c","h"].indexOf(prop) !== -1) {
colour = colour.oklch[prop];
}
return colour.toString();
});
exports["colour-set-oklch"] = makeSerialColourOperator(function (colour, operator, options) {
var prop = ((operator.suffixes || [])[0] || ["l"])[0];
if(["l","c","h"].indexOf(prop) !== -1) {
colour.oklch[prop] = $tw.utils.parseNumber(operator.operand);
}
return colour.display().toString();
});
exports["colour-set-alpha"] = makeSerialColourOperator(function (colour, operator, options) {
colour.alpha = $tw.utils.parseNumber(operator.operand);
return colour.display().toString();
});
exports["colour-contrast"] = makeParallelColourOperator(function (colours, operator, options) {
var colourContrasts = [];
$tw.utils.each(colours,function(colour,index) {
if(!colour) {
colour = $tw.utils.parseCSSColorObject("white");
colours[index] = colour;
}
if(index > 0) {
colourContrasts.push(colour.contrast(colours[index - 1],"DeltaPhi").toString());
}
});
return colourContrasts;
});
exports["colour-best-contrast"] = makeParallelColourOperator(function (colours, operator, options, originalColours) {
var bestContrast = 0,
bestColour = null;
if(colours.length < 2) {
return [];
}
var targetColour = colours[colours.length - 1];
for(var t=0; t<colours.length; t++) {
var colour = colours[t];
if(colour) {
var contrast = colour.contrast(targetColour,"DeltaPhi");
if(contrast > bestContrast) {
bestContrast = contrast;
bestColour = originalColours[t];
}
}
}
if(bestColour) {
return [bestColour];
} else {
return [];
}
});
exports["colour-interpolate"] = function(source,operator,options) {
// Get the colour space suffix
var space = ((((operator.suffixes || [])[0] || ["srgb"])[0]) || "").toLowerCase();
if(colourSpacesList.indexOf(space) === -1) {
space = "lch";
}
// Get the hue adjuster suffix
var hueAdjuster = ((((operator.suffixes || [])[1] || ["shorter"])[0]) || "").toLowerCase();
if(hueAdjustersList.indexOf(hueAdjuster) === -1) {
hueAdjuster = "shorter";
}
// Get the colours
if(operator.operands.length < 2) {
return [];
}
var colourA = $tw.utils.parseCSSColorObject(operator.operands[0]),
colourB = $tw.utils.parseCSSColorObject(operator.operands[1]);
if(!colourA || !colourB) {
return [];
}
var rangefn = colourA.range(colourB,{space: space, hue: hueAdjuster});
// Cycle through the weights
var results = [];
source(function(tiddler,title) {
var index = $tw.utils.parseNumber(title);
var colour = rangefn(index);
results.push(colour.display().toString());
});
return results;
};
function makeSerialColourOperator(fn) {
return function (source, operator, options) {
var results = [];
source(function (tiddler, title) {
var c = $tw.utils.parseCSSColorObject(title);
if (c) {
c = fn(c, operator, options);
results.push(c);
} else {
results.push("");
}
});
return results;
};
}
function makeParallelColourOperator(fn) {
return function (source, operator, options) {
var originalColours = [],
colours = [];
source(function (tiddler, title) {
originalColours.push(title);
colours.push($tw.utils.parseCSSColorObject(title));
});
return fn(colours, operator, options, originalColours);
};
}

View File

@@ -32,4 +32,4 @@ var modes = {
"gt": function(value) {return value > 0;},
"lteq": function(value) {return value <= 0;},
"lt": function(value) {return value < 0;}
};
}

View File

@@ -31,4 +31,4 @@ exports["deserialize"] = function(source,operator,options) {
return [$tw.language.getString("Error/DeserializeOperator/MissingOperand")];
}
return results;
};
}

View File

@@ -15,8 +15,8 @@ Export our filter function
*/
exports.each = function(source,operator,options) {
var results =[] ,
value,values = {},
field = operator.operand || "title";
value,values = {},
field = operator.operand || "title";
if(operator.suffix === "value" && field === "title") {
source(function(tiddler,title) {
if(!$tw.utils.hop(values,title)) {

View File

@@ -53,7 +53,7 @@ exports.field = function(source,operator,options) {
if(source.byField && operator.operand) {
indexedResults = source.byField(fieldname,operator.operand);
if(indexedResults) {
return indexedResults;
return indexedResults
}
}
source(function(tiddler,title) {

View File

@@ -24,7 +24,7 @@ exports.fields = function(source,operator,options) {
for(fieldName in tiddler.fields) {
(operand.indexOf(fieldName) !== -1) ? $tw.utils.pushTop(results,fieldName) : "";
}
} else if(suffixes.indexOf("exclude") !== -1) {
} else if (suffixes.indexOf("exclude") !== -1) {
for(fieldName in tiddler.fields) {
(operand.indexOf(fieldName) !== -1) ? "" : $tw.utils.pushTop(results,fieldName);
}

View File

@@ -13,13 +13,15 @@ Filter operator returning those input titles that pass a subfilter
Export our filter function
*/
exports.filter = function(source,operator,options) {
var filterFn = options.wiki.compileFilter(operator.operand),
var suffixes = operator.suffixes || [],
defaultFilterRunPrefix = (suffixes[0] || [options.defaultFilterRunPrefix] || [])[0] || "or",
filterFn = options.wiki.compileFilter(operator.operand,{defaultFilterRunPrefix}),
results = [],
target = operator.prefix !== "!";
source(function(tiddler,title) {
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title,
"..currentTiddler": options.widget.getVariable("currentTiddler",{defaultValue:""})
"..currentTiddler": options.widget.getVariable("currentTiddler","")
}));
if((list.length > 0) === target) {
results.push(title);

View File

@@ -12,7 +12,7 @@ Export our filter function
exports.timestamp = function(source,operand,options) {
var results = [];
source(function(tiddler,title) {
if(title.match(/^-?\d+$/)) {
if (title.match(/^-?\d+$/)) {
var value = new Date(Number(title));
results.push($tw.utils.formatDateString(value,operand || "[UTC]YYYY0MM0DD0hh0mm0ss0XXX"));
}

View File

@@ -13,7 +13,7 @@ returns the value at a given index of datatiddlers
Export our filter function
*/
exports.getindex = function(source,operator,options) {
var data,results = [];
var data,title,results = [];
if(operator.operand){
source(function(tiddler,title) {
title = tiddler ? tiddler.fields.title : title;

View File

@@ -157,13 +157,13 @@ function convertDataItemValueToStrings(item) {
if(item === undefined) {
return undefined;
} else if(item === null) {
return ["null"];
return ["null"]
} else if(typeof item === "object") {
var results = [],i,t;
if(Array.isArray(item)) {
// Return all the items in arrays recursively
for(i=0; i<item.length; i++) {
t = convertDataItemValueToStrings(item[i]);
t = convertDataItemValueToStrings(item[i])
if(t !== undefined) {
results.push.apply(results,t);
}
@@ -231,7 +231,7 @@ function getItemAtIndex(item,index) {
return item[index];
} else if(Array.isArray(item)) {
index = $tw.utils.parseInt(index);
if(index < 0) { index = index + item.length; };
if(index < 0) { index = index + item.length };
return item[index]; // Will be undefined if index was out-of-bounds
} else {
return undefined;
@@ -289,7 +289,7 @@ function setDataItem(data,indexes,value) {
var lastIndex = indexes[indexes.length - 1];
if(Array.isArray(current)) {
lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length; };
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
}
// Only set indexes on objects and arrays
if(typeof current === "object") {
@@ -316,7 +316,7 @@ function deleteDataItem(data,indexes) {
var lastIndex = indexes[indexes.length - 1];
if(Array.isArray(current) && current !== null) {
lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length; };
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
// Check if index is valid before splicing
if(lastIndex >= 0 && lastIndex < current.length) {
current.splice(lastIndex,1);

View File

@@ -25,7 +25,7 @@ exports.lookup = function(source,operator,options) {
indexSuffix = (suffixes[1] && suffixes[1][0] === "index") ? true : false,
target;
if(operator.operands.length == 2) {
target = operator.operands[1];
target = operator.operands[1]
} else {
target = indexSuffix ? "0": "text";
}

View File

@@ -17,35 +17,35 @@ Note that strings are converted to numbers automatically. Trailing non-digits ar
"use strict";
exports.negate = makeNumericBinaryOperator(
function(a) {return -a;}
function(a) {return -a}
);
exports.abs = makeNumericBinaryOperator(
function(a) {return Math.abs(a);}
function(a) {return Math.abs(a)}
);
exports.ceil = makeNumericBinaryOperator(
function(a) {return Math.ceil(a);}
function(a) {return Math.ceil(a)}
);
exports.floor = makeNumericBinaryOperator(
function(a) {return Math.floor(a);}
function(a) {return Math.floor(a)}
);
exports.round = makeNumericBinaryOperator(
function(a) {return Math.round(a);}
function(a) {return Math.round(a)}
);
exports.trunc = makeNumericBinaryOperator(
function(a) {return Math.trunc(a);}
function(a) {return Math.trunc(a)}
);
exports.untrunc = makeNumericBinaryOperator(
function(a) {return Math.ceil(Math.abs(a)) * Math.sign(a);}
function(a) {return Math.ceil(Math.abs(a)) * Math.sign(a)}
);
exports.sign = makeNumericBinaryOperator(
function(a) {return Math.sign(a);}
function(a) {return Math.sign(a)}
);
exports.add = makeNumericBinaryOperator(
@@ -103,29 +103,29 @@ exports.log = makeNumericBinaryOperator(
);
exports.sum = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;},
function(accumulator,value) {return accumulator + value},
0 // Initial value
);
exports.product = makeNumericReducingOperator(
function(accumulator,value) {return accumulator * value;},
function(accumulator,value) {return accumulator * value},
1 // Initial value
);
exports.maxall = makeNumericReducingOperator(
function(accumulator,value) {return Math.max(accumulator,value);},
function(accumulator,value) {return Math.max(accumulator,value)},
-Infinity // Initial value
);
exports.minall = makeNumericReducingOperator(
function(accumulator,value) {return Math.min(accumulator,value);},
function(accumulator,value) {return Math.min(accumulator,value)},
Infinity // Initial value
);
exports.median = makeNumericArrayOperator(
function(values) {
var len = values.length, median;
values.sort(function(a,b) {return a-b;});
values.sort(function(a,b) {return a-b});
if(len % 2) {
// Odd, return the middle number
median = values[(len - 1) / 2];
@@ -138,7 +138,7 @@ exports.median = makeNumericArrayOperator(
);
exports.average = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;},
function(accumulator,value) {return accumulator + value},
0, // Initial value
function(finalValue,numberOfValues) {
return finalValue/numberOfValues;
@@ -146,7 +146,7 @@ exports.average = makeNumericReducingOperator(
);
exports.variance = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;},
function(accumulator,value) {return accumulator + value},
0,
function(finalValue,numberOfValues,originalValues) {
return getVarianceFromArray(originalValues,finalValue/numberOfValues);
@@ -154,7 +154,7 @@ exports.variance = makeNumericReducingOperator(
);
exports["standard-deviation"] = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;},
function(accumulator,value) {return accumulator + value},
0,
function(finalValue,numberOfValues,originalValues) {
var variance = getVarianceFromArray(originalValues,finalValue/numberOfValues);
@@ -164,31 +164,31 @@ exports["standard-deviation"] = makeNumericReducingOperator(
//trigonometry
exports.cos = makeNumericBinaryOperator(
function(a) {return Math.cos(a);}
function(a) {return Math.cos(a)}
);
exports.sin = makeNumericBinaryOperator(
function(a) {return Math.sin(a);}
function(a) {return Math.sin(a)}
);
exports.tan = makeNumericBinaryOperator(
function(a) {return Math.tan(a);}
function(a) {return Math.tan(a)}
);
exports.acos = makeNumericBinaryOperator(
function(a) {return Math.acos(a);}
function(a) {return Math.acos(a)}
);
exports.asin = makeNumericBinaryOperator(
function(a) {return Math.asin(a);}
function(a) {return Math.asin(a)}
);
exports.atan = makeNumericBinaryOperator(
function(a) {return Math.atan(a);}
function(a) {return Math.atan(a)}
);
exports.atan2 = makeNumericBinaryOperator(
function(a,b) {return Math.atan2(a,b);}
function(a,b) {return Math.atan2(a,b)}
);
//Calculate the variance of a population of numbers in an array given its mean
@@ -222,8 +222,8 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
return [];
}
var value = result.reduce(function(accumulator,currentValue) {
return fnCalc(accumulator,currentValue);
},initialValue);
return fnCalc(accumulator,currentValue);
},initialValue);
if(fnFinal) {
value = fnFinal(value,result.length,result);
}

View File

@@ -21,7 +21,7 @@ exports.range = function(source,operator,options) {
}
// Process the parts
var beg, end, inc, i, fixed = 0;
for(i=0; i<parts.length; i++) {
for (i=0; i<parts.length; i++) {
// Validate real number
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
return ["range: bad number \"" + parts[i] + "\""];
@@ -36,10 +36,10 @@ exports.range = function(source,operator,options) {
switch(parts.length) {
case 1:
end = parts[0];
if(end >= 1) {
if (end >= 1) {
beg = 1;
}
else if(end <= -1) {
else if (end <= -1) {
beg = -1;
}
else {
@@ -72,7 +72,7 @@ exports.range = function(source,operator,options) {
end += direction * 0.5 * Math.pow(0.1,fixed);
var safety = 10010;
// Enumerate the range
if(end<beg) {
if (end<beg) {
for(i=beg; i>end; i+=inc) {
results.push(i.toFixed(fixed));
if(--safety<0) {

View File

@@ -15,7 +15,7 @@ Export our filter function
exports.removesuffix = function(source,operator,options) {
var results = [],
suffixes = (operator.suffixes || [])[0] || [];
if(!operator.operand) {
if (!operator.operand) {
source(function(tiddler,title) {
results.push(title);
});

View File

@@ -13,7 +13,9 @@ Filter operator returning its operand evaluated as a filter
Export our filter function
*/
exports.subfilter = function(source,operator,options) {
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source);
var suffixes = operator.suffixes || [],
defaultFilterRunPrefix = (suffixes[0] || [options.defaultFilterRunPrefix] || [])[0] || "or";
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source,{defaultFilterRunPrefix});
if(operator.prefix === "!") {
var results = [];
source(function(tiddler,title) {

View File

@@ -15,7 +15,7 @@ Export our filter function
exports.suffix = function(source,operator,options) {
var results = [],
suffixes = (operator.suffixes || [])[0] || [];
if(!operator.operand) {
if (!operator.operand) {
source(function(tiddler,title) {
results.push(title);
});

View File

@@ -24,4 +24,4 @@ exports.variables = function(source,operator,options) {
}
}
return names.sort();
};
};

View File

@@ -7,224 +7,224 @@ Extended filter operators to manipulate the current list.
\*/
"use strict";
"use strict";
/*
/*
Fetch titles from the current list
*/
var prepare_results = function (source) {
var prepare_results = function (source) {
var results = [];
source(function (tiddler, title) {
results.push(title);
});
return results;
};
source(function (tiddler, title) {
results.push(title);
});
return results;
};
/*
/*
Moves a number of items from the tail of the current list before the item named in the operand
*/
exports.putbefore = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
results.slice(0, -1) :
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count));
};
exports.putbefore = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
results.slice(0, -1) :
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count));
};
/*
/*
Moves a number of items from the tail of the current list after the item named in the operand
*/
exports.putafter = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
results.slice(0, -1) :
results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
};
exports.putafter = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
results.slice(0, -1) :
results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
};
/*
/*
Replaces the item named in the operand with a number of items from the tail of the current list
*/
exports.replace = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
results.slice(0, -count) :
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
};
exports.replace = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ?
results.slice(0, -count) :
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
};
/*
/*
Moves a number of items from the tail of the current list to the head of the list
*/
exports.putfirst = function (source, operator) {
var results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1);
return results.slice(-count).concat(results.slice(0, -count));
};
exports.putfirst = function (source, operator) {
var results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1);
return results.slice(-count).concat(results.slice(0, -count));
};
/*
/*
Moves a number of items from the head of the current list to the tail of the list
*/
exports.putlast = function (source, operator) {
var results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1);
return results.slice(count).concat(results.slice(0, count));
};
exports.putlast = function (source, operator) {
var results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1);
return results.slice(count).concat(results.slice(0, count));
};
/*
/*
Moves the item named in the operand a number of places forward or backward in the list
*/
exports.move = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1),
marker = results.splice(index, 1),
offset = (index + count) > 0 ? index + count : 0;
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
};
exports.move = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1),
marker = results.splice(index, 1),
offset = (index + count) > 0 ? index + count : 0;
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
};
/*
/*
Returns the items from the current list that are after the item named in the operand
*/
exports.allafter = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1) ? [] :
(operator.suffix) ? results.slice(index) :
exports.allafter = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1) ? [] :
(operator.suffix) ? results.slice(index) :
results.slice(index + 1);
};
};
/*
/*
Returns the items from the current list that are before the item named in the operand
*/
exports.allbefore = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1) ? [] :
(operator.suffix) ? results.slice(0, index + 1) :
exports.allbefore = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1) ? [] :
(operator.suffix) ? results.slice(0, index + 1) :
results.slice(0, index);
};
};
/*
/*
Appends the items listed in the operand array to the tail of the current list
*/
exports.append = function (source, operator) {
var append = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = parseInt(operator.suffix) || append.length;
return (append.length === 0) ? results :
(operator.prefix) ? results.concat(append.slice(-count)) :
exports.append = function (source, operator) {
var append = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = parseInt(operator.suffix) || append.length;
return (append.length === 0) ? results :
(operator.prefix) ? results.concat(append.slice(-count)) :
results.concat(append.slice(0, count));
};
};
/*
/*
Prepends the items listed in the operand array to the head of the current list
*/
exports.prepend = function (source, operator) {
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,prepend.length);
return (prepend.length === 0) ? results :
(operator.prefix) ? prepend.slice(-count).concat(results) :
exports.prepend = function (source, operator) {
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,prepend.length);
return (prepend.length === 0) ? results :
(operator.prefix) ? prepend.slice(-count).concat(results) :
prepend.slice(0, count).concat(results);
};
};
/*
/*
Returns all items from the current list except the items listed in the operand array
*/
exports.remove = function (source, operator) {
var array = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = parseInt(operator.suffix) || array.length,
p,
len,
index;
len = array.length - 1;
for(p = 0; p < count; ++p) {
if(operator.prefix) {
index = results.indexOf(array[len - p]);
} else {
index = results.indexOf(array[p]);
exports.remove = function (source, operator) {
var array = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source),
count = parseInt(operator.suffix) || array.length,
p,
len,
index;
len = array.length - 1;
for (p = 0; p < count; ++p) {
if (operator.prefix) {
index = results.indexOf(array[len - p]);
} else {
index = results.indexOf(array[p]);
}
if (index !== -1) {
results.splice(index, 1);
}
}
if(index !== -1) {
results.splice(index, 1);
}
}
return results;
};
return results;
};
/*
/*
Returns all items from the current list sorted in the order of the items in the operand array
*/
exports.sortby = function (source, operator) {
var results = prepare_results(source);
if(!results || results.length < 2) {
exports.sortby = function (source, operator) {
var results = prepare_results(source);
if (!results || results.length < 2) {
return results;
}
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
results.sort(function (a, b) {
return lookup.indexOf(a) - lookup.indexOf(b);
});
return results;
}
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
results.sort(function (a, b) {
return lookup.indexOf(a) - lookup.indexOf(b);
});
return results;
};
};
/*
/*
Removes all duplicate items from the current list
*/
exports.unique = function (source, operator) {
var results = prepare_results(source);
var set = results.reduce(function (a, b) {
if(a.indexOf(b) < 0) {
a.push(b);
}
return a;
}, []);
return set;
};
exports.unique = function (source, operator) {
var results = prepare_results(source);
var set = results.reduce(function (a, b) {
if (a.indexOf(b) < 0) {
a.push(b);
}
return a;
}, []);
return set;
};
var cycleValueInArray = function(results,operands,stepSize) {
var resultsIndex,
step = stepSize || 1,
i = 0,
opLength = operands.length,
nextOperandIndex;
for(i; i < opLength; i++) {
resultsIndex = results.indexOf(operands[i]);
var cycleValueInArray = function(results,operands,stepSize) {
var resultsIndex,
step = stepSize || 1,
i = 0,
opLength = operands.length,
nextOperandIndex;
for(i; i < opLength; i++) {
resultsIndex = results.indexOf(operands[i]);
if(resultsIndex !== -1) {
break;
}
}
if(resultsIndex !== -1) {
break;
}
}
if(resultsIndex !== -1) {
i = i + step;
nextOperandIndex = (i < opLength ? i : i % opLength);
if(operands.length > 1) {
results.splice(resultsIndex,1,operands[nextOperandIndex]);
i = i + step;
nextOperandIndex = (i < opLength ? i : i % opLength);
if(operands.length > 1) {
results.splice(resultsIndex,1,operands[nextOperandIndex]);
} else {
results.splice(resultsIndex,1);
}
} else {
results.splice(resultsIndex,1);
results.push(operands[0]);
}
} else {
results.push(operands[0]);
return results;
}
return results;
};
/*
/*
Toggles an item in the current list.
*/
exports.toggle = function(source,operator) {
return cycleValueInArray(prepare_results(source),operator.operands);
};
exports.cycle = function(source,operator) {
var results = prepare_results(source),
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
step = $tw.utils.getInt(operator.operands[1]||"",1);
if(step < 0) {
operands.reverse();
step = Math.abs(step);
exports.toggle = function(source,operator) {
return cycleValueInArray(prepare_results(source),operator.operands);
}
exports.cycle = function(source,operator) {
var results = prepare_results(source),
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
step = $tw.utils.getInt(operator.operands[1]||"",1);
if(step < 0) {
operands.reverse();
step = Math.abs(step);
}
return cycleValueInArray(results,operands,step);
}
return cycleValueInArray(results,operands,step);
};

View File

@@ -46,7 +46,7 @@ function BackSubIndexer(indexer,extractor) {
BackSubIndexer.prototype.init = function() {
// lazy init until first lookup
this.index = null;
};
}
BackSubIndexer.prototype._init = function() {
this.index = Object.create(null);
@@ -60,11 +60,11 @@ BackSubIndexer.prototype._init = function() {
self.index[target][sourceTitle] = true;
});
});
};
}
BackSubIndexer.prototype.rebuild = function() {
this.index = null;
};
}
/*
* Get things that is being referenced in the text, e.g. tiddler names in the link syntax.
@@ -78,7 +78,7 @@ BackSubIndexer.prototype._getTarget = function(tiddler) {
return this.wiki[this.extractor](parser.tree, tiddler.fields.title);
}
return [];
};
}
BackSubIndexer.prototype.update = function(updateDescriptor) {
// lazy init/update until first lookup
@@ -86,8 +86,8 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
return;
}
var newTargets = [],
oldTargets = [],
self = this;
oldTargets = [],
self = this;
if(updateDescriptor.old.exists) {
oldTargets = this._getTarget(updateDescriptor.old.tiddler);
}
@@ -106,7 +106,7 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
}
self.index[target][updateDescriptor.new.tiddler.fields.title] = true;
});
};
}
BackSubIndexer.prototype.lookup = function(title) {
if(!this.index) {
@@ -117,6 +117,6 @@ BackSubIndexer.prototype.lookup = function(title) {
} else {
return [];
}
};
}
exports.BackIndexer = BackIndexer;

View File

@@ -19,7 +19,7 @@ FieldIndexer.prototype.init = function() {
this.index = null;
this.maxIndexedValueLength = DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH;
this.addIndexMethods();
};
}
// Provided for testing
FieldIndexer.prototype.setMaxIndexedValueLength = function(length) {
@@ -33,14 +33,14 @@ FieldIndexer.prototype.addIndexMethods = function() {
this.wiki.each.byField = function(name,value) {
var lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) {
return self.wiki.tiddlerExists(title);
return self.wiki.tiddlerExists(title)
});
};
// get shadow tiddlers, including shadow tiddlers that is overwritten
this.wiki.eachShadow.byField = function(name,value) {
var lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) {
return self.wiki.isShadowTiddler(title);
return self.wiki.isShadowTiddler(title)
});
};
this.wiki.eachTiddlerPlusShadows.byField = function(name,value) {

View File

@@ -14,12 +14,12 @@ exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
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]
["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]
];
}

View File

@@ -140,7 +140,7 @@ function KeyboardManager(options) {
this.shortcutParsedList = []; // Stores the parsed key descriptors
this.shortcutPriorityList = []; // Stores the parsed shortcut priority
this.lookupNames = ["shortcuts"];
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac");
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac")
this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows");
this.lookupNames.push($tw.platform.isLinux ? "shortcuts-linux" : "shortcuts-not-linux");
this.updateShortcutLists(this.getShortcutTiddlerList());
@@ -161,7 +161,7 @@ KeyboardManager.prototype.getModifierKeys = function() {
91, // Meta (left)
93, // Meta (right)
224 // Meta (Firefox)
];
]
};
/*
@@ -187,7 +187,8 @@ KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor,options) {
metaKey: false
};
for(var t=0; t<components.length; t++) {
var s = components[t].toLowerCase();
var s = components[t].toLowerCase(),
c = s.charCodeAt(0);
// Look for modifier keys
if(s === "ctrl") {
info.ctrlKey = true;
@@ -265,7 +266,7 @@ KeyboardManager.prototype.getPrintableShortcuts = function(keyInfoArray) {
}
});
return result;
};
}
KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
return keyInfo &&
@@ -292,15 +293,15 @@ KeyboardManager.prototype.getMatchingKeyDescriptor = function(event,keyInfoArray
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" :
event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "shift" :
event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" :
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" :
event.altKey && event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt-shift" :
event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" :
event.altKey && event.shiftKey && event.ctrlKey && !event.metaKey ? "ctrl-alt-shift" :
event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" :
event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" :
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
event.metaKey && event.ctrlKey && event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" :
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" :
event.altKey && event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt-shift" :
event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" :
event.altKey && event.shiftKey && event.ctrlKey && !event.metaKey ? "ctrl-alt-shift" :
event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" :
event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" :
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
event.metaKey && event.ctrlKey && event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
};
KeyboardManager.prototype.getShortcutTiddlerList = function() {
@@ -370,8 +371,8 @@ KeyboardManager.prototype.handleShortcutChanges = function(changedTiddlers) {
var newList = this.getShortcutTiddlerList();
var hasChanged = $tw.utils.hopArray(changedTiddlers,this.shortcutTiddlers) ? true :
($tw.utils.hopArray(changedTiddlers,newList) ? true :
(this.detectNewShortcuts(changedTiddlers))
);
(this.detectNewShortcuts(changedTiddlers))
);
// Re-cache shortcuts if something changed
if(hasChanged) {
this.updateShortcutLists(newList);

View File

@@ -26,25 +26,26 @@ exports.params = [
Run the macro
*/
exports.run = function(target,fallbackTarget,colourA,colourB) {
var rgbTarget = $tw.utils.parseCSSColor(target) || $tw.utils.parseCSSColor(fallbackTarget);
var rgbTarget = $tw.utils.parseCSSColorObject(target) || $tw.utils.parseCSSColorObject(fallbackTarget);
if(!rgbTarget) {
return colourA;
}
var rgbColourA = $tw.utils.parseCSSColor(colourA),
rgbColourB = $tw.utils.parseCSSColor(colourB);
var rgbColourA = $tw.utils.parseCSSColorObject(colourA),
rgbColourB = $tw.utils.parseCSSColorObject(colourB);
if(rgbColourA && !rgbColourB) {
return rgbColourA;
return colourA;
}
if(rgbColourB && !rgbColourA) {
return rgbColourB;
return colourB;
}
if(!rgbColourA && !rgbColourB) {
// If neither colour is readable, return a crude inverse of the target
return [255 - rgbTarget[0],255 - rgbTarget[1],255 - rgbTarget[2],rgbTarget[3]];
rgbTarget.srgb.r = 1 - rgbTarget.srgb.r;
rgbTarget.srgb.g = 1 - rgbTarget.srgb.g;
rgbTarget.srgb.b = 1 - rgbTarget.srgb.b;
return rgbTarget.display();
}
// Colour brightness formula derived from http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
var brightnessTarget = rgbTarget[0] * 0.299 + rgbTarget[1] * 0.587 + rgbTarget[2] * 0.114,
brightnessA = rgbColourA[0] * 0.299 + rgbColourA[1] * 0.587 + rgbColourA[2] * 0.114,
brightnessB = rgbColourB[0] * 0.299 + rgbColourB[1] * 0.587 + rgbColourB[2] * 0.114;
return Math.abs(brightnessTarget - brightnessA) > Math.abs(brightnessTarget - brightnessB) ? colourA : colourB;
var aContrast = rgbColourA.contrast(rgbTarget,"DeltaPhi"),
bContrast = rgbColourB.contrast(rgbTarget,"DeltaPhi");
return aContrast > bContrast ? colourA : colourB;
};

View File

@@ -24,7 +24,8 @@ exports.params = [
Run the macro
*/
exports.run = function(filter,format) {
var tiddlers = this.wiki.filterTiddlers(filter),
var self = this,
tiddlers = this.wiki.filterTiddlers(filter),
tiddler,
fields = [],
t,f;
@@ -45,24 +46,24 @@ exports.run = function(filter,format) {
var p = fields.indexOf(value);
if(p !== -1) {
fields.splice(p,1);
fields.unshift(value);
fields.unshift(value)
}
});
// Output the column headings
var output = [], row = [];
fields.forEach(function(value) {
row.push(quoteAndEscape(value));
row.push(quoteAndEscape(value))
});
output.push(row.join(","));
// Output each tiddler
for(var t=0;t<tiddlers.length; t++) {
row = [];
tiddler = this.wiki.getTiddler(tiddlers[t]);
if(tiddler) {
for(f=0; f<fields.length; f++) {
row.push(quoteAndEscape(tiddler ? tiddler.getFieldString(fields[f]) || "" : ""));
}
}
if(tiddler) {
for(f=0; f<fields.length; f++) {
row.push(quoteAndEscape(tiddler ? tiddler.getFieldString(fields[f]) || "" : ""));
}
}
output.push(row.join(","));
}
return output.join("\n");

View File

@@ -31,8 +31,8 @@ exports.run = function(shortcuts,prefix,separator,suffix) {
}));
if(shortcutArray.length > 0) {
shortcutArray.sort(function(a,b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
return a.toLowerCase().localeCompare(b.toLowerCase());
})
return prefix + shortcutArray.join(separator) + suffix;
} else {
return "";

View File

@@ -7,17 +7,19 @@ 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
attributes: {
controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"}
}
};
type: "element",
tag: "$audio", // Using $audio to enable widget interception
attributes: {
controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"}
}
};
// Pass through source information
if(options._canonical_uri) {

View File

@@ -59,7 +59,7 @@ var BinaryParser = function(type,text,options) {
class: {type: "string", value: "tc-binary-warning"}
},
children: [warn, link]
};
}
this.tree = [element];
this.source = text;
this.type = type;

View File

@@ -45,7 +45,7 @@ var CsvParser = function(type,text,options) {
row.children.push({
"type": "element", "tag": tag, "children": [{
"type": "text",
"text": columns[column] || ""
"text": columns[column] || ''
}]
});
}

View File

@@ -45,7 +45,7 @@ exports.parseWhiteSpace = function(source,pos) {
type: "whitespace",
start: pos,
end: p
};
}
}
};
@@ -107,14 +107,13 @@ exports.parseStringLiteral = function(source,pos) {
type: "string",
start: pos
};
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[((?:[^\]]|\](?!\]))*)\]\]/g;
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')/g;
reString.lastIndex = pos;
var match = reString.exec(source);
if(match && match.index === pos) {
node.value = match[1] !== undefined ? match[1] :(
match[2] !== undefined ? match[2] : (
match[3] !== undefined ? match[3] : match[4]
));
match[2] !== undefined ? match[2] : match[3]
);
node.end = pos + match[0].length;
return node;
} else {
@@ -143,14 +142,7 @@ exports.parseParameterDefinition = function(paramString,options) {
var paramInfo = {name: paramMatch[1]},
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5];
if(defaultValue !== undefined) {
// Check for an MVV reference ((varname))
var mvvDefaultMatch = /^\(\(([^)|]+)\)\)$/.exec(defaultValue);
if(mvvDefaultMatch) {
paramInfo.defaultType = "multivalue-variable";
paramInfo.defaultVariable = mvvDefaultMatch[1];
} else {
paramInfo["default"] = defaultValue;
}
paramInfo["default"] = defaultValue;
}
params.push(paramInfo);
// Look for the next parameter
@@ -170,7 +162,7 @@ exports.parseMacroParameters = function(node,source,pos) {
}
node.end = pos;
return node;
};
}
/*
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
@@ -181,7 +173,7 @@ exports.parseMacroParameter = function(source,pos) {
start: pos
};
// Define our regexp
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[((?:[^\]]|\](?!\]))*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the parameter
@@ -192,16 +184,16 @@ exports.parseMacroParameter = function(source,pos) {
pos = token.end;
// Get the parameter details
node.value = token.match[2] !== undefined ? token.match[2] : (
token.match[3] !== undefined ? token.match[3] : (
token.match[4] !== undefined ? token.match[4] : (
token.match[5] !== undefined ? token.match[5] : (
token.match[6] !== undefined ? token.match[6] : (
""
token.match[3] !== undefined ? token.match[3] : (
token.match[4] !== undefined ? token.match[4] : (
token.match[5] !== undefined ? token.match[5] : (
token.match[6] !== undefined ? token.match[6] : (
""
)
)
)
)
)
)
)
);
);
if(token.match[1]) {
node.name = token.match[1];
}
@@ -214,201 +206,28 @@ exports.parseMacroParameter = function(source,pos) {
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:}
*/
exports.parseMacroInvocationAsTransclusion = function(source,pos) {
var node = {
type: "transclude",
start: pos,
attributes: {},
orderedAttributes: []
};
// Define our regexps
var reVarName = /([^\s>"'=:]+)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double opening angle bracket
var token = $tw.utils.parseTokenString(source,pos,"<<");
if(!token) {
return null;
}
pos = token.end;
// Get the variable name for the macro
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
if(!token) {
return null;
}
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
pos = token.end;
// Check that the tag is terminated by a space or >>
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
return null;
}
// Process attributes
pos = $tw.utils.parseMacroParametersAsAttributes(node,source,pos);
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double closing angle bracket
token = $tw.utils.parseTokenString(source,pos,">>");
if(!token) {
return null;
}
node.end = token.end;
return node;
};
/*
Look for an MVV (multi-valued variable) reference as a transclusion, i.e. ((varname)) or ((varname params))
Returns null if not found, or a parse tree node of type "transclude" with isMVV: true
*/
exports.parseMVVReferenceAsTransclusion = function(source,pos) {
var node = {
type: "transclude",
isMVV: true,
start: pos,
attributes: {},
orderedAttributes: []
};
// Define our regexps
var reVarName = /([^\s>"'=:)]+)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double opening parenthesis
var token = $tw.utils.parseTokenString(source,pos,"((");
if(!token) {
return null;
}
pos = token.end;
// Get the variable name
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
if(!token) {
return null;
}
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
pos = token.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double closing parenthesis
token = $tw.utils.parseTokenString(source,pos,"))");
if(!token) {
return null;
}
node.end = token.end;
return node;
};
/*
Parse macro parameters as attributes. Returns the position after the last attribute
*/
exports.parseMacroParametersAsAttributes = function(node,source,pos) {
var position = 0,
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
while(attribute) {
if(!attribute.name) {
attribute.name = (position++) + "";
attribute.isPositional = true;
}
node.orderedAttributes.push(attribute);
node.attributes[attribute.name] = attribute;
pos = attribute.end;
// Get the next attribute
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
}
node.end = pos;
return pos;
};
/*
Parse a macro parameter as an attribute. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}, with the name being optional
*/
exports.parseMacroParameterAsAttribute = function(source,pos) {
var node = {
start: pos
};
// Define our regexps
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 and the separator token
var nameToken = $tw.utils.parseTokenRegExp(source,pos,reAttributeName),
namePos = nameToken && $tw.utils.skipWhiteSpace(source,nameToken.end),
separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/g),
isNewStyleSeparator = false; // If there is no separator then we don't allow new style values
// If we have a name and a separator then we have a named attribute
if(nameToken && separatorToken) {
node.name = nameToken.match[1];
// key value separator is `=` or `:`
node.assignmentOperator = separatorToken.match[0];
pos = separatorToken.end;
isNewStyleSeparator = (node.assignmentOperator === "=");
}
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
// Mark the value as having been quoted in the source
node.quoted = true;
} else {
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue && isNewStyleSeparator) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
} else {
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue && isNewStyleSeparator) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation && isNewStyleSeparator) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference && isNewStyleSeparator) {
pos = mvvReference.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
} else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue && isNewStyleSeparator) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
}
}
}
var node = $tw.utils.parseMacroInvocation(source,pos);
if(node) {
var positionalName = 0,
transclusion = {
type: "transclude",
start: node.start,
end: node.end
};
$tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
$tw.utils.each(node.params,function(param) {
var name = param.name;
if(name) {
if(name.charAt(0) === "$") {
name = "$" + name;
}
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: name,type: "string", value: param.value, start: param.start, end: param.end});
} else {
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: (positionalName++) + "",type: "string", value: param.value, start: param.start, end: param.end});
}
}
});
return transclusion;
}
// Bail if we don't have a value
if(!node.type) {
return null;
}
// Update the end position
node.end = pos;
return node;
};
@@ -477,7 +296,7 @@ exports.parseFilterVariable = function(source) {
};
/*
Look for an HTML attribute definition. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
*/
exports.parseAttribute = function(source,pos) {
var node = {
@@ -527,20 +346,19 @@ exports.parseAttribute = function(source,pos) {
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference) {
pos = mvvReference.end;
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
node.value = macroInvocation;
} else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue) {
@@ -548,16 +366,8 @@ exports.parseAttribute = function(source,pos) {
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
node.type = "string";
node.value = "true";
}
node.type = "string";
node.value = "true";
}
}
}
@@ -565,7 +375,6 @@ exports.parseAttribute = function(source,pos) {
}
}
} else {
// If there is no equals sign or colon, then this is an attribute with no value, defaulting to "true"
node.type = "string";
node.value = "true";
}

View File

@@ -11,10 +11,11 @@ The PDF parser embeds a PDF viewer
var ImageParser = function(type,text,options) {
var element = {
type: "element",
tag: "iframe",
attributes: {}
};
type: "element",
tag: "iframe",
attributes: {}
},
src;
if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) {

View File

@@ -11,13 +11,14 @@ The video parser parses a video tiddler into an embeddable HTML element
var VideoParser = function(type,text,options) {
var element = {
type: "element",
tag: "video",
attributes: {
controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"}
}
};
type: "element",
tag: "video",
attributes: {
controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"}
}
},
src;
if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) {

View File

@@ -46,10 +46,10 @@ exports.parse = function() {
}
// Return the $codeblock widget
return [{
type: "codeblock",
attributes: {
code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
}
type: "codeblock",
attributes: {
code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
}
}];
};

View File

@@ -51,10 +51,10 @@ exports.parse = function() {
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
return [{
type: "void",
children: [],
text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart,
end: commentEnd
type: "void",
children: [],
text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart,
end: commentEnd
}];
};

View File

@@ -44,9 +44,9 @@ exports.parse = function() {
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
return [{
type: "void",
text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart,
end: commentEnd
type: "void",
text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart,
end: commentEnd
}];
};

View File

@@ -95,7 +95,7 @@ exports.parseIfClause = function(filterCondition) {
hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
// If we found an else then we need to parse the body looking for the endif
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>",
ex;
ex;
if(hasLineBreak) {
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
} else {

View File

@@ -26,6 +26,8 @@ exports.init = function(parser) {
Parse the most recent match
*/
exports.parse = function() {
// Get all the details of the match
var entityString = this.match[1];
// Move past the macro call
this.parser.pos = this.matchRegExp.lastIndex;
// Return the entity

View File

@@ -32,7 +32,7 @@ Instantiate parse rule
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /\\(function|procedure|widget)\s+([^(\s]+)\((\s*([^)]*(?:\)\)[^)]*)*))?\)(\s*\r?\n)?/mg;
this.matchRegExp = /\\(function|procedure|widget)\s+([^(\s]+)\((\s*([^)]*))?\)(\s*\r?\n)?/mg;
};
/*

View File

@@ -29,6 +29,7 @@ exports.init = function(parser) {
Parse the most recent match
*/
exports.parse = function() {
var self = this;
// Move past the pragma invocation
this.parser.pos = this.matchRegExp.lastIndex;
// Parse the filter terminated by a line break

View File

@@ -37,7 +37,7 @@ exports.parse = function() {
var paramString = this.match[2],
params = [];
if(paramString !== "") {
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[((?:[^\]]|\](?!\]))*)\]\]|([^"'\s]+)))?/mg,
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))?/mg,
paramMatch = reParam.exec(paramString);
while(paramMatch) {
// Save the parameter details

View File

@@ -1,95 +0,0 @@
/*\
title: $:/core/modules/parsers/wikiparser/rules/mvvdisplayinline.js
type: application/javascript
module-type: wikirule
Wiki rule for inline display of multi-valued variables and filter results.
Variable display: ((varname)) or ((varname||separator))
Filter display: (((filter))) or (((filter||separator)))
The default separator is ", " (comma space).
\*/
"use strict";
exports.name = "mvvdisplayinline";
exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
};
exports.findNextMatch = function(startPos) {
var source = this.parser.source;
var nextStart = startPos;
while((nextStart = source.indexOf("((",nextStart)) >= 0) {
if(source.charAt(nextStart + 2) === "(") {
// Filter mode: (((filter))) or (((filter||sep)))
var match = /^\(\(\(([\s\S]+?)\)\)\)/.exec(source.substring(nextStart));
if(match) {
// Check for separator: split on last || before )))
var inner = match[1];
var sepIndex = inner.lastIndexOf("||");
if(sepIndex >= 0) {
this.nextMatch = {
type: "filter",
filter: inner.substring(0,sepIndex),
separator: inner.substring(sepIndex + 2),
start: nextStart,
end: nextStart + match[0].length
};
} else {
this.nextMatch = {
type: "filter",
filter: inner,
separator: ", ",
start: nextStart,
end: nextStart + match[0].length
};
}
return nextStart;
}
} else {
// Variable mode: ((varname)) or ((varname||sep))
var match = /^\(\(([^()|]+?)(?:\|\|([^)]*))?\)\)/.exec(source.substring(nextStart));
if(match) {
this.nextMatch = {
type: "variable",
varName: match[1],
separator: match[2] !== undefined ? match[2] : ", ",
start: nextStart,
end: nextStart + match[0].length
};
return nextStart;
}
}
nextStart += 2;
}
return undefined;
};
/*
Parse the most recent match
*/
exports.parse = function() {
var match = this.nextMatch;
this.nextMatch = null;
this.parser.pos = match.end;
var filter, sep = match.separator;
if(match.type === "variable") {
filter = "[(" + match.varName + ")join[" + sep + "]]";
} else {
filter = match.filter + " +[join[" + sep + "]]";
}
return [{
type: "text",
attributes: {
text: {name: "text", type: "filtered", filter: filter}
},
orderedAttributes: [
{name: "text", type: "filtered", filter: filter}
]
}];
};

View File

@@ -93,7 +93,7 @@ exports.parseLink = function(source,pos) {
splitPos = null;
}
// Pull out the tooltip and URL
var URL, urlStart;
var tooltip, URL, urlStart;
textNode.start = pos;
if(splitPos) {
urlStart = splitPos + 1;

View File

@@ -67,5 +67,5 @@ exports.parse = function() {
return [{
type: "void",
children: tree
}];
}]
};

View File

@@ -60,7 +60,7 @@ var processRow = function(prevColumns) {
// End of row
if(prevCell && colSpanCount > 1) {
if(prevCell.attributes && prevCell.attributes && prevCell.attributes.colspan) {
colSpanCount += prevCell.attributes.colspan.value;
colSpanCount += prevCell.attributes.colspan.value;
} else {
colSpanCount -= 1;
}
@@ -163,7 +163,7 @@ exports.parse = function() {
table.children.splice(0,0,rowContainer); // Insert it at the bottom
}
// Set the alignment - TODO: figure out why TW did this
// rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom";
// rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom";
// Parse the caption
rowContainer.children = this.parser.parseInlineRun(rowTermRegExp,{eatTerminator: true});
} else {

View File

@@ -23,6 +23,27 @@ 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;
@@ -32,17 +53,17 @@ exports.parse = function() {
params = this.match[3] ? this.match[3].split("|") : [];
// Prepare the transclude widget
var transcludeNode = {
type: "transclude",
attributes: {},
isBlock: true
};
type: "transclude",
attributes: {},
isBlock: true
};
$tw.utils.each(params,function(paramValue,index) {
var name = "" + index;
transcludeNode.attributes[name] = {
name: name,
type: "string",
value: paramValue
};
}
});
// Prepare the tiddler widget
var tr, targetTitle, targetField, targetIndex, tiddlerNode;

View File

@@ -23,6 +23,27 @@ 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;
@@ -32,16 +53,16 @@ exports.parse = function() {
params = this.match[3] ? this.match[3].split("|") : [];
// Prepare the transclude widget
var transcludeNode = {
type: "transclude",
attributes: {}
};
type: "transclude",
attributes: {}
};
$tw.utils.each(params,function(paramValue,index) {
var name = "" + index;
transcludeNode.attributes[name] = {
name: name,
type: "string",
value: paramValue
};
}
});
// Prepare the tiddler widget
var tr, targetTitle, targetField, targetIndex, tiddlerNode;

View File

@@ -25,6 +25,8 @@ $$$
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.name = "typedblock";
exports.types = {block: true};

View File

@@ -49,7 +49,8 @@ PluginSwitcher.prototype.switchPlugins = function() {
var tiddler = self.wiki.getTiddler(title);
if(tiddler && tiddler.isPlugin() && plugins.indexOf(title) === -1) {
plugins.push(title);
var dependents = $tw.utils.parseStringArray(tiddler.fields.dependents || "");
var pluginInfo = $tw.utils.parseJSONSafe(self.wiki.getTiddlerText(title)),
dependents = $tw.utils.parseStringArray(tiddler.fields.dependents || "");
$tw.utils.each(dependents,function(title) {
accumulatePlugin(title);
});
@@ -57,11 +58,11 @@ PluginSwitcher.prototype.switchPlugins = function() {
};
accumulatePlugin(selectedPluginTitle);
// Read the plugin info for the incoming plugins
$tw.wiki.readPluginInfo(plugins);
var changes = $tw.wiki.readPluginInfo(plugins);
// Unregister any existing theme tiddlers
$tw.wiki.unregisterPluginTiddlers(this.pluginType);
var unregisteredTiddlers = $tw.wiki.unregisterPluginTiddlers(this.pluginType);
// Register any new theme tiddlers
$tw.wiki.registerPluginTiddlers(this.pluginType,plugins);
var registeredTiddlers = $tw.wiki.registerPluginTiddlers(this.pluginType,plugins);
// Unpack the current theme tiddlers
$tw.wiki.unpackPluginTiddlers();
// Call the switch handler

View File

@@ -32,10 +32,10 @@ function SaverHandler(options) {
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
// Count of changes that have not yet been saved
var filteredChanges = self.filterFn.call(self.wiki,function(iterator) {
$tw.utils.each(self.preloadDirty,function(title) {
var tiddler = self.wiki.getTiddler(title);
iterator(tiddler,title);
});
$tw.utils.each(self.preloadDirty,function(title) {
var tiddler = self.wiki.getTiddler(title);
iterator(tiddler,title);
});
});
this.numChanges = filteredChanges.length;
// Listen out for changes to tiddlers

View File

@@ -15,27 +15,27 @@ var AndTidWiki = function(wiki) {
AndTidWiki.prototype.save = function(text,method,callback,options) {
var filename = options && options.variables ? options.variables.filename : null;
if(method === "download") {
if (method === "download") {
// Support download
if(window.twi.saveDownload) {
if (window.twi.saveDownload) {
try {
window.twi.saveDownload(text,filename);
} catch(err) {
if(err.message === "Method not found") {
if (err.message === "Method not found") {
window.twi.saveDownload(text);
}
}
} else {
var link = document.createElement("a");
link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
if(filename) {
link.setAttribute("download",filename);
if (filename) {
link.setAttribute("download",filename);
}
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
} else if(window.twi.saveWiki) {
} else if (window.twi.saveWiki) {
// Direct save in Tiddloid
window.twi.saveWiki(text);
} else {

View File

@@ -22,7 +22,7 @@ var findSaver = function(window) {
console.log({ msg: "custom saver is disabled", reason: err });
return null;
}
};
}
var saver = findSaver(window) || findSaver(window.parent) || {};
var CustomSaver = function(wiki) {

View File

@@ -80,7 +80,7 @@ GiteaSaver.prototype.save = function(text,method,callback) {
callback: function(err,getResponseDataJson,xhr) {
if(xhr.status === 404) {
callback("Please ensure the branch in the Gitea repo exists");
} else {
}else{
data["branch"] = branch;
self.upload(uri + filename, use_put?"PUT":"POST", headers, data, callback);
}
@@ -101,6 +101,7 @@ GiteaSaver.prototype.upload = function(uri,method,headers,data,callback) {
if(err) {
return callback(err);
}
var putResponseData = $tw.utils.parseJSONSafe(putResponseDataJson);
callback(null);
}
});

View File

@@ -17,7 +17,8 @@ var GitHubSaver = function(wiki) {
};
GitHubSaver.prototype.save = function(text,method,callback) {
var username = this.wiki.getTiddlerText("$:/GitHub/Username"),
var self = this,
username = this.wiki.getTiddlerText("$:/GitHub/Username"),
password = $tw.utils.getPassword("github"),
repo = this.wiki.getTiddlerText("$:/GitHub/Repo"),
path = this.wiki.getTiddlerText("$:/GitHub/Path",""),
@@ -80,6 +81,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
if(err) {
return callback(err);
}
var putResponseData = $tw.utils.parseJSONSafe(putResponseDataJson);
callback(null);
}
});

View File

@@ -18,7 +18,8 @@ var GitLabSaver = function(wiki) {
GitLabSaver.prototype.save = function(text,method,callback) {
/* See https://docs.gitlab.com/ee/api/repository_files.html */
var username = this.wiki.getTiddlerText("$:/GitLab/Username"),
var self = this,
username = this.wiki.getTiddlerText("$:/GitLab/Username"),
password = $tw.utils.getPassword("gitlab"),
repo = this.wiki.getTiddlerText("$:/GitLab/Repo"),
path = this.wiki.getTiddlerText("$:/GitLab/Path",""),
@@ -44,7 +45,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
var uri = endpoint + "/projects/" + encodeURIComponent(repo) + "/repository/";
// Perform a get request to get the details (inc shas) of files in the same path as our file
$tw.utils.httpRequest({
url: uri + "tree/?path=" + encodeURIComponent(path.replace(/^\/+|\/$/g, "")) + "&branch=" + encodeURIComponent(branch.replace(/^\/+|\/$/g, "")),
url: uri + "tree/?path=" + encodeURIComponent(path.replace(/^\/+|\/$/g, '')) + "&branch=" + encodeURIComponent(branch.replace(/^\/+|\/$/g, '')),
type: "GET",
headers: headers,
callback: function(err,getResponseDataJson,xhr) {
@@ -70,7 +71,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
};
// Perform a request to save the file
$tw.utils.httpRequest({
url: uri + "files/" + encodeURIComponent(path.replace(/^\/+/, "") + filename),
url: uri + "files/" + encodeURIComponent(path.replace(/^\/+/, '') + filename),
type: requestType,
headers: headers,
data: JSON.stringify(data),
@@ -78,6 +79,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
if(err) {
return callback(err);
}
var putResponseData = $tw.utils.parseJSONSafe(putResponseDataJson);
callback(null);
}
});

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