1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-22 19:04:38 +00:00

Compare commits

..

160 Commits

Author SHA1 Message Date
Jeremy Ruston
b034587390 Alternative fix 2024-07-15 16:59:28 +01:00
Jeremy Ruston
3372eb3ba6 Revert "Initial Commit"
This reverts commit 25edf0e212.
2024-07-09 21:04:54 +01:00
Jeremy Ruston
b878feca59 Merge branch 'master' into fix-typing-closed-tiddler 2024-07-09 20:58:06 +01:00
Jeremy Ruston
5758d0b313 Merge branch 'tiddlywiki-com' 2024-07-09 17:00:41 +01:00
springerspandrel
753b289ba9 Clarify opposite handling of de-duplication order for unique Operator vs Dominant Append (#8357) 2024-07-09 16:34:18 +01:00
springerspandrel
ad5661ef1c Docs: Clarify wording on examples for tag-picker Macro (#8348) 2024-07-09 11:07:08 +01:00
springerspandrel
bc18bd9261 Make it easier to see which filter Operators are selection constructors (#8349) 2024-07-09 10:43:52 +01:00
springerspandrel
5aa889859a Help beginners orient to empty filter parameters (#8353) 2024-07-09 10:40:14 +01:00
Jeremy Ruston
eb6f3a423a Fix RSOE when editing the JSON of a plugin tiddler (#8354) 2024-07-09 09:47:38 +01:00
Jeremy Ruston
25edf0e212 Initial Commit 2024-07-06 18:08:13 +01:00
btheado
eeeb9f97a9 Add testcase to illustrate the bug in #8330 (#8336)
* Add testcase to illustrate the bug in #8330

* Move new testcase to tw5.com edition
2024-07-06 14:22:28 +01:00
Jeremy Ruston
8f1792df20 Testcase Widget: Fix import icon 2024-07-06 10:29:06 +01:00
Jeremy Ruston
e19f86482a Testcase Widget: Fix placement of toolbar dropdown 2024-07-06 10:28:50 +01:00
Jeremy Ruston
53924de313 Update release note 2024-07-05 12:27:14 +01:00
Jeremy Ruston
d2c2ada33c Fix full screen tour in zoomin storyview 2024-07-05 12:26:21 +01:00
Jeremy Ruston
b906515c69 Fix release note typo 2024-07-05 10:38:49 +01:00
Jeremy Ruston
8928b6e603 Update release note 2024-07-04 17:53:26 +01:00
Mario Pietsch
73163386c1 Datawidget: Add check if tiddler exists for $filter attribute to avoide rsod (#8333) 2024-07-04 17:37:40 +01:00
Mario Pietsch
32c75cbb68 Allow fieldmangler to catch unsaved tag changes (#8332)
* allow fieldmangler to catch unsaved tag changes

* fix typo in comment
2024-07-04 17:24:06 +01:00
Leilei332
b60abadf33 Fix transparent draft list (#8329) 2024-07-04 17:23:06 +01:00
Jeremy Ruston
a9b6de8c35 New Release Banner for v5.3.5 2024-07-04 16:07:25 +01:00
Mario Pietsch
84d1c81bb2 Revert to \define colour macro for backwards compatibility (#8327)
* revert to \define colour macro for backwards compatibility

* add color macro

* remove new functions
2024-07-01 22:12:04 +01:00
Jeremy Ruston
c25b8e3056 Merge branch 'tiddlywiki-com' 2024-07-01 10:21:33 +01:00
oeyoews
b81a1f22fe Fix: remove extra "tags:" typo (#8322) 2024-06-30 18:26:19 +01:00
Jeremy Ruston
703edd154c Fix illegal filename 2024-06-30 18:21:11 +01:00
springerspandrel
64e6a9a946 Docs: Update Lists in WikiText.tid so css class targets a real class (#8302)
Replace dummy .MyClass with a functional class such as .tc-muted, so that the example renders in a way that shows a difference.
2024-06-29 13:26:09 +01:00
springerspandrel
068b76b07d Docs: Update AutoSave.tid replace dead link to "SaverModule" with SavingMechanism (#8303)
AutoSave tiddler's first sentence currently points to SaverModule, which is a missing tiddler. SavingMechanism seems to be the retitled tiddler that wasn't relinked. (Perhaps more changes are warranted, but this minimal change avoids the embarrassment of a dead link at a place newbies might actually be depending on info.)
2024-06-29 13:25:52 +01:00
springerspandrel
f060ba75ff Docs: Fix typo in Named Filter Run Prefix.tid (#8304)
Fix typo/mispelling. The phrase "prefixes were implemented" had an errant h yielding "where implemented".
2024-06-29 13:25:22 +01:00
springerspandrel
7beaddb293 Docs: Add InputActions example to EditTextWidget (#8306) 2024-06-29 13:25:03 +01:00
springerspandrel
1937789ee2 Docs: Make currentTab variable tiddler, link from it to tabs Macro (#8310) 2024-06-29 13:24:26 +01:00
springerspandrel
2f2806c00c Docs: Add simple examples for EditWidget (#8308) 2024-06-29 13:23:30 +01:00
springerspandrel
87adbe0b14 Docs: Expand $:/language/Docs/Fields/_canonical_uri to note broader range of _canonical_uri types (#8313) 2024-06-29 13:22:03 +01:00
Jeremy Ruston
6554b5c9f4 Re-apply "Link to correct plugin instructions for Node.js #8246"
This change was accidentally missed when reverting #7821
2024-06-29 13:08:16 +01:00
Leilei332
c93d4c52fc Add stability badges colors (#8317) 2024-06-28 18:09:47 +01:00
Mario Pietsch
f3b129c245 [DOCS] Improve TiddlyWiki Archive (#8320) 2024-06-28 18:06:30 +01:00
Leilei332
74c9e4465d Signing the CLA (#8314)
Co-authored-by: Jeremy Ruston <jeremy@jermolene.com>
2024-06-28 11:28:57 +01:00
springerspandrel
0f4bc93a7e Signing CLA (#8307) 2024-06-28 11:27:35 +01:00
Jeremy Ruston
05bff57b65 Prepare for v5.3.5 2024-06-27 17:18:48 +01:00
Jeremy Ruston
0dcf7e91bf Version number update for 5.3.4 2024-06-27 17:05:52 +01:00
Jeremy Ruston
f50c2a2e64 Preparing for release of v5.3.4 2024-06-27 17:05:17 +01:00
Jeremy Ruston
a42dad6a5c Update readme 2024-06-27 17:05:06 +01:00
Jeremy Ruston
cff685ea11 Testcase widget: remove negative margins
The intention was to horizontally align the body text with the text within the test case. However, it also caused an overflow when used within vertical tabs (as in the release note)
2024-06-27 17:02:11 +01:00
Jeremy Ruston
791c7fac63 Merge branch 'tiddlywiki-com' 2024-06-27 16:47:57 +01:00
Jeremy Ruston
b90c3841c9 Add new release banner image to readme for v5.3.4 2024-06-27 09:11:06 +01:00
Bram Chen
a5e05e4eec Update chinese language files (#8297)
* Add chinese translations for TestCaseImport button
2024-06-27 09:02:40 +01:00
Jeremy Ruston
05792a9de3 Update new release banner image 2024-06-27 09:01:13 +01:00
lin onetwo
1c1f0ff4e8 Docs: Update Alternative page layouts.tid (#8298) 2024-06-27 08:43:08 +01:00
Mario Pietsch
d253503335 Update German translation (#8300) 2024-06-27 08:34:27 +01:00
Jeremy Ruston
a16dab9710 Test case docs update 2024-06-26 10:26:42 +01:00
Jeremy Ruston
18152aa7c8 Testcase UI enhancements (#8292)
* Include the ExpectedResults in the displayed tabs

* Lighted testcase background

* Add testcase toolbar with export and import options

* Further styling tweaks
2024-06-26 10:23:54 +01:00
Jeremy Ruston
f15b6a26da Testcase widget: Improve docs 2024-06-24 17:47:32 +01:00
btheado
5d06b922d3 Fix wikitext-example-table-row to render output in block mode (#8288)
* Fix wikitext-example-table-row so example output table cell is rendered in block mode

* Use transclude with =block instead of empty line to force block mode parsing
2024-06-22 17:53:47 +01:00
Jeremy Ruston
0031a95dfe Merge branch 'tiddlywiki-com' 2024-06-22 16:56:39 +01:00
Jeremy Ruston
eecd40723e Avoid accented characters in filenames 2024-06-22 16:56:22 +01:00
Mario Pietsch
5b9f4751ea Remove "debugger" statement from code - Make confetti examples more impressive (#8284)
* make confetti examples more impressive

* comment debugger statement
2024-06-21 14:15:31 +01:00
Mario Pietsch
b6cf098c5f Make the tour confetti more impressive (#8286) 2024-06-21 14:14:46 +01:00
Jeremy Ruston
5c63262feb Merge branch 'tiddlywiki-com' 2024-06-21 09:09:55 +01:00
Jeremy Ruston
3b88f0e741 Tweak wording 2024-06-21 09:09:44 +01:00
Mohammad Rahmani
b49ecf886b Correction to Minlength Operator (#8281) 2024-06-21 09:08:38 +01:00
Mario Pietsch
02ccec7ea8 Improve docs for TranscludeWidget and Transclusion tiddler (#8282) 2024-06-21 09:07:41 +01:00
Mario Pietsch
14c5628d35 Fix: Edge-Browser - Opening HelloThere with debugger "Pause on caught exceptions" causes a break (#8283) 2024-06-21 09:06:33 +01:00
Mario Pietsch
4bd3576432 improve ControlPanel Settings style-ability (#8275) 2024-06-19 18:01:34 +01:00
Jeremy Ruston
756ef697dd Merge branch 'tiddlywiki-com' 2024-06-19 14:35:20 +01:00
Bram Chen
11f562a918 Update chinese language files (#8274)
* Add chinese translations of palette colour names used for stability badges
2024-06-19 12:42:15 +01:00
Jeremy Ruston
083489102e Tour plugin: Improve layout
See https://talk.tiddlywiki.org/t/final-checks-before-release-of-v5-3-4/9934/19
2024-06-19 12:41:39 +01:00
Jeremy Ruston
cd8c483f67 Stability badges: further fix to palette usage 2024-06-19 12:28:31 +01:00
Jeremy Ruston
c8cbf6853e Stability badges: Use palette colours
I am happy to merge translations of these strings before v5.3.4 releases /cc @BramChen
2024-06-19 10:24:47 +01:00
Jeremy Ruston
153b66e4ee Tour plugin: search for "home" instead of "help" 2024-06-19 10:08:53 +01:00
Jeremy Ruston
93c9323d0f Tour plugin: do not offer further tours if none are loaded 2024-06-19 10:08:36 +01:00
Jeremy Ruston
4cd66697ad Tour plugin: remove unfinished "Using Tags" tour 2024-06-19 10:08:19 +01:00
lin onetwo
741aef55e4 Fix: transcludes and backtranscludes operators to always include self-referential transclusion (#8257)
* fix: ignore self-referential transclusion

* feat: support old <$transclude tiddler param

* fix: restore old behavior: include itself like backlinks[]

* refactor: use LinkedList in transcludes[] and backtranscludes[]

* fix: only fallback to title when {{!!xxx}}, not when input is empty

* refactor: move transcludes ast extractor to a file

* refactor: move links ast extractor to a file

* Revert "refactor: move links ast extractor to a file"

This reverts commit 5600a00cd8.

* Revert "refactor: move transcludes ast extractor to a file"

This reverts commit 61d5484f09.

* lint: use pushTop and remove space
2024-06-19 09:38:02 +01:00
Jeremy Ruston
8eb08820ac Update release note 2024-06-18 20:57:24 +01:00
Jeremy Ruston
4ca883fd9b Revert #7821
See https://github.com/Jermolene/TiddlyWiki5/pull/7821#issuecomment-2176843674
2024-06-18 20:52:35 +01:00
twMat
2f4c21e374 Update Procedures.tid (#8273)
Clarifying of the "tip" assuming this is what the tip is after.
2024-06-18 18:17:29 +01:00
Jeremy Ruston
6239384e7b Geomap: Do not attempt to render to fakedom 2024-06-18 15:50:15 +01:00
Jeremy Ruston
ead36cf329 Geomap docs typo 2024-06-18 15:45:40 +01:00
Mario Pietsch
cdd3f4b6a2 Update German translations - fix some typos (#8261)
* Update German translations - fix some typos

* fix typo
2024-06-18 10:29:13 +01:00
Mario Pietsch
fdb86e7881 Remove NEW ribbon from "Saving with Polly" and "TiddlyBucket " (#8266) 2024-06-18 09:11:50 +01:00
Mario Pietsch
b4ac1e6b35 Update description field for Release v5.3.2 and v5.3.3 (#8267) 2024-06-18 09:11:24 +01:00
btheado
91e0b2afb6 Use the testcase widget to add some simple tm-http-request examples (#8260) 2024-06-15 09:25:12 +01:00
Jeremy Ruston
2d5b935b1c Fix server header authentication when header is missing
Fixes #8237
2024-06-14 09:58:06 +01:00
Jeremy Ruston
177ba4b56e Update archive
@pmario v5.3.2 appears to be missing, is that something you could kindly help with?
2024-06-14 09:54:48 +01:00
Andrei Rybak
6f248bf5b5 Docs: Link to correct plugin instructions for Node.js (#8246)
If a user of a Node.js (aka "client-server") installation of TiddlyWiki5
goes through instructions of "Installing a plugin from the plugin
library" [1], they will encounter a dead end, quote:

	The official plugin library is disabled when using the
	client-server configuration. Instead, plugins should be
	installed via the `tiddlywiki.info` file, as described here.

The word "here" links to the same tiddler [1], sending the user into a
endless loop.

Instead, link to "Installing official plugins on Node.js" [2], which
actually contains the instructions for editing `tiddlywiki.info` file.

[1] https://tiddlywiki.com/#Installing%20a%20plugin%20from%20the%20plugin%20library
[2] https://tiddlywiki.com/#Installing%20official%20plugins%20on%20Node.js
2024-06-12 22:26:52 +01:00
Jeremy Ruston
4bda8cfee6 Tweak release note 2024-06-12 11:54:33 +01:00
Jeremy Ruston
93d32d59aa Fix spotlight effect when scrollbars visible 2024-06-12 11:54:24 +01:00
Jeremy Ruston
e30746d5e5 Button widget should refresh when tooltip attribute changes
Fixes #8253
2024-06-12 10:20:40 +01:00
Jeremy Ruston
3e1d8fa598 Tweak release note 2024-06-12 10:02:51 +01:00
lin onetwo
32cbc97a0c Fix/self transclude (#8254)
* fix: ignore empty tiddler param when extract transcludes

* test: about self transclude
2024-06-12 09:39:43 +01:00
Mateusz Wilczek
d276e0aa25 Improve docs of transcludes and backtranscludes operators (#8247)
* Improve docs of transcludes and backtranscludes operators

* Improve docs: cross reference hard/soft links and transclusions
2024-06-10 11:36:44 +01:00
Andrei Rybak
3243adc3a5 Sign the CLA (#8245)
Sign the CLA for Andrei Rybak, https://github.com/rybak
2024-06-09 15:52:55 +01:00
Jeremy Ruston
bf9865af20 Update release note 2024-06-09 09:12:47 +01:00
Saq Imtiaz
08c7a8805b Fix: action-log should not evaluate functions (#8239) 2024-06-08 17:12:51 +01:00
Mario Pietsch
12c551ef05 Make sure split(regex) returns an array of strings (#8222)
* make sure split(regex) returns an array of strings

* remove "undefined" from the output

* add info about capture groups to the docs
2024-06-08 17:09:21 +01:00
btheado
a67c0e1399 Use the testcase widget for the -deletefield widget examples (#8243) 2024-06-08 16:53:32 +01:00
btheado
7ec8334005 Use the testcase widget for the $action-deletetiddler widget examples (#8242) 2024-06-08 16:51:55 +01:00
Jeremy Ruston
1a57d08feb Tweak #7866 to omit "rule" property when unset, instead of leaving it null
Also make tests pass
2024-06-08 16:51:00 +01:00
Jeremy Ruston
5db3eeeaa2 Update release note 2024-06-08 16:41:32 +01:00
Jeremy Ruston
e4c682d04b Merging #7866: Add start and end properties to WikiText AST nodes
commit 5687d9f44b
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Dec 6 11:33:43 2023 +0800

    Fix for html parser

commit df0a1b184e
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Dec 6 02:47:47 2023 +0800

    Fix HTML AST node boundary parsing in WikiText

commit ac8dda0a1a
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Sat Dec 2 13:02:52 2023 +0800

    update test-wikitext-parser.js, change for-const-of -to .utils.each, add more range attributes

commit e2b9a4ed57
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Nov 29 22:35:39 2023 +0800

    Add more start-end range attributes for AST

commit d3e62ec56a
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Nov 29 20:45:00 2023 +0800

    Add rule attribute for WikiText AST nodes

commit 4200495055
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Nov 29 15:48:38 2023 +0800

    Add start and end properties to AST nodes for list, codeblock, and all other elements
2024-06-08 16:40:20 +01:00
Jeremy Ruston
240496d85c Update release note 2024-06-08 15:04:24 +01:00
lin onetwo
78ace99685 Feat: translatable plugins and docs (#7821)
* feat: t macro and docs

* feat: support block mode so you can transclude whole tiddler

* refactor: use lingo and procedure

* refactor: use function instead of set variable

* docs: about  mode:"inline"

* Update LingoMacro.tid

* docs: more usage about inline

* refactor: update translate macro to reuse lingo macro

* Delete translateMacro.tid

* refactor: update translation of tiddlyweb

* docs: more tiddlyweb l10n

* feat: add comment, so when use <$text text=<<lingo>> by mistake, it shows

* i18n: add more l10n

* feat: add tree to plugin to reveal l10n structure

* i18n: add menubar translation for example

* i18n: more for menubal

* docs: Headings -> Heading

* refactor: remove the "tree" tid

* Revert "refactor: remove the "tree" tid"

This reverts commit fb70f0b146.
2024-06-08 14:58:21 +01:00
Jeremy Ruston
3ddd10d373 Update release note 2024-06-07 18:13:18 +01:00
Jeremy Ruston
6833ccdb97 Revert "Improve command line logging (#3704)"
This reverts commit 25ec52b912.
2024-06-07 18:09:50 +01:00
Jeremy Ruston
36a9e3f54e Merge branch 'tiddlywiki-com' 2024-06-06 17:16:13 +01:00
Jeremy Ruston
789d64f768 Merge PR #7661 2024-06-06 17:15:41 +01:00
Jeremy Ruston
25ec52b912 Improve command line logging (#3704)
* Initial improvements

* Fix broken merge
2024-06-06 16:46:10 +01:00
Jeremy Ruston
4be81b2bf4 Merge branch 'tiddlywiki-com' 2024-06-06 13:30:02 +01:00
Jeremy Ruston
423075e89d AWS Plugin: Fix for SJCL changes 2024-06-06 11:29:02 +01:00
Mario Pietsch
51ad11401b Docs: fix broken internal links (#8159)
* fix broken internal links

* reset modified fields
2024-06-06 11:25:03 +01:00
Cameron Fischer
352272905e Fixed issue where $parameters did nothing with no $transclude (#8203)
* Fixed issue where $parameters did nothing with no $transclude

* Figured I should test \parameters too
2024-06-06 11:20:35 +01:00
Saq Imtiaz
eb15dc8408 Docs: Corrects tag on parsermode pragma documentation (#8235)
* docs: Corrects tag on parsermode pragma documentation

* Update Pragma_ _parsermode.tid

reset modified date
2024-06-04 19:42:22 +01:00
Saq Imtiaz
33bc77f46f fix: nested functions should resolve filter run variables (#8233) 2024-06-04 18:19:41 +01:00
lin onetwo
4860b14315 Import global macros when render title (#8097)
* fix: import lingo macro when render title

* refactor: only import lingo macro for title to save memory

* Revert "refactor: only import lingo macro for title to save memory"

This reverts commit 36bf0848e0.
2024-06-04 17:13:41 +01:00
Jeremy Ruston
913d15dc53 Fixed editor layout
Fixes #8217
2024-06-04 11:50:55 +01:00
lin onetwo
9e1babdf82 Update backtranscludes.tid (#8014) 2024-06-04 11:39:51 +01:00
Jeremy Ruston
ea173ec83d Add basic authentication support for tm-http-request (#8109) 2024-06-03 19:20:12 +01:00
Jeremy Ruston
40801f3c29 Update release note 2024-06-03 09:21:51 +01:00
twMat
312b3b2037 Typo in Procedures.tid (#8229) 2024-06-02 10:25:30 +01:00
Xavier Cazin
f8ae96118a Catchup with fr-FR translation (#8231)
* fr-FR description of the `stability` core field

* fr-FR translations for testcase-related description strings

* fr-FR translations for testcase-related palette descriptions

* fr-FR translation for emergency download button caption

* Replace operand with parameters in fr-FR description of isfilteroperator

* fr-FR description of the `class` core field

* fr-FR update of a --command example

* better fr-FR description for main types

* Clearer fr-FR description of the `server` command

* Complete the fr-FR translation for the --savewikifolder description
2024-06-02 10:17:03 +01:00
Jeremy Ruston
7337b6da63 Missing contributor from release note 2024-05-31 14:42:39 +01:00
Jeremy Ruston
416c6ee0d4 Fix URL of geospatial demo 2024-05-31 14:02:21 +01:00
Jeremy Ruston
743bc4933f Update release note 2024-05-31 13:46:27 +01:00
Jeremy Ruston
4055501f71 Add Geospatial plugin (#7406)
* Add XLSX import spec for demo real estate spreadsheets

* Fix fieldname

* Improve map pin

* RealEstate demo: Set lat, long, price fields to be numeric

* Clean up Flickr demo

* Update geomap widget to refresh properly

* Add Leaflet MasterCluster plugin

* Setup the marker cluster plugin

* Rearrange real estate demo

* Reduce default cluster radius

* Beginnings of real estate demo

* Fix interpretation of HTTP status codes

* Real estate demo: Make columns hideable

* Real estate demo: sortability

* Real estate demo: search and limit

* Fix typo

* Fix lat long transposition

* Fix startup ordering

* Add geolookup operator

* Real Estate Demo: Add support for computed columns

* Real estate demo: Increase result limit

* Remove demo data

* Track map pan and zoom state in a state tiddler

* WIP

* Use geojson extension for geojson file

* Use geojson extensions for another geojson file

* Split demo from the geospatial plugin into its own edition

* Add build targets required by ./bin/site-build.sh...

... when building the geospatial edition as the main edition, making it easier to find on Vercel

* CI Fixes

* Fix default tab

* Rearranging geospatial plugin vs. edition

* More refactoring between demo and plugin

* Start of plugin docs

* Display GeoJSON properties on click

* Fix layer lookup demo

* Restore XLSX Utils plugin and dependencies

* Cleanup docs

* Remove 5.2.8 release note

* Remove 5.2.8 release note

* Docs update

* Fix minor refreshing bug for geomap widget

* Docs updates

* Add jsonset operator

* Add geonearestpoint operator

* jsonset: support for other data types and documentation

* Add logo

* Add link to preview build

* jsonset: add support for assigning JSON strings

* Fix nonstandard initialisation code for fill/parameter/slot widgets

* Introduce testcase widget so that we can reuse testcases as documentation examples

There's still a bit to do: adding tabs to the source panel of the testcase display, and tweaking the CSS.

* Update logo

* Testcasewidget: Add tabs for switching between source tiddlers

* Testcase appearance tweaks

* Switch to fluid-fixed layout

* Docs for the testcase-transclude and testcase-view widgets

* Split docs into separate tabs

* Extend testcase-view to be able to view other fields

* Extend default testcase template to show all fields of payload tiddlers

* Add some geomap examples

* Fix testcase rounded corners

* Add a geomap layer demo

* Add favicon

* Switch from building the geospatial plugin as the main build back to tw5.com

To make it easier to get to the documentation for the new features

* Remove obsolete comment

* Remove geospatial plugin from tw5.com build

* Fix build link

* Add note about core enhancements included in this branch

* Refactor data widget implementation

To avoid code duplication

* Integrate test cases with the docs

* Remove erroneously pasted docs material

* Remove erroneously copied olc-encode tests within old-decode test case

* Refactor compound tiddler handling into data widget

And add some tests for the data widget

* Default test case template tweaks

* Move Flickr macros into geospatial plugin from the demo edition

* FlickrDemo: Simplify UI

* FlickrMacros: Use a template to define photo tiddler fields

* Remove geospatial plugin from prerelease default tiddlers

* Extend Flickr helpers to support photoTiddlerTemplate parameter

* Update modification times of doc tiddlers

So that they are at the top of the recent tab

* Update 5.3.0 release note

* Remove custom CI step for this branch

* Restore standard sitetitle

* Flickr macro docs

* Rename $:/tags/GeoLayer to $:/tags/GeoFeature

And make sure that it works with all GeoJSON features, not just polygons

* More test data (from leaflet.js)

* Captions should be transcluded, not viewed raw

* Make HTTP handler use wiki of widget that sent the message

* Switch testcase widget to use an intrinsic template

Makes things much simpler

* Complete Flickr demos

* Extend geonearestpoint operator to work with feature collections

* Extend realestate demo to show data on nearest volcano

* Flickr macros: fix pagination after first page

Make sure that the widget we create to run the actions also has access to the event handlers attached to the rootwidget.

* Real estate demo: Fix nearest volcano

* Testcase docs update

* Testcase template: put title at the top and remove header row

* Docs correction

* New geonearestpoint test case

* Make test cases editable

* Test case default template: Always put "Output" tab first

* Initial Commit

* HttpClient object shouldn't need to know about events

* Add support for cancelling HTTP requests

* Make the number of outstanding HTTP requests available in a state tiddler

* Add a network activity button

Click it to cancel outstanding requests

* WIP

* Fix typo

Thanks @btheado

Co-authored-by: btheado <brian.theado@gmail.com>

* Data widget: parse carriage returns in compound tiddlers

* Fix crash when cancelling more than one HTTP request

Thanks @saqimtiaz

* Further fixes to cancelling outstanding HTTP requests

* Don't have data widget rendering its own JSON

Making the data widget render its raw JSON (introduced in 683ec33004) was a bad idea as it messes up the innerwiki use of the data widget. Instead we use the testcase widget with a special template to render the raw JSON of the payload of a testcase, thus giving us a way to test the data widget

* Fix missed docs update

* Introduce geolayer widget for specifying layers for geomap

* Fix breaking tests

* Remove docs references to obsolete widgets

* Tests for geounion, geointersect and geodifference

* Support for multiple base layers

* Make the layers control visible which allows the base layer to be chosen, and individual overlay layers to be hidden
* Add tiddlers tagged $:/tags/GeoBaseLayer to define some useful map base layers
* Add geobaselayer widget to define base layers

* Add a satellite base layer and another terrain base layer

* Add a note where to get more base layers

* Docs update

* Geomap widget: fix default base layer rendering

* Add startPosition and layersPanel attributes to geomap widget

* Update geolayer widget docs with missing attributes

* Add interactive demos for geounion, geodifference, geointersection

* Open geofeature and geomarker maps on the bounds of their content

* Move settings from demo into plugin

Because now the Flickr macros are part of the plugin

* Icon for geospatial plugin

* Fix missing body

* Flickr Demo typo

* Docs update

* Add support for draggable markers

* Removed accidentally committed file

* Remove unwanted log

* Add support for tm-request-geolocation message

* Fix typo

* Fix bug when fitting to non-extistent bounds

* Update main wiki greeting

* Use "Flickr helpers" instead of "Flickr macros"

* File renames for 05d3271603

* Fix testcase widget example

Thanks @btheado

* Fix testcase widget refreshing

* Fix failing tests from 03b6413c7a

* Docs: Clarify that template must be in the payload

* Testcase widget: Exclude tab state tiddlers

See https://github.com/Jermolene/TiddlyWiki5/pull/7406#discussion_r1327971965

Thanks @btheado

* Remove obsolete setquerystring operator

Instead we have the query- parameters to the http request message

* Remove obsolete change to --setfield command

* Fix tiddler name typo

* Initial Commit

* Add note to preview build

* Fix whitespace and indenting

Thanks @pmario

* Fix crash with unset $tiddler attribute on <$data> widget

Thanks @CodaCodr

* Remove Stamen baselayers

They have stopped making them available for free - see https://maps.stamen.com/stadia-partnership/

* Disable test that won't run in browser CI

* Disable broken tests

* Update olc-encode.tid (#7885)

Correct spelling

* Don't duplicate "description" field in test cases

* Use different background colours for nested testcase widgets

* Extend the testcase widget to run tests

* Add testcases to control panel

* Add a view template body template to render testcase tiddlers

* Test edition should display testcases

* Whitespace fixes

* Make testcase tiddler tempalte link to itself

* Styling tweaks

* Docs improvements

* Styling tweaks

* Run the new tw5.com testcases in the test edition

* Update data widget to display its content in JSON

* Add testcase convenience procedure

* Clearer testcases for data widget, and docs tweaks

* Don't expect our intentionally failing test to pass

* Extend testcase default template so that the display format can be chosen

It is selected by setting the variable "displayFormat"

* DataWidget docs typo

* Mark Geospatial plugin as experimental

* Update to Leaflet v1.9.4

* Remove unneeded template

Left over from when the testcase widget was first implemented

* Don't hide the volcanoes of the world data set

* Update Flickr demo docs

* Fix subtle typo that was preventing popups from working correctly

* Go back to hiding the volcanoes of the world by default

Too much data for a small device now that the markers are displayed correctly

* Clarify docs for tm-request-location

* Update modified testcase from master

* Prepare for merging

---------

Co-authored-by: btheado <brian.theado@gmail.com>
Co-authored-by: Drevarr <drevarr@gmail.com>
2024-05-31 13:31:30 +01:00
Jeremy Ruston
ac855b0065 Improve refreshing of the data widget 2024-05-31 12:43:21 +01:00
Jeremy Ruston
7a50b2b554 Fix tm-copy-to-clipboard crash
See https://github.com/Jermolene/TiddlyWiki5/pull/8211#issuecomment-2138600286
2024-05-30 17:58:07 +01:00
Matt Lauber
65d9384261 Add useDefaultHeaders flag to tm-http-request (V2) (#8225)
* Add defaultHeaders flag that controls helpful default heders that can sometimes interfere with apis

* Bump version number

* rename parameter to useDefaultHeaders, and catch one location where the default was not being set properly.

* Use a better comparision operator

* remove bad change
2024-05-30 17:53:22 +01:00
Jeremy Ruston
da8d4ecfae Tweak #8214 by avoiding renaming boot.css
Improves the continuity of our GitHub history
2024-05-30 17:29:12 +01:00
Bram Chen
6a84ae332d Update chinese language files (#8224)
* Improve traditional chinese translation of "Standard Layout"
2024-05-30 08:27:55 +01:00
Jeremy Ruston
e35793bc38 Update release note 2024-05-29 21:29:47 +01:00
lin onetwo
3af2a0ae6f Rename default layout to "Standard Layout" (#8172)
* refactor: default PageTemplate -> DefaultLayout

* refactor: DefaultLayout -> StandardLayout

* i18n: Default ~PageTemplate -> Standard Layout
2024-05-29 16:47:52 +01:00
Jeremy Ruston
f3614c1e47 Simplify splash screen 2024-05-29 15:14:13 +01:00
Jeremy Ruston
78fb4a2c1d Custom copy clipboard notifications (#8211)
* Initial Commit

* Improve plugin tests

Fixes #8209

* Fix RSOE

* Fix extraneous copy to clipboard at startup
2024-05-29 15:06:33 +01:00
Jeremy Ruston
928f3fc413 Revert "Add defaultHeaders flag that controls helpful default heders that can sometimes interfere with apis (#8152)"
This reverts commit 6910be795f.
2024-05-29 13:55:32 +01:00
lin onetwo
47029bac9e Fix/backlink binary (#8098)
* fix: prevent check binary tiddler for backlink

* refactor: test for backlink
2024-05-29 11:53:44 +01:00
Matt Lauber
6910be795f Add defaultHeaders flag that controls helpful default heders that can sometimes interfere with apis (#8152)
* Add defaultHeaders flag that controls helpful default heders that can sometimes interfere with apis

* Bump version number
2024-05-29 11:42:50 +01:00
yaisog
cd2d4b3eb7 Clarify handling of title lists in ActionListopsWidget documentation (#8184)
* Improve section on subfilter expressions

* Further refinement of the info box.
2024-05-29 11:39:41 +01:00
Mario Pietsch
5856bd8342 Fix get variable info params (#8179)
* return params for every variable type

* add tests for widget getVariableInfo.params

* make param values different to names
2024-05-29 11:14:21 +01:00
Jeremy Ruston
15001020fe Update release note 2024-05-29 10:33:08 +01:00
Jeremy Ruston
0f17ff0f6c Testcase widget should treat test cases without a test as if they had passed 2024-05-29 10:25:34 +01:00
Jeremy Ruston
4274e8fd7f Fix tests broken in 1b6e8e1a79 2024-05-29 08:36:52 +01:00
Jeremy Ruston
1b6e8e1a79 Testcase widget should only run tests if expected results are specified
Fixes #8218
2024-05-29 08:28:34 +01:00
Jeremy Ruston
9756b79683 Fix currentTiddler in testcase renderings
See eb4e9d86ac (r142368175)
2024-05-28 14:30:59 +01:00
Jeremy Ruston
613ee13294 Testcase docs: add note about description field overwriting Description payload tiddler 2024-05-28 13:37:50 +01:00
Jeremy Ruston
b5bd4c9673 Fix testcase heading link destination 2024-05-28 13:22:44 +01:00
Jeremy Ruston
2312cd3301 Improve wording for failing test
See https://talk.tiddlywiki.org/t/introducing-the-testcase-widget/9847/11
2024-05-28 13:17:35 +01:00
lin onetwo
dbe912ba5d Fix boot.css bug from #8099 (#8214) 2024-05-27 12:45:29 +01:00
lin onetwo
a463783283 Fix/sjcl variable (#8099)
* refactor: use files to add prefix

* fix: always use $tw.sjcl

* refactor: move sjcl to lib/sjcl

* fix: require sjcl in lib/

* refactor: move sjcl.js back into /boot
2024-05-26 15:56:25 +01:00
Bram Chen
e3f9be995b Update chinese language files (#8204)
* Add chinese description for field `stability`
2024-05-25 12:12:19 +01:00
Cameron Fischer
e932b09016 More robust infinite recursion handling with custom exception (#7882)
* Introduced preliminary idea for infinite recurse exception

* Better handling of infinite recursion

But it could be better still...

* the TransclusionError is a proper error

Moved the magic number to be on the error's class. Not sure if that's
a great idea.

* Fixed minor minor issue that came up in conflict

The minor fix to the jasmine regexp that escaped a '+' somehow
broke some random test.
2024-05-25 10:56:19 +01:00
Mario Pietsch
074d35c388 Make the linter happy (#8210) 2024-05-23 18:13:52 +01:00
Jeremy Ruston
18d23048da Improve plugin test implementation 2024-05-23 16:47:28 +01:00
Jeremy Ruston
970f829c83 Fix bug in f9df4f0741 2024-05-23 16:34:24 +01:00
Jeremy Ruston
f9df4f0741 Plugin tests should only apply to core plugins
Hi @pmario could you kindly try this?

Fixes #8207
2024-05-23 16:28:08 +01:00
Jeremy Ruston
fc0de10cd1 Fix plugin library URLs 2024-05-22 11:50:15 +01:00
Cameron Fischer
01b2e864c1 Fixed issue with fakedome TW_Node inheritence (#8195) 2024-05-21 22:02:37 +01:00
Jeremy Ruston
0adc6024d1 Fix plugin library URLs broken by #8198
Thanks @pmario
2024-05-21 18:33:04 +01:00
Jeremy Ruston
4d2aa1dc95 Fix plugin tests in the browser 2024-05-21 11:26:24 +01:00
Jeremy Ruston
5aa3646df5 Add plugin stability badges (#8198)
* Initial Commit

* Fix plugin library URL

* Need to set plugin library location for prerelease

* Styling tweaks

* Docs

* Add tests that the core plugins all have a valid stability field
2024-05-21 11:22:39 +01:00
Erwan
3e27093c94 sign the CLA (#8202)
Signing the CLA for CyberFoxar
2024-05-20 23:05:53 +01:00
Bram Chen
71d77fe428 Update chinese language files (#8200)
* Update chinese language files

* Add chinese translations for the new `<$testcase>` widget

* Update chinese language files

* Add chinese translations for the new <$testcase> widget
2024-05-20 16:32:55 +01:00
Jeremy Ruston
ece8b0ee01 Add <$testcase> widget (#7817)
* Initial Commit

* Add note to preview build

* Fix whitespace and indenting

Thanks @pmario

* Fix crash with unset $tiddler attribute on <$data> widget

Thanks @CodaCodr

* Don't duplicate "description" field in test cases

* Use different background colours for nested testcase widgets

* Extend the testcase widget to run tests

* Add testcases to control panel

* Add a view template body template to render testcase tiddlers

* Test edition should display testcases

* Whitespace fixes

* Make testcase tiddler tempalte link to itself

* Styling tweaks

* Docs improvements

* Styling tweaks

* Run the new tw5.com testcases in the test edition

* Update data widget to display its content in JSON

* Add testcase convenience procedure

* Clearer testcases for data widget, and docs tweaks

* Don't expect our intentionally failing test to pass

* Extend testcase default template so that the display format can be chosen

It is selected by setting the variable "displayFormat"

* DataWidget docs typo

* Fix data widget not refreshing

* Links in testcase output switch to the tab containing that tiddler

Thanks to @btheado for the suggestion

* Docs update for 648855e8a5

* Wording tweak

* Add support for narrative tiddlers in test cases

* Documentation improvements

* Cleanup comments

* Remove obsolete code comments

* Simplify template

* Docs update

* Rename $:/core/ui/testcases/DefaultTemplate/SourceTabs from $:/core/ui/testcases/DefaultTemplate/Source

* Use the view template body for failing tests

* Don't reference the geospatial plugin

* "Test case" should be two words

* Fix handling of currentTiddler variable

Fixes problem reported by @btheado in https://github.com/Jermolene/TiddlyWiki5/pull/7817#issuecomment-2103704468

* Prepare for merging
2024-05-20 11:30:30 +01:00
475 changed files with 24925 additions and 908 deletions

View File

@@ -5,7 +5,7 @@
# Default to the current version number for building the plugin library
if [ -z "$TW5_BUILD_VERSION" ]; then
TW5_BUILD_VERSION=v5.3.3
TW5_BUILD_VERSION=v5.3.5
fi
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
@@ -393,6 +393,17 @@ node $TW5_BUILD_TIDDLYWIKI \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/highlight/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/geospatial/index.html Demo wiki with geospatial plugin
# /plugins/tiddlywiki/geospatial/empty.html Empty wiki with geospatial plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/geospatialdemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/geospatial/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/geospatial/empty.html text/plain \
|| exit 1
######################################################
#
# Language editions

View File

@@ -142,15 +142,15 @@ $tw.utils.each = function(object,callback) {
var next,f,length;
if(object) {
if(Object.prototype.toString.call(object) == "[object Array]") {
for (f=0, length=object.length; f<length; f++) {
for(f=0, length=object.length; f<length; f++) {
next = callback(object[f],f,object);
if(next === false) {
break;
}
}
}
} else {
var keys = Object.keys(object);
for (f=0, length=keys.length; f<length; f++) {
for(f=0, length=keys.length; f<length; f++) {
var key = keys[f];
next = callback(object[key],key,object);
if(next === false) {
@@ -275,7 +275,7 @@ Extend an object with the properties from a list of source objects
$tw.utils.extend = function(object /*, sourceObjectList */) {
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
if(source) {
for (var p in source) {
for(var p in source) {
object[p] = source[p];
}
}
@@ -289,7 +289,7 @@ Fill in any null or undefined properties of an object with the properties from a
$tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
$tw.utils.each(Array.prototype.slice.call(arguments,1),function(source) {
if(source) {
for (var p in source) {
for(var p in source) {
if(object[p] === null || object[p] === undefined) {
object[p] = source[p];
}
@@ -893,8 +893,8 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
} else {
/*
CommonJS optional require.main property:
In a browser we offer a fake main module which points back to the boot function
(Theoretically, this may allow TW to eventually load itself as a module in the browser)
In a browser we offer a fake main module which points back to the boot function
(Theoretically, this may allow TW to eventually load itself as a module in the browser)
*/
Object.defineProperty(sandbox.require, "main", {
value: (typeof(require) !== "undefined") ? require.main : {TiddlyWiki: _boot},
@@ -936,9 +936,9 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
moduleInfo.exports = moduleInfo.definition;
}
} catch(e) {
if (e instanceof SyntaxError) {
if(e instanceof SyntaxError) {
var line = e.lineNumber || e.line; // Firefox || Safari
if (typeof(line) != "undefined" && line !== null) {
if(typeof(line) != "undefined" && line !== null) {
$tw.utils.error("Syntax error in boot module " + name + ":" + line + ":\n" + e.stack);
} else if(!$tw.browser) {
// this is the only way to get node.js to display the line at which the syntax error appeared,
@@ -1533,7 +1533,7 @@ Define all modules stored in ordinary tiddlers
$tw.Wiki.prototype.defineTiddlerModules = function() {
this.each(function(tiddler,title) {
if(tiddler.hasField("module-type")) {
switch (tiddler.fields.type) {
switch(tiddler.fields.type) {
case "application/javascript":
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
if(!$tw.utils.hop($tw.modules.titles,tiddler.fields.title)) {
@@ -2043,7 +2043,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
arrayOfFiles = arrayOfFiles || [];
var files = fs.readdirSync(dirPath);
files.forEach(function(file) {
if (recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
if(recurse && fs.statSync(dirPath + path.sep + file).isDirectory()) {
arrayOfFiles = getAllFiles(dirPath + path.sep + file, recurse, arrayOfFiles);
} else if(fs.statSync(dirPath + path.sep + file).isFile()){
arrayOfFiles.push(path.join(dirPath, path.sep, file));
@@ -2188,13 +2188,16 @@ Returns an array of search paths
*/
$tw.getLibraryItemSearchPaths = function(libraryPath,envVar) {
var pluginPaths = [path.resolve($tw.boot.corePath,libraryPath)],
env;
if(envVar) {
env = process.env[envVar];
if(env) {
env.split(path.delimiter).map(function(item) {
if(item) {
pluginPaths.push(item);
}
});
if(env) {
env.split(path.delimiter).map(function(item) {
if(item) {
pluginPaths.push(item);
}
});
}
}
return pluginPaths;
};
@@ -2280,7 +2283,7 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
}
$tw.wiki.addTiddlers(tiddlerFile.tiddlers);
});
if ($tw.boot.wikiPath == wikiPath) {
if($tw.boot.wikiPath == wikiPath) {
// Save the original tiddler file locations if requested
var output = {}, relativePath, fileInfo;
for(var title in $tw.boot.files) {
@@ -2634,14 +2637,14 @@ $tw.boot.doesTaskMatchPlatform = function(taskModule) {
var platforms = taskModule.platforms;
if(platforms) {
for(var t=0; t<platforms.length; t++) {
switch (platforms[t]) {
switch(platforms[t]) {
case "browser":
if ($tw.browser) {
if($tw.browser) {
return true;
}
break;
case "node":
if ($tw.node) {
if($tw.node) {
return true;
}
break;
@@ -2724,7 +2727,7 @@ Invoke the hook by key
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
var args = Array.prototype.slice.call(arguments,1);
if($tw.utils.hop($tw.hooks.names,hookName)) {
for (var i = 0; i < $tw.hooks.names[hookName].length; i++) {
for(var i = 0; i < $tw.hooks.names[hookName].length; i++) {
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
}
}

View File

@@ -1,3 +0,0 @@
title: $:/library/sjcl.js
type: application/javascript
library: yes

32
boot/tiddlywiki.files Normal file
View File

@@ -0,0 +1,32 @@
{
"tiddlers": [
{
"file": "sjcl.js",
"fields": {
"title": "$:/library/sjcl.js",
"type": "application/javascript",
"library": "yes"
},
"prefix": "(function(define) {\n",
"suffix": "\n})(function (_,defined){window.sjcl = defined()})\n"
},
{
"file": "boot.js",
"fields": {
"title": "$:/boot/boot.js",
"type": "application/javascript"
}
},
{
"file": "bootprefix.js",
"fields": {
"title": "$:/boot/bootprefix.js",
"type": "application/javascript"
}
},
{
"file": "boot.css.tid",
"isTiddlerFile": true
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
title: $:/core/images/input-button
tags: $:/tags/Image
\parameters (size:"22pt")
<svg width=<<size>> height=<<size>> class="tc-image-input-button tc-image-button" viewBox="0 0 22 22"><path d="M1.375 22h19.249c.365 0 .716-.145.973-.404v.001c.258-.257.404-.607.403-.972v-11a1.376 1.376 0 0 0-2.75 0v9.625H2.75V9.625a1.376 1.376 0 0 0-2.75 0v11C0 21.384.617 22 1.375 22Z"/><path d="m9.732 11.904-1.541-1.541a1.375 1.375 0 1 0-1.944 1.944l3.887 3.888c.258.258.608.402.973.402h-.001c.353 0 .705-.134.974-.402l3.888-3.889a1.376 1.376 0 0 0 .001-1.944 1.377 1.377 0 0 0-1.946 0l-1.541 1.542V1.376a1.375 1.375 0 1 0-2.75 0v10.528Z"/></svg>

View File

@@ -1,7 +1,7 @@
title: $:/core/images/default-layout
title: $:/core/images/standard-layout
tags: $:/tags/Image
\parameters (size:"22pt")
<svg width=<<size>> height=<<size>> class="tc-image-default-layout tc-image-button" viewBox="0 0 128 128">
<svg width=<<size>> height=<<size>> class="tc-image-standard-layout tc-image-button" viewBox="0 0 128 128">
<path d="M71.93 72A8.07 8.07 0 0 1 80 80.07v7.86A8.071 8.071 0 0 1 71.93 96H8.07A8.067 8.067 0 0 1 0 87.93v-7.86A8.072 8.072 0 0 1 8.07 72h63.86Zm0 32a8.07 8.07 0 0 1 8.07 8.07v7.86a8.071 8.071 0 0 1-8.07 8.07H8.07A8.067 8.067 0 0 1 0 119.93v-7.86A8.072 8.072 0 0 1 8.07 104h63.86Zm0-104A8.068 8.068 0 0 1 80 8.07v47.86A8.073 8.073 0 0 1 71.93 64H8.07A8.07 8.07 0 0 1 0 55.93V8.07A8.072 8.072 0 0 1 8.07 0h63.86Zm48 0c2.14 0 4.193.85 5.706 2.364A8.067 8.067 0 0 1 128 8.07v111.86c0 2.14-.85 4.193-2.364 5.706A8.067 8.067 0 0 1 119.93 128H96.07c-2.14 0-4.193-.85-5.706-2.364A8.067 8.067 0 0 1 88 119.93V8.07c0-2.14.85-4.193 2.364-5.706A8.067 8.067 0 0 1 96.07 0h23.86ZM116 24h-16a3.995 3.995 0 0 0-2.828 1.172 3.995 3.995 0 0 0 0 5.656A3.995 3.995 0 0 0 100 32h16a3.995 3.995 0 0 0 2.828-1.172 3.995 3.995 0 0 0 0-5.656A3.995 3.995 0 0 0 116 24Z"/>
</svg>

View File

@@ -104,6 +104,8 @@ ShowSideBar/Caption: show sidebar
ShowSideBar/Hint: Show sidebar
TagManager/Caption: tag manager
TagManager/Hint: Open tag manager
TestCaseImport/Caption: import tiddlers
TestCaseImport/Hint: Import tiddlers
Timestamp/Caption: timestamps
Timestamp/Hint: Choose whether modifications update timestamps
Timestamp/On/Caption: timestamps are on

View File

@@ -65,6 +65,10 @@ sidebar-tab-foreground-selected: Sidebar tab foreground for selected tabs
sidebar-tab-foreground: Sidebar tab foreground
sidebar-tiddler-link-foreground-hover: Sidebar tiddler link foreground hover
sidebar-tiddler-link-foreground: Sidebar tiddler link foreground
stability-stable: Badge for stability level "stable"
stability-experimental: Badge for stability level "experimental"
stability-deprecated: Badge for stability level "deprecated"
stability-legacy: Badge for stability level "legacy"
testcase-accent-level-1: Test case accent colour with no nesting
testcase-accent-level-2: Test case accent colour with 2nd level nesting
testcase-accent-level-3: Test case accent colour with 3rd level nesting or higher

View File

@@ -30,6 +30,7 @@ name: The human readable name associated with a plugin tiddler
parent-plugin: For a plugin, specifies which plugin of which it is a sub-plugin
plugin-priority: A numerical value indicating the priority of a plugin tiddler
plugin-type: The type of plugin in a plugin tiddler
stability: The development status of a plugin: deprecated, experimental, stable, or legacy
revision: The revision of the tiddler held at the server
released: Date of a TiddlyWiki release
source: The source URL associated with a tiddler

View File

@@ -70,7 +70,7 @@ No: No
OfficialPluginLibrary: Official ~TiddlyWiki Plugin Library
OfficialPluginLibrary/Hint: The official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team.
PageTemplate/Description: the default ~TiddlyWiki layout
PageTemplate/Name: Default ~PageTemplate
PageTemplate/Name: Standard Layout
PluginReloadWarning: Please save {{$:/core/ui/Buttons/save-wiki}} and reload {{$:/core/ui/Buttons/refresh}} to allow changes to ~JavaScript plugins to take effect
RecentChanges/DateFormat: DDth MMM YYYY
Shortcuts/Input/AdvancedSearch/Hint: Open the ~AdvancedSearch panel from within the sidebar search field

View File

@@ -27,33 +27,8 @@ var Command = function(params,commander,callback) {
Command.prototype.execute = function() {
var wiki = this.commander.wiki,
fs = require("fs"),
path = require("path"),
upgradeLibraryTitle = this.params[0] || UPGRADE_LIBRARY_TITLE,
tiddlers = {};
// Collect up the library plugins
var collectPlugins = function(folder) {
var pluginFolders = $tw.utils.getSubdirectories(folder) || [];
for(var p=0; p<pluginFolders.length; p++) {
if(!$tw.boot.excludeRegExp.test(pluginFolders[p])) {
pluginFields = $tw.loadPluginFolder(path.resolve(folder,"./" + pluginFolders[p]));
if(pluginFields && pluginFields.title) {
tiddlers[pluginFields.title] = pluginFields;
}
}
}
},
collectPublisherPlugins = function(folder) {
var publisherFolders = $tw.utils.getSubdirectories(folder) || [];
for(var t=0; t<publisherFolders.length; t++) {
if(!$tw.boot.excludeRegExp.test(publisherFolders[t])) {
collectPlugins(path.resolve(folder,"./" + publisherFolders[t]));
}
}
};
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,$tw.config.pluginsEnvVar),collectPublisherPlugins);
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,$tw.config.themesEnvVar),collectPublisherPlugins);
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,$tw.config.languagesEnvVar),collectPlugins);
tiddlers = $tw.utils.getAllPlugins();
// Save the upgrade library tiddler
var pluginFields = {
title: upgradeLibraryTitle,

View File

@@ -16,11 +16,11 @@ Filter operator for returning all the backtranscludes from a tiddler
Export our filter function
*/
exports.backtranscludes = function(source,operator,options) {
var results = [];
var results = new $tw.utils.LinkedList();
source(function(tiddler,title) {
$tw.utils.pushTop(results,options.wiki.getTiddlerBacktranscludes(title));
results.pushTop(options.wiki.getTiddlerBacktranscludes(title));
});
return results;
return results.makeTiddlerIterator(options.wiki);
};
})();

View File

@@ -127,7 +127,7 @@ function diffPartsToChars(text1,text2,mode) {
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
chars += String.fromCharCode(lineHash[line]);
} else {
if (lineArrayLength == maxLines) {
if(lineArrayLength == maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
@@ -217,7 +217,10 @@ exports.splitregexp = function(source,operator,options) {
return ["RegExp error: " + ex];
}
source(function(tiddler,title) {
Array.prototype.push.apply(result,title.split(regExp));
var parts = title.split(regExp).map(function(part){
return part || ""; // make sure it's a string
});
Array.prototype.push.apply(result,parts);
});
return result;
};
@@ -264,7 +267,7 @@ exports.pad = function(source,operator,options) {
} else {
var padString = "",
padStringLength = targetLength - title.length;
while (padStringLength > padString.length) {
while(padStringLength > padString.length) {
padString += fill;
}
//make sure we do not exceed the specified length

View File

@@ -20,7 +20,7 @@ exports.transcludes = function(source,operator,options) {
source(function(tiddler,title) {
results.pushTop(options.wiki.getTiddlerTranscludes(title));
});
return results.toArray();
return results.makeTiddlerIterator(options.wiki);
};
})();

View File

@@ -70,9 +70,12 @@ BackSubIndexer.prototype.rebuild = function() {
* Get things that is being referenced in the text, e.g. tiddler names in the link syntax.
*/
BackSubIndexer.prototype._getTarget = function(tiddler) {
if(this.wiki.isBinaryTiddler(tiddler.fields.text)) {
return [];
}
var parser = this.wiki.parseText(tiddler.fields.type, tiddler.fields.text, {});
if(parser) {
return this.wiki[this.extractor](parser.tree);
return this.wiki[this.extractor](parser.tree, tiddler.fields.title);
}
return [];
}

View File

@@ -114,7 +114,7 @@ exports.parseStringLiteral = function(source,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]
match[2] !== undefined ? match[2] : match[3]
);
node.end = pos + match[0].length;
return node;

View File

@@ -29,13 +29,16 @@ exports.init = function(parser) {
exports.parse = function() {
var reEnd = /(\r?\n```$)/mg;
var languageStart = this.parser.pos + 3,
languageEnd = languageStart + this.match[1].length;
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
// Look for the end of the block
reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source),
text;
text,
codeStart = this.parser.pos;
// Process the block
if(match) {
text = this.parser.source.substring(this.parser.pos,match.index);
@@ -48,8 +51,8 @@ exports.parse = function() {
return [{
type: "codeblock",
attributes: {
code: {type: "string", value: text},
language: {type: "string", value: this.match[1]}
code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
}
}];
};

View File

@@ -33,7 +33,8 @@ exports.parse = function() {
// Look for the end marker
reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source),
text;
text,
start = this.parser.pos;
// Process the text
if(match) {
text = this.parser.source.substring(this.parser.pos,match.index);
@@ -47,7 +48,9 @@ exports.parse = function() {
tag: "code",
children: [{
type: "text",
text: text
text: text,
start: start,
end: this.parser.pos
}]
}];
};

View File

@@ -31,6 +31,7 @@ exports.init = function(parser) {
exports.parse = function() {
// Move past the match
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex;
// Create the link unless it is suppressed
if(this.match[0].substr(0,1) === "~") {
@@ -46,7 +47,7 @@ exports.parse = function() {
rel: {type: "string", value: "noopener noreferrer"}
},
children: [{
type: "text", text: this.match[0]
type: "text", text: this.match[0], start: start, end: this.parser.pos
}]
}];
}

View File

@@ -31,6 +31,16 @@ exports.init = function(parser) {
exports.parse = function() {
// Move past the match
var filterStart = this.parser.pos + 3;
var filterEnd = filterStart + this.match[1].length;
var toolTipStart = filterEnd + 1;
var toolTipEnd = toolTipStart + (this.match[2] ? this.match[2].length : 0);
var templateStart = toolTipEnd + 2;
var templateEnd = templateStart + (this.match[3] ? this.match[3].length : 0);
var styleStart = templateEnd + 2;
var styleEnd = styleStart + (this.match[4] ? this.match[4].length : 0);
var classesStart = styleEnd + 1;
var classesEnd = classesStart + (this.match[5] ? this.match[5].length : 0);
this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details
var filter = this.match[1],
@@ -42,21 +52,21 @@ exports.parse = function() {
var node = {
type: "list",
attributes: {
filter: {type: "string", value: filter}
filter: {type: "string", value: filter, start: filterStart, end: filterEnd},
},
isBlock: true
};
if(tooltip) {
node.attributes.tooltip = {type: "string", value: tooltip};
node.attributes.tooltip = {type: "string", value: tooltip, start: toolTipStart, end: toolTipEnd};
}
if(template) {
node.attributes.template = {type: "string", value: template};
node.attributes.template = {type: "string", value: template, start: templateStart, end: templateEnd};
}
if(style) {
node.attributes.style = {type: "string", value: style};
node.attributes.style = {type: "string", value: style, start: styleStart, end: styleEnd};
}
if(classes) {
node.attributes.itemClass = {type: "string", value: classes.split(".").join(" ")};
node.attributes.itemClass = {type: "string", value: classes.split(".").join(" "), start: classesStart, end: classesEnd};
}
return [node];
};

View File

@@ -30,6 +30,16 @@ exports.init = function(parser) {
};
exports.parse = function() {
var filterStart = this.parser.pos + 3;
var filterEnd = filterStart + this.match[1].length;
var toolTipStart = filterEnd + 1;
var toolTipEnd = toolTipStart + (this.match[2] ? this.match[2].length : 0);
var templateStart = toolTipEnd + 2;
var templateEnd = templateStart + (this.match[3] ? this.match[3].length : 0);
var styleStart = templateEnd + 2;
var styleEnd = styleStart + (this.match[4] ? this.match[4].length : 0);
var classesStart = styleEnd + 1;
var classesEnd = classesStart + (this.match[5] ? this.match[5].length : 0);
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details
@@ -42,20 +52,20 @@ exports.parse = function() {
var node = {
type: "list",
attributes: {
filter: {type: "string", value: filter}
filter: {type: "string", value: filter, start: filterStart, end: filterEnd},
}
};
if(tooltip) {
node.attributes.tooltip = {type: "string", value: tooltip};
node.attributes.tooltip = {type: "string", value: tooltip, start: toolTipStart, end: toolTipEnd};
}
if(template) {
node.attributes.template = {type: "string", value: template};
node.attributes.template = {type: "string", value: template, start: templateStart, end: templateEnd};
}
if(style) {
node.attributes.style = {type: "string", value: style};
node.attributes.style = {type: "string", value: style, start: styleStart, end: styleEnd};
}
if(classes) {
node.attributes.itemClass = {type: "string", value: classes.split(".").join(" ")};
node.attributes.itemClass = {type: "string", value: classes.split(".").join(" "), start: classesStart, end: classesEnd};
}
return [node];
};

View File

@@ -45,10 +45,11 @@ exports.parse = function() {
reEnd.lastIndex = this.parser.pos;
match = reEnd.exec(this.parser.source);
if(match) {
var start = this.parser.pos;
this.parser.pos = reEnd.lastIndex;
// Add a line break if the terminator was a line break
if(match[2]) {
tree.push({type: "element", tag: "br"});
tree.push({type: "element", tag: "br", start: start, end: this.parser.pos});
}
}
} while(match && !match[1]);

View File

@@ -30,15 +30,17 @@ exports.parse = function() {
// Move past the !s
this.parser.pos = this.matchRegExp.lastIndex;
// Parse any classes, whitespace and then the heading itself
var classStart = this.parser.pos;
var classes = this.parser.parseClasses();
var classEnd = this.parser.pos;
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var tree = this.parser.parseInlineRun(/(\r?\n)/mg);
// Return the heading
return [{
type: "element",
tag: "h" + headingLevel,
tag: "h" + headingLevel,
attributes: {
"class": {type: "string", value: classes.join(" ")}
"class": {type: "string", value: classes.join(" "), start: classStart, end: classEnd}
},
children: tree
}];

View File

@@ -44,6 +44,10 @@ Parse the most recent match
exports.parse = function() {
// Retrieve the most recent match so that recursive calls don't overwrite it
var tag = this.nextTag;
if (!tag.isSelfClosing) {
tag.openTagStart = tag.start;
tag.openTagEnd = tag.end;
}
this.nextTag = null;
// Advance the parser position to past the tag
this.parser.pos = tag.end;
@@ -60,6 +64,27 @@ exports.parse = function() {
var reEnd = new RegExp("(" + reEndString + ")","mg");
tag.children = this.parser.parseInlineRun(reEnd,{eatTerminator: true});
}
tag.end = this.parser.pos;
tag.closeTagEnd = tag.end;
if (tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== '>') {
tag.closeTagStart = tag.end;
} else {
tag.closeTagStart = tag.closeTagEnd - 2;
var closeTagMinPos = tag.children.length > 0 ? tag.children[tag.children.length-1].end : tag.openTagEnd;
if (!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
while (tag.closeTagStart >= closeTagMinPos) {
var char = this.parser.source[tag.closeTagStart];
if (char === '>') {
tag.closeTagStart = -1;
break;
}
if (char === '<') break;
tag.closeTagStart -= 1;
}
if (tag.closeTagStart < closeTagMinPos) {
tag.closeTagStart = tag.end;
}
}
}
// Return the tag
return [tag];

View File

@@ -122,9 +122,9 @@ exports.parseImage = function(source,pos) {
}
pos = token.end;
if(token.match[1]) {
node.attributes.tooltip = {type: "string", value: token.match[1].trim()};
node.attributes.tooltip = {type: "string", value: token.match[1].trim(),start: token.start,end:token.start + token.match[1].length - 1};
}
node.attributes.source = {type: "string", value: (token.match[2] || "").trim()};
node.attributes.source = {type: "string", value: (token.match[2] || "").trim(), start: token.start + (token.match[1] ? token.match[1].length : 0), end: token.end - 2};
// Update the end position
node.end = pos;
return node;

View File

@@ -38,13 +38,14 @@ exports.parse = function() {
// Parse the filter terminated by a line break
var reMatch = /(.*)(?:$|\r?\n)/mg;
reMatch.lastIndex = this.parser.pos;
var filterStart = this.parser.source;
var match = reMatch.exec(this.parser.source);
this.parser.pos = reMatch.lastIndex;
// Parse tree nodes to return
return [{
type: "importvariables",
attributes: {
filter: {type: "string", value: match[1]}
filter: {type: "string", value: match[1], start: filterStart, end: this.parser.pos}
},
children: []
}];

View File

@@ -74,6 +74,7 @@ exports.parse = function() {
// Match the list marker
var reMatch = /([\*#;:>]+)/mg;
reMatch.lastIndex = this.parser.pos;
var start = this.parser.pos;
var match = reMatch.exec(this.parser.source);
if(!match || match.index !== this.parser.pos) {
break;
@@ -94,9 +95,21 @@ exports.parse = function() {
}
// Construct the list element or reuse the previous one at this level
if(listStack.length <= t) {
var listElement = {type: "element", tag: listInfo.listTag, children: [
{type: "element", tag: listInfo.itemTag, children: []}
]};
var listElement = {
type: "element",
tag: listInfo.listTag,
children: [
{
type: "element",
tag: listInfo.itemTag,
children: [],
start: start,
end: this.parser.pos,
}
],
start: start,
end: this.parser.pos,
};
// Link this list element into the last child item of the parent list item
if(t) {
var prevListItem = listStack[t-1].children[listStack[t-1].children.length-1];
@@ -105,21 +118,33 @@ exports.parse = function() {
// Save this element in the stack
listStack[t] = listElement;
} else if(t === (match[0].length - 1)) {
listStack[t].children.push({type: "element", tag: listInfo.itemTag, children: []});
listStack[t].children.push({
type: "element",
tag: listInfo.itemTag,
children: [],
start: start,
end: this.parser.pos,
});
}
}
if(listStack.length > match[0].length) {
listStack.splice(match[0].length,listStack.length - match[0].length);
}
// Process the body of the list item into the last list item
var classStart = this.parser.pos;
var lastListChildren = listStack[listStack.length-1].children,
lastListItem = lastListChildren[lastListChildren.length-1],
classes = this.parser.parseClasses();
var classEnd = this.parser.pos;
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var tree = this.parser.parseInlineRun(/(\r?\n)/mg);
lastListItem.children.push.apply(lastListItem.children,tree);
lastListItem.end = this.parser.pos;
listStack[listStack.length-1].end = this.parser.pos;
if(classes.length > 0) {
$tw.utils.addClassToParseTreeNode(lastListItem,classes.join(" "));
lastListItem.attributes.class.start = classStart;
lastListItem.attributes.class.end = classEnd;
}
// Consume any whitespace following the list item
this.parser.skipWhitespace();

View File

@@ -96,15 +96,20 @@ exports.parseLink = function(source,pos) {
splitPos = null;
}
// Pull out the tooltip and URL
var tooltip, URL;
var tooltip, URL, urlStart;
textNode.start = pos;
if(splitPos) {
urlStart = splitPos + 1;
URL = source.substring(splitPos + 1,closePos).trim();
textNode.text = source.substring(pos,splitPos).trim();
textNode.end = splitPos;
} else {
urlStart = pos;
URL = source.substring(pos,closePos).trim();
textNode.text = URL;
textNode.end = closePos;
}
node.attributes.href = {type: "string", value: URL};
node.attributes.href = {type: "string", value: URL, start: urlStart, end: closePos};
node.attributes.target = {type: "string", value: "_blank"};
node.attributes.rel = {type: "string", value: "noopener noreferrer"};
// Update the end position

View File

@@ -29,32 +29,39 @@ exports.init = function(parser) {
exports.parse = function() {
// Move past the match
var start = this.parser.pos + 2;
this.parser.pos = this.matchRegExp.lastIndex;
// Process the link
var text = this.match[1],
link = this.match[2] || text;
link = this.match[2] || text,
textEndPos = this.parser.source.indexOf("|", start);
if (textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
textEndPos = this.matchRegExp.lastIndex - 2;
}
var linkStart = this.match[2] ? (start + this.match[1].length + 1) : start;
var linkEnd = linkStart + link.length;
if($tw.utils.isLinkExternal(link)) {
return [{
type: "element",
tag: "a",
attributes: {
href: {type: "string", value: link},
href: {type: "string", value: link, start: linkStart, end: linkEnd},
"class": {type: "string", value: "tc-tiddlylink-external"},
target: {type: "string", value: "_blank"},
rel: {type: "string", value: "noopener noreferrer"}
},
children: [{
type: "text", text: text
type: "text", text: text, start: start, end: textEndPos
}]
}];
} else {
return [{
type: "link",
attributes: {
to: {type: "string", value: link}
to: {type: "string", value: link, start: linkStart, end: linkEnd}
},
children: [{
type: "text", text: text
type: "text", text: text, start: start, end: textEndPos
}]
}];
}

View File

@@ -28,9 +28,13 @@ exports.parse = function() {
// Move past the <s
this.parser.pos = this.matchRegExp.lastIndex;
// Parse any classes, whitespace and then the optional cite itself
var classStart = this.parser.pos;
classes.push.apply(classes, this.parser.parseClasses());
var classEnd = this.parser.pos;
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var citeStart = this.parser.pos;
var cite = this.parser.parseInlineRun(/(\r?\n)/mg);
var citeEnd = this.parser.pos;
// before handling the cite, parse the body of the quote
var tree = this.parser.parseBlocks(reEndString);
// If we got a cite, put it before the text
@@ -38,18 +42,24 @@ exports.parse = function() {
tree.unshift({
type: "element",
tag: "cite",
children: cite
children: cite,
start: citeStart,
end: citeEnd
});
}
// Parse any optional cite
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
citeStart = this.parser.pos;
cite = this.parser.parseInlineRun(/(\r?\n)/mg);
citeEnd = this.parser.pos;
// If we got a cite, push it
if(cite.length > 0) {
tree.push({
type: "element",
tag: "cite",
children: cite
children: cite,
start: citeStart,
end: citeEnd
});
}
// Return the blockquote element
@@ -57,7 +67,7 @@ exports.parse = function() {
type: "element",
tag: "blockquote",
attributes: {
class: { type: "string", value: classes.join(" ") },
class: { type: "string", value: classes.join(" "), start: classStart, end: classEnd },
},
children: tree
}];

View File

@@ -29,10 +29,11 @@ exports.init = function(parser) {
exports.parse = function() {
var match = this.match[0];
// Move past the match
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex;
// Create the link unless it is suppressed
if(match.substr(0,1) === "~") {
return [{type: "text", text: match.substr(1)}];
return [{type: "text", text: match.substr(1), start: start+1, end: this.parser.pos}];
} else {
return [{
type: "link",
@@ -41,10 +42,12 @@ exports.parse = function() {
},
children: [{
type: "text",
text: match
text: match,
start: start,
end: this.parser.pos
}]
}];
}
};
})();
})();

View File

@@ -150,7 +150,7 @@ exports.parse = function() {
} else {
// Otherwise, create a new row if this one is of a different type
if(rowType !== currRowType) {
rowContainer = {type: "element", tag: rowContainerTypes[rowType], children: []};
rowContainer = {type: "element", tag: rowContainerTypes[rowType], children: [], start: this.parser.pos, end: this.parser.pos};
table.children.push(rowContainer);
currRowType = rowType;
}
@@ -178,6 +178,7 @@ exports.parse = function() {
// Increment the row count
rowCount++;
}
rowContainer.end = this.parser.pos;
}
rowMatch = rowRegExp.exec(this.parser.source);
}

View File

@@ -46,6 +46,7 @@ exports.parse = function() {
renderType = this.match[2];
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
var start = this.parser.pos;
// Look for the end of the block
reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source),
@@ -74,7 +75,9 @@ exports.parse = function() {
tag: "pre",
children: [{
type: "text",
text: text
text: text,
start: start,
end: this.parser.pos
}]
}];
}

View File

@@ -36,6 +36,7 @@ exports.parse = function() {
// Get the details of the match
var linkText = this.match[0];
// Move past the macro call
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex;
// If the link starts with the unwikilink character then just output it as plain text
if(linkText.substr(0,1) === $tw.config.textPrimitives.unWikiLink) {
@@ -57,7 +58,9 @@ exports.parse = function() {
},
children: [{
type: "text",
text: linkText
text: linkText,
start: start,
end: this.parser.pos
}]
}];
};

View File

@@ -91,6 +91,11 @@ var WikiParser = function(type,text,options) {
} else {
topBranch.push.apply(topBranch,this.parseBlocks());
}
// Build rules' name map
this.usingRuleMap = {};
$tw.utils.each(this.pragmaRules, function (ruleInfo) { self.usingRuleMap[ruleInfo.rule.name] = Object.getPrototypeOf(ruleInfo.rule); });
$tw.utils.each(this.blockRules, function (ruleInfo) { self.usingRuleMap[ruleInfo.rule.name] = Object.getPrototypeOf(ruleInfo.rule); });
$tw.utils.each(this.inlineRules, function (ruleInfo) { self.usingRuleMap[ruleInfo.rule.name] = Object.getPrototypeOf(ruleInfo.rule); });
// Return the parse tree
};
@@ -209,8 +214,13 @@ WikiParser.prototype.parsePragmas = function() {
break;
}
// Process the pragma rule
var start = this.pos;
var subTree = nextMatch.rule.parse();
if(subTree.length > 0) {
// Set the start and end positions of the pragma rule if
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
// Quick hack; we only cope with a single parse tree node being returned, which is true at the moment
currentTreeBranch.push.apply(currentTreeBranch,subTree);
subTree[0].children = [];
@@ -235,7 +245,15 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
// Look for a block rule that applies at the current position
var nextMatch = this.findNextMatch(this.blockRules,this.pos);
if(nextMatch && nextMatch.matchIndex === this.pos) {
return nextMatch.rule.parse();
var start = this.pos;
var subTree = nextMatch.rule.parse();
// Set the start and end positions of the first and last blocks if they're not already set
if (subTree.length > 0) {
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
}
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
return subTree;
}
// Treat it as a paragraph if we didn't find a block rule
var start = this.pos;
@@ -332,7 +350,16 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
this.pos = nextMatch.matchIndex;
}
// Process the run rule
tree.push.apply(tree,nextMatch.rule.parse());
var start = this.pos;
var subTree = nextMatch.rule.parse();
// Set the start and end positions of the first and last child if they're not already set
if (subTree.length > 0) {
// Set the start and end positions of the first and last child if they're not already set
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
}
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
tree.push.apply(tree,subTree);
// Look for the next run rule
nextMatch = this.findNextMatch(this.inlineRules,this.pos);
}
@@ -383,7 +410,15 @@ WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegEx
this.pos = inlineRuleMatch.matchIndex;
}
// Process the inline rule
tree.push.apply(tree,inlineRuleMatch.rule.parse());
var start = this.pos;
var subTree = inlineRuleMatch.rule.parse();
// Set the start and end positions of the first and last child if they're not already set
if (subTree.length > 0) {
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
}
$tw.utils.each(subTree, function (node) { node.rule = inlineRuleMatch.rule.name; });
tree.push.apply(tree,subTree);
// Look for the next inline rule
inlineRuleMatch = this.findNextMatch(this.inlineRules,this.pos);
// Look for the next terminator match
@@ -409,7 +444,7 @@ WikiParser.prototype.pushTextWidget = function(array,text,start,end) {
text = $tw.utils.trim(text);
}
if(text) {
array.push({type: "text", text: text, start: start, end: end});
array.push({type: "text", text: text, start: start, end: end});
}
};
@@ -462,4 +497,3 @@ WikiParser.prototype.amendRules = function(type,names) {
exports["text/vnd.tiddlywiki"] = WikiParser;
})();

View File

@@ -95,6 +95,7 @@ function SaverHandler(options) {
if($tw.browser) {
$tw.rootWidget.addEventListener("tm-save-wiki",function(event) {
self.saveWiki({
wiki: event.widget.wiki,
template: event.param,
downloadType: "text/plain",
variables: event.paramObject
@@ -102,6 +103,7 @@ function SaverHandler(options) {
});
$tw.rootWidget.addEventListener("tm-download-file",function(event) {
self.saveWiki({
wiki: event.widget.wiki,
method: "download",
template: event.param,
downloadType: "text/plain",
@@ -147,20 +149,22 @@ Save the wiki contents. Options are:
method: "save", "autosave" or "download"
template: the tiddler containing the template to save
downloadType: the content type for the saved file
wiki: optional wiki, overriding the default wiki specified in the constructor
*/
SaverHandler.prototype.saveWiki = function(options) {
options = options || {};
var self = this,
wiki = options.wiki || this.wiki,
method = options.method || "save";
// Ignore autosave if disabled
if(method === "autosave" && ($tw.config.disableAutoSave || this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes")) {
if(method === "autosave" && ($tw.config.disableAutoSave || wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes")) {
return false;
}
var variables = options.variables || {},
template = (options.template ||
this.wiki.getTiddlerText("$:/config/SaveWikiButton/Template","$:/core/save/all")).trim(),
wiki.getTiddlerText("$:/config/SaveWikiButton/Template","$:/core/save/all")).trim(),
downloadType = options.downloadType || "text/plain",
text = this.wiki.renderTiddler(downloadType,template,options),
text = wiki.renderTiddler(downloadType,template,options),
callback = function(err) {
if(err) {
alert($tw.language.getString("Error/WhileSaving") + ":\n\n" + err);

View File

@@ -37,7 +37,9 @@ HeaderAuthenticator.prototype.authenticateRequest = function(request,response,st
return false;
} else {
// authenticatedUsername will be undefined for anonymous users
state.authenticatedUsername = $tw.utils.decodeURIComponentSafe(username);
if(username) {
state.authenticatedUsername = $tw.utils.decodeURIComponentSafe(username);
}
return true;
}
};

View File

@@ -61,7 +61,7 @@ exports.startup = function() {
// Collect the shadow tiddlers of any modified plugins
$tw.utils.each(changes.modifiedPlugins,function(pluginTitle) {
var pluginInfo = $tw.wiki.getPluginInfo(pluginTitle);
if(pluginInfo) {
if(pluginInfo && pluginInfo.tiddlers) {
$tw.utils.each(Object.keys(pluginInfo.tiddlers),function(title) {
changedShadowTiddlers[title] = false;
});

View File

@@ -29,7 +29,11 @@ var THROTTLE_REFRESH_TIMEOUT = 400;
exports.startup = function() {
// Set up the title
$tw.titleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TITLE_TITLE,{document: $tw.fakeDocument, parseAsInline: true});
$tw.titleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TITLE_TITLE, {
document: $tw.fakeDocument,
parseAsInline: true,
importPageMacros: true,
});
$tw.titleContainer = $tw.fakeDocument.createElement("div");
$tw.titleWidgetNode.render($tw.titleContainer,null);
document.title = $tw.titleContainer.textContent;

View File

@@ -39,6 +39,7 @@ exports.startup = function() {
method: params.method,
body: params.body,
binary: params.binary,
useDefaultHeaders: params.useDefaultHeaders,
oncompletion: params.oncompletion,
onprogress: params.onprogress,
bindStatus: params["bind-status"],
@@ -47,7 +48,11 @@ exports.startup = function() {
headers: getPropertiesWithPrefix(params,"header-"),
passwordHeaders: getPropertiesWithPrefix(params,"password-header-"),
queryStrings: getPropertiesWithPrefix(params,"query-"),
passwordQueryStrings: getPropertiesWithPrefix(params,"password-query-")
passwordQueryStrings: getPropertiesWithPrefix(params,"password-query-"),
basicAuthUsername: params["basic-auth-username"],
basicAuthUsernameFromStore: params["basic-auth-username-from-store"],
basicAuthPassword: params["basic-auth-password"],
basicAuthPasswordFromStore: params["basic-auth-password-from-store"]
});
});
$tw.rootWidget.addEventListener("tm-http-cancel-all-requests",function(event) {
@@ -68,7 +73,10 @@ exports.startup = function() {
});
// Install the copy-to-clipboard mechanism
$tw.rootWidget.addEventListener("tm-copy-to-clipboard",function(event) {
$tw.utils.copyToClipboard(event.param);
$tw.utils.copyToClipboard(event.param,{
successNotification: event.paramObject && event.paramObject.successNotification,
failureNotification: event.paramObject && event.paramObject.failureNotification
});
});
// Install the tm-focus-selector message
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {

View File

@@ -93,7 +93,9 @@ exports.startup = function() {
updateAddressBar: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_UPDATE_ADDRESS_BAR,"yes").trim() === "yes" ? "permalink" : "none",
updateHistory: $tw.wiki.getTiddlerText(CONFIG_UPDATE_HISTORY,"no").trim(),
targetTiddler: event.param || event.tiddlerTitle,
copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permalink" : "none"
copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permalink" : "none",
successNotification: event.paramObject && event.paramObject.successNotification,
failureNotification: event.paramObject && event.paramObject.failureNotification
});
});
// Listen for the tm-permaview message
@@ -102,7 +104,9 @@ exports.startup = function() {
updateAddressBar: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_UPDATE_ADDRESS_BAR,"yes").trim() === "yes" ? "permaview" : "none",
updateHistory: $tw.wiki.getTiddlerText(CONFIG_UPDATE_HISTORY,"no").trim(),
targetTiddler: event.param || event.tiddlerTitle,
copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permaview" : "none"
copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permaview" : "none",
successNotification: event.paramObject && event.paramObject.successNotification,
failureNotification: event.paramObject && event.paramObject.failureNotification
});
});
}
@@ -177,6 +181,8 @@ options.updateAddressBar: "permalink", "permaview" or "no" (defaults to "permavi
options.updateHistory: "yes" or "no" (defaults to "no")
options.copyToClipboard: "permalink", "permaview" or "no" (defaults to "no")
options.targetTiddler: optional title of target tiddler for permalink
options.successNotification: optional title of tiddler to use as the notification in case of success
options.failureNotification: optional title of tiddler to use as the notification in case of failure
*/
function updateLocationHash(options) {
// Get the story and the history stack
@@ -205,14 +211,18 @@ function updateLocationHash(options) {
break;
}
// Copy URL to the clipboard
var url = "";
switch(options.copyToClipboard) {
case "permalink":
$tw.utils.copyToClipboard($tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler));
url = $tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler);
break;
case "permaview":
$tw.utils.copyToClipboard($tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler) + ":" + encodeURIComponent($tw.utils.stringifyList(storyList)));
url = $tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler) + ":" + encodeURIComponent($tw.utils.stringifyList(storyList));
break;
}
if(url) {
$tw.utils.copyToClipboard(url,{successNotification: options.successNotification, failureNotification: options.failureNotification});
}
// Only change the location hash if we must, thus avoiding unnecessary onhashchange events
if($tw.utils.getLocationHash() !== $tw.locationHash) {
if(options.updateHistory === "yes") {

View File

@@ -82,6 +82,10 @@ ClassicStoryView.prototype.remove = function(widget) {
removeElement = function() {
widget.removeChildDomNodes();
};
// Blur the focus if it is within the descendents of the node we are removing
if($tw.utils.domContains(targetElement,targetElement.ownerDocument.activeElement)) {
targetElement.ownerDocument.activeElement.blur();
}
// Abandon if the list entry isn't a DOM element (it might be a text node)
if(!targetElement || targetElement.nodeType === Node.TEXT_NODE) {
removeElement();

View File

@@ -292,7 +292,9 @@ exports.copyToClipboard = function(text,options) {
} catch (err) {
}
if(!options.doNotNotify) {
$tw.notifier.display(succeeded ? "$:/language/Notifications/CopiedToClipboard/Succeeded" : "$:/language/Notifications/CopiedToClipboard/Failed");
var successNotification = options.successNotification || "$:/language/Notifications/CopiedToClipboard/Succeeded",
failureNotification = options.failureNotification || "$:/language/Notifications/CopiedToClipboard/Failed"
$tw.notifier.display(succeeded ? successNotification : failureNotification);
}
document.body.removeChild(textArea);
};

View File

@@ -69,7 +69,7 @@ HttpClient.prototype.cancelAllHttpRequests = function() {
for(var t=this.requests.length - 1; t--; t>=0) {
var requestInfo = this.requests[t];
requestInfo.request.cancel();
}
}
}
this.requests = [];
this.updateRequestTracker();
@@ -100,6 +100,10 @@ headers: hashmap of header name to header value to be sent with the request
passwordHeaders: hashmap of header name to password store name to be sent with the request
queryStrings: hashmap of query string parameter name to parameter value to be sent with the request
passwordQueryStrings: hashmap of query string parameter name to password store name to be sent with the request
basicAuthUsername: plain username for basic authentication
basicAuthUsernameFromStore: name of password store entry containing username
basicAuthPassword: plain password for basic authentication
basicAuthPasswordFromStore: name of password store entry containing password
*/
function HttpClientRequest(options) {
var self = this;
@@ -112,6 +116,7 @@ function HttpClientRequest(options) {
this.method = options.method || "GET";
this.body = options.body || "";
this.binary = options.binary || "";
this.useDefaultHeaders = options.useDefaultHeaders !== "false" ? true : false,
this.variables = options.variables;
var url = options.url;
$tw.utils.each(options.queryStrings,function(value,name) {
@@ -128,6 +133,11 @@ function HttpClientRequest(options) {
$tw.utils.each(options.passwordHeaders,function(value,name) {
self.requestHeaders[name] = $tw.utils.getPassword(value) || "";
});
this.basicAuthUsername = options.basicAuthUsername || (options.basicAuthUsernameFromStore && $tw.utils.getPassword(options.basicAuthUsernameFromStore)) || "";
this.basicAuthPassword = options.basicAuthPassword || (options.basicAuthPasswordFromStore && $tw.utils.getPassword(options.basicAuthPasswordFromStore)) || "";
if(this.basicAuthUsername && this.basicAuthPassword) {
this.requestHeaders.Authorization = "Basic " + $tw.utils.base64Encode(this.basicAuthUsername + ":" + this.basicAuthPassword);
}
}
HttpClientRequest.prototype.send = function(callback) {
@@ -156,6 +166,7 @@ HttpClientRequest.prototype.send = function(callback) {
this.xhr = $tw.utils.httpRequest({
url: this.url,
type: this.method,
useDefaultHeaders: this.useDefaultHeaders,
headers: this.requestHeaders,
data: this.body,
returnProp: this.binary === "" ? "responseText" : "response",
@@ -231,7 +242,8 @@ Make an HTTP request. Options are:
exports.httpRequest = function(options) {
var type = options.type || "GET",
url = options.url,
headers = options.headers || {accept: "application/json"},
useDefaultHeaders = options.useDefaultHeaders !== false ? true : false,
headers = options.headers || (useDefaultHeaders ? {accept: "application/json"} : {}),
hasHeader = function(targetHeader) {
targetHeader = targetHeader.toLowerCase();
var result = false;
@@ -257,7 +269,7 @@ exports.httpRequest = function(options) {
if(hasHeader("Content-Type") && ["application/x-www-form-urlencoded","multipart/form-data","text/plain"].indexOf(getHeader["Content-Type"]) === -1) {
return false;
}
return true;
return true;
},
returnProp = options.returnProp || "responseText",
request = new XMLHttpRequest(),
@@ -307,10 +319,10 @@ exports.httpRequest = function(options) {
request.setRequestHeader(headerTitle,header);
});
}
if(data && !hasHeader("Content-Type")) {
if(data && !hasHeader("Content-Type") && useDefaultHeaders) {
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
}
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers) && useDefaultHeaders) {
request.setRequestHeader("X-Requested-With","TiddlyWiki");
}
// Send data

View File

@@ -0,0 +1,23 @@
/*\
title: $:/core/modules/utils/errors.js
type: application/javascript
module-type: utils
Custom errors for TiddlyWiki.
\*/
(function(){
function TranscludeRecursionError() {
Error.apply(this,arguments);
this.signatures = Object.create(null);
};
/* Maximum permitted depth of the widget tree for recursion detection */
TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH = 1000;
TranscludeRecursionError.prototype = Object.create(Error);
exports.TranscludeRecursionError = TranscludeRecursionError;
})();

View File

@@ -42,7 +42,7 @@ var TW_TextNode = function(text) {
this.textContent = text + "";
};
Object.setPrototypeOf(TW_TextNode,TW_Node.prototype);
Object.setPrototypeOf(TW_TextNode.prototype,TW_Node.prototype);
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
get: function() {
@@ -67,7 +67,7 @@ var TW_Element = function(tag,namespace) {
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
};
Object.setPrototypeOf(TW_Element,TW_Node.prototype);
Object.setPrototypeOf(TW_Element.prototype,TW_Node.prototype);
Object.defineProperty(TW_Element.prototype, "style", {
get: function() {

View File

@@ -0,0 +1,52 @@
/*\
title: $:/core/modules/utils/repository.js
type: application/javascript
module-type: utils
Utilities for working with the TiddlyWiki repository file structure
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Get an object containing all the plugins as a hashmap by title of the JSON representation of the plugin
Options:
ignoreEnvironmentVariables: defaults to false
*/
exports.getAllPlugins = function(options) {
options = options || {};
var fs = require("fs"),
path = require("path"),
tiddlers = {};
// Collect up the library plugins
var collectPlugins = function(folder) {
var pluginFolders = $tw.utils.getSubdirectories(folder) || [];
for(var p=0; p<pluginFolders.length; p++) {
if(!$tw.boot.excludeRegExp.test(pluginFolders[p])) {
var pluginFields = $tw.loadPluginFolder(path.resolve(folder,"./" + pluginFolders[p]));
if(pluginFields && pluginFields.title) {
tiddlers[pluginFields.title] = pluginFields;
}
}
}
},
collectPublisherPlugins = function(folder) {
var publisherFolders = $tw.utils.getSubdirectories(folder) || [];
for(var t=0; t<publisherFolders.length; t++) {
if(!$tw.boot.excludeRegExp.test(publisherFolders[t])) {
collectPlugins(path.resolve(folder,"./" + publisherFolders[t]));
}
}
};
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.pluginsEnvVar),collectPublisherPlugins);
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.themesEnvVar),collectPublisherPlugins);
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.languagesEnvVar),collectPlugins);
return tiddlers;
};
})();

View File

@@ -825,7 +825,7 @@ options.length .. number of characters returned defaults to 64
*/
exports.sha256 = function(str, options) {
options = options || {}
return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(str)).substr(0,options.length || 64);
return $tw.sjcl.codec.hex.fromBits($tw.sjcl.hash.sha256.hash(str)).substr(0,options.length || 64);
}
/*

View File

@@ -66,7 +66,12 @@ LogWidget.prototype.log = function() {
});
for(var v in this.variables) {
allVars[v] = this.getVariable(v,{defaultValue:""});
var variable = this.parentWidget && this.parentWidget.variables[v];
if(variable && variable.isFunctionDefinition) {
allVars[v] = variable.value;
} else {
allVars[v] = this.getVariable(v,{defaultValue:""});
}
}
if(this.filter) {
filteredVars = this.wiki.compileFilter(this.filter).call(this.wiki,this.wiki.makeTiddlerIterator(allVars));

View File

@@ -262,7 +262,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
ButtonWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
if(changedAttributes.tooltip || changedAttributes.actions || changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup]) || (this.popupTitle && changedTiddlers[this.popupTitle]) || changedAttributes.popupAbsCoords || changedAttributes.setTitle || changedAttributes.setField || changedAttributes.setIndex || changedAttributes.popupTitle || changedAttributes.disabled || changedAttributes["default"]) {
this.refreshSelf();
return true;
} else {

View File

@@ -31,34 +31,49 @@ DataWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
var jsonPayload = JSON.stringify(this.readDataTiddlerValues(),null,4);
var textNode = this.document.createTextNode(jsonPayload);
parent.insertBefore(textNode,nextSibling);
this.domNodes.push(textNode);
this.dataPayload = this.computeDataTiddlerValues(); // Array of $tw.Tiddler objects
this.domNode = this.document.createTextNode(this.readDataTiddlerValuesAsJson());
parent.insertBefore(this.domNode,nextSibling);
this.domNodes.push(this.domNode);
};
/*
Compute the internal state of the widget
*/
DataWidget.prototype.execute = function() {
// Construct the child widgets
this.makeChildWidgets();
// Nothing to do here
};
/*
Read the tiddler value(s) from a data widget must be called after the .render() method
Read the tiddler value(s) from a data widget as an array of tiddler field objects (not $tw.Tiddler objects)
*/
DataWidget.prototype.readDataTiddlerValues = function() {
var results = [];
$tw.utils.each(this.dataPayload,function(tiddler,index) {
results.push(tiddler.getFieldStrings());
});
return results;
};
/*
Read the tiddler value(s) from a data widget as an array of tiddler field objects (not $tw.Tiddler objects)
*/
DataWidget.prototype.readDataTiddlerValuesAsJson = function() {
return JSON.stringify(this.readDataTiddlerValues(),null,4);
};
/*
Compute list of tiddlers from a data widget
*/
DataWidget.prototype.computeDataTiddlerValues = function() {
var self = this;
// Start with a blank object
var item = Object.create(null);
// Read any attributes not prefixed with $
var item = Object.create(null);
$tw.utils.each(this.attributes,function(value,name) {
if(name.charAt(0) !== "$") {
item[name] = value;
}
});
item = new $tw.Tiddler(item);
// Deal with $tiddler, $filter or $compound-tiddler attributes
var tiddlers = [],title;
if(this.hasAttribute("$tiddler")) {
@@ -76,7 +91,9 @@ DataWidget.prototype.readDataTiddlerValues = function() {
var titles = this.wiki.filterTiddlers(filter);
$tw.utils.each(titles,function(title) {
var tiddler = self.wiki.getTiddler(title);
tiddlers.push(tiddler);
if(tiddler) {
tiddlers.push(tiddler);
}
});
}
}
@@ -86,21 +103,22 @@ DataWidget.prototype.readDataTiddlerValues = function() {
tiddlers.push.apply(tiddlers,this.extractCompoundTiddler(title));
}
}
// Convert the literal item to field strings
item = item.getFieldStrings();
if(tiddlers.length === 0) {
// Return the literal item if none of the special attributes were used
if(!this.hasAttribute("$tiddler") && !this.hasAttribute("$filter") && !this.hasAttribute("$compound-tiddler")) {
if(Object.keys(item).length > 0 && !!item.title) {
return [item];
return [new $tw.Tiddler(item)];
} else {
return [];
}
} else {
var results = [];
$tw.utils.each(tiddlers,function(tiddler,index) {
var fields = tiddler.getFieldStrings();
results.push($tw.utils.extend({},fields,item));
});
return results;
// Apply the item fields to each of the tiddlers
delete item.title; // Do not overwrite the title
if(Object.keys(item).length > 0) {
$tw.utils.each(tiddlers,function(tiddler,index) {
tiddlers[index] = new $tw.Tiddler(tiddler,item);
});
}
return tiddlers;
}
};
@@ -134,12 +152,33 @@ DataWidget.prototype.extractCompoundTiddler = function(title) {
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DataWidget.prototype.refresh = function(changedTiddlers) {
// It would be expensive to calculate whether the changedTiddlers impact the filter
// identified by the $filter attribute so we just refresh ourselves unconditionally
this.refreshSelf();
return true;
var changedAttributes = this.computeAttributes();
var newPayload = this.computeDataTiddlerValues();
if(hasPayloadChanged(this.dataPayload,newPayload)) {
this.dataPayload = newPayload;
this.domNode.textContent = this.readDataTiddlerValuesAsJson();
return true;
} else {
return false;
}
};
/*
Compare two arrays of tiddlers and return true if they are different
*/
function hasPayloadChanged(a,b) {
if(a.length === b.length) {
for(var t=0; t<a.length; t++) {
if(!(a[t].isEqual(b[t]))) {
return true;
}
}
return false;
} else {
return true;
}
}
exports.data = DataWidget;
})();

View File

@@ -74,6 +74,18 @@ ParametersWidget.prototype.execute = function() {
self.setVariable(variableName,getValue(name));
}
});
} else {
// There is no parent transclude. i.e. direct rendering.
// We use default values only.
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(self.parseTreeNode),function(attr,index) {
var name = attr.name;
// If the attribute name starts with $$ then reduce to a single dollar
if(name.substr(0,2) === "$$") {
name = name.substr(1);
}
var value = self.getAttribute(attr.name,"");
self.setVariable(name,value);
});
}
// Construct the child widgets
this.makeChildWidgets();

View File

@@ -77,8 +77,13 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) {
this.setVariable("transclusion",$tw.utils.hashString(jsonPayload));
// Generate a `payloadTiddlers` variable that contains the payload in JSON format
this.setVariable("payloadTiddlers",jsonPayload);
// Only run the tests if the testcase output and expected results were specified, and those tiddlers actually exist in the wiki
var shouldRunTests = false;
if(this.testcaseTestOutput && this.testcaseWiki.tiddlerExists(this.testcaseTestOutput) && this.testcaseTestExpectedResult && this.testcaseWiki.tiddlerExists(this.testcaseTestExpectedResult)) {
shouldRunTests = true;
}
// Render the test rendering if required
if(this.testcaseTestOutput && this.testcaseTestExpectedResult) {
if(shouldRunTests) {
var testcaseOutputContainer = $tw.fakeDocument.createElement("div");
var testcaseOutputWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTestOutput,{
document: $tw.fakeDocument,
@@ -101,7 +106,7 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) {
var testResult = "",
outputHTML = "",
expectedHTML = "";
if(this.testcaseTestOutput && this.testcaseTestExpectedResult) {
if(shouldRunTests) {
outputHTML = testcaseOutputContainer.children[0].innerHTML;
expectedHTML = this.testcaseWiki.getTiddlerText(this.testcaseTestExpectedResult);
if(outputHTML === expectedHTML) {
@@ -115,7 +120,7 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) {
this.setVariable("currentTiddler",this.testcaseTestOutput);
}
// Don't display anything if testHideIfPass is "yes" and the tests have passed
if(this.testcaseHideIfPass === "yes" && testResult === "pass") {
if(this.testcaseHideIfPass === "yes" && testResult !== "fail") {
return;
}
// Render the page root template of the subwiki

View File

@@ -30,7 +30,30 @@ TranscludeWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
try {
this.renderChildren(parent,nextSibling);
} catch(error) {
if(error instanceof $tw.utils.TranscludeRecursionError) {
// We were infinite looping.
// We need to try and abort as much of the loop as we can, so we will keep "throwing" upward until we find a transclusion that has a different signature.
// Hopefully that will land us just outside where the loop began. That's where we want to issue an error.
// Rendering widgets beneath this point may result in a freezing browser if they explode exponentially.
var transcludeSignature = this.getVariable("transclusion");
if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH - 50) {
// For the first fifty transcludes we climb up, we simply collect signatures.
// We're assuming that those first 50 will likely include all transcludes involved in the loop.
error.signatures[transcludeSignature] = true;
} else if(!error.signatures[transcludeSignature]) {
// Now that we're past the first 50, let's look for the first signature that wasn't in the loop. That'll be where we print the error and resume rendering.
this.children = [this.makeChildWidget({type: "error", attributes: {
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
}})];
this.renderChildren(parent,nextSibling);
return;
}
}
throw error;
}
};
/*

View File

@@ -12,9 +12,6 @@ Widget base class
/*global $tw: false */
"use strict";
/* Maximum permitted depth of the widget tree for recursion detection */
var MAX_WIDGET_TREE_DEPTH = 1000;
/*
Create a widget object for a parse tree node
parseTreeNode: reference to the parse tree node to be rendered
@@ -166,6 +163,8 @@ Widget.prototype.getVariableInfo = function(name,options) {
});
resultList = this.wiki.filterTiddlers(value,this.makeFakeWidgetWithVariables(variables),options.source);
value = resultList[0] || "";
} else {
params = variable.params;
}
return {
text: value,
@@ -317,7 +316,8 @@ Widget.prototype.getStateQualifier = function(name) {
Make a fake widget with specified variables, suitable for variable lookup in filters
*/
Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
var self = this;
var self = this,
variables = variables || {};
return {
getVariable: function(name,opts) {
if($tw.utils.hop(variables,name)) {
@@ -335,7 +335,7 @@ Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
};
} else {
opts = opts || {};
opts.variables = variables;
opts.variables = $tw.utils.extend(variables,opts.variables);
return self.getVariableInfo(name,opts);
};
},
@@ -494,10 +494,8 @@ Widget.prototype.makeChildWidgets = function(parseTreeNodes,options) {
this.children = [];
var self = this;
// Check for too much recursion
if(this.getAncestorCount() > MAX_WIDGET_TREE_DEPTH) {
this.children.push(this.makeChildWidget({type: "error", attributes: {
"$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")}
}}));
if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH) {
throw new $tw.utils.TranscludeRecursionError();
} else {
// Create set variable widgets for each variable
$tw.utils.each(options.variables,function(value,name) {

View File

@@ -551,28 +551,41 @@ exports.getTiddlerBacklinks = function(targetTitle) {
/*
Return an array of tiddler titles that are directly transcluded within the given parse tree
Return an array of tiddler titles that are directly transcluded within the given parse tree. `title` is the tiddler being parsed, we will ignore its self-referential transclusions, only return
*/
exports.extractTranscludes = function(parseTreeRoot) {
exports.extractTranscludes = function(parseTreeRoot, title) {
// Count up the transcludes
var transcludes = [],
checkParseTree = function(parseTree, parentNode) {
for(var t=0; t<parseTree.length; t++) {
var parseTreeNode = parseTree[t];
if(parseTreeNode.type === "transclude" && parseTreeNode.attributes.$tiddler && parseTreeNode.attributes.$tiddler.type === "string") {
var value;
// if it is Transclusion with Templates like `{{Index||$:/core/ui/TagTemplate}}`, the `$tiddler` will point to the template. We need to find the actual target tiddler from parent node
if(parentNode && parentNode.type === "tiddler" && parentNode.attributes.tiddler && parentNode.attributes.tiddler.type === "string") {
value = parentNode.attributes.tiddler.value;
} else {
value = parseTreeNode.attributes.$tiddler.value;
if(parseTreeNode.type === "transclude") {
if(parseTreeNode.attributes.$tiddler && parseTreeNode.attributes.$tiddler.type === "string") {
var value;
// if it is Transclusion with Templates like `{{Index||$:/core/ui/TagTemplate}}`, the `$tiddler` will point to the template. We need to find the actual target tiddler from parent node
if(parentNode && parentNode.type === "tiddler" && parentNode.attributes.tiddler && parentNode.attributes.tiddler.type === "string") {
// Empty value (like `{{!!field}}`) means self-referential transclusion.
value = parentNode.attributes.tiddler.value || title;
} else {
value = parseTreeNode.attributes.$tiddler.value;
}
} else if(parseTreeNode.attributes.tiddler && parseTreeNode.attributes.tiddler.type === "string") {
// Old transclude widget usage
value = parseTreeNode.attributes.tiddler.value;
} else if(parseTreeNode.attributes.$field && parseTreeNode.attributes.$field.type === "string") {
// Empty value (like `<$transclude $field='created'/>`) means self-referential transclusion.
value = title;
} else if(parseTreeNode.attributes.field && parseTreeNode.attributes.field.type === "string") {
// Old usage with Empty value (like `<$transclude field='created'/>`)
value = title;
}
if(transcludes.indexOf(value) === -1) {
transcludes.push(value);
// Deduplicate the result.
if(value && transcludes.indexOf(value) === -1) {
$tw.utils.pushTop(transcludes,value);
}
}
if(parseTreeNode.children) {
checkParseTree(parseTreeNode.children, parseTreeNode);
checkParseTree(parseTreeNode.children,parseTreeNode);
}
}
};
@@ -591,7 +604,8 @@ exports.getTiddlerTranscludes = function(title) {
// Parse the tiddler
var parser = self.parseTiddler(title);
if(parser) {
return self.extractTranscludes(parser.tree);
// this will ignore self-referential transclusions from `title`
return self.extractTranscludes(parser.tree,title);
}
return [];
});

View File

@@ -82,6 +82,10 @@ sidebar-tab-foreground: <<colour tab-foreground>>
sidebar-tiddler-link-foreground-hover: #458588
sidebar-tiddler-link-foreground: #98971a
site-title-foreground: <<colour tiddler-title-foreground>>
stability-deprecated: #cc241d
stability-experimental: #d79921
stability-legacy: #458588
stability-stable: #98971a
static-alert-foreground: #B48EAD
tab-background-selected: #ebdbb2
tab-background: #665c54

View File

@@ -82,6 +82,10 @@ sidebar-tab-foreground: <<colour tab-foreground>>
sidebar-tiddler-link-foreground-hover: #A3BE8C
sidebar-tiddler-link-foreground: #81A1C1
site-title-foreground: <<colour tiddler-title-foreground>>
stability-deprecated: #bf616a
stability-experimental: #d08770
stability-legacy: #88c0d0
stability-stable: #a3be8c
static-alert-foreground: #B48EAD
tab-background-selected: #ECEFF4
tab-background: #4C566A

View File

@@ -18,7 +18,7 @@ button-foreground: #93a1a1
code-background: #073642
code-border: #586e75
code-foreground: #93a1a1
dirty-indicator: inherit
dirty-indicator: #dc322f
download-background: #859900
download-foreground: #073642
dragger-background: #073642
@@ -72,6 +72,10 @@ sidebar-tab-foreground-selected: #93a1a1
sidebar-tiddler-link-foreground: #2aa198
sidebar-tiddler-link-foreground-hover: #eee8d5
site-title-foreground: #d33682
stability-deprecated: #dc322f
stability-experimental: #b58900
stability-legacy: #268bd2
stability-stable: #859900
static-alert-foreground: #93a1a1
tab-background: #073642
tab-background-selected: #002b36

View File

@@ -18,7 +18,7 @@ button-foreground: #586e75
code-background: #eee8d5
code-border: #93a1a1
code-foreground: #586e75
dirty-indicator: inherit
dirty-indicator: #dc322f
download-background: #859900
download-foreground: #eee8d5
dragger-background: #eee8d5
@@ -72,6 +72,10 @@ sidebar-tab-foreground-selected: #586e75
sidebar-tiddler-link-foreground: #2aa198
sidebar-tiddler-link-foreground-hover: #002b36
site-title-foreground: #d33682
stability-deprecated: #dc322f
stability-experimental: #b58900
stability-legacy: #268bd2
stability-stable: #859900
static-alert-foreground: #586e75
tab-background: #eee8d5
tab-background-selected: #fdf6e3

View File

@@ -82,6 +82,10 @@ sidebar-tab-foreground: <<colour tab-foreground>>
sidebar-tiddler-link-foreground-hover: #444444
sidebar-tiddler-link-foreground: #999999
site-title-foreground: <<colour tiddler-title-foreground>>
stability-stable: #008000
stability-experimental: #c07c00
stability-deprecated: #ff0000
stability-legacy: #0000ff
static-alert-foreground: #aaaaaa
tab-background-selected: #ffffff
tab-background: #d8d8d8
@@ -95,7 +99,7 @@ table-footer-background: #a8a8a8
table-header-background: #f0f0f0
tag-background: #ec6
tag-foreground: #ffffff
testcase-accent-level-1: #84C5E6
testcase-accent-level-1: #c1eaff
testcase-accent-level-2: #E3B740
testcase-accent-level-3: #5FD564
tiddler-background: <<colour background>>

View File

@@ -5,5 +5,6 @@
"author": "JeremyRuston",
"core-version": ">=5.0.0",
"plugin-priority": "0",
"list": "readme"
"list": "readme",
"stability": "STABILITY_2_STABLE"
}

View File

@@ -45,7 +45,17 @@ $:/config/Plugins/Disabled/$(currentTiddler)$
<$view field="title"/>
</h2>
<h2>
<div><em><$view field="version"/></em></div>
<div>
<%if [<currentTiddler>get[stability]match[STABILITY_0_DEPRECATED]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-deprecated">DEPRECATED</span>
<%elseif [<currentTiddler>get[stability]match[STABILITY_1_EXPERIMENTAL]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-experimental">EXPERIMENTAL</span>
<%elseif [<currentTiddler>get[stability]match[STABILITY_2_STABLE]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-stable">STABLE</span>
<%elseif [<currentTiddler>get[stability]match[STABILITY_3_LEGACY]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-legacy">LEGACY</span>
<%endif%>
<em><$view field="version"/></em></div>
</h2>
</div>
\end

View File

@@ -70,9 +70,20 @@ $:/state/add-plugin-info/$(connectionTiddler)$/$(assetInfo)$
<div class="tc-plugin-info-chunk tc-plugin-info-description">
<h1><strong><$text text={{{ [<assetInfo>get[name]] ~[<assetInfo>get[original-title]split[/]last[1]] }}}/></strong>:
&#32;
<$view tiddler=<<assetInfo>> field="description"/></h1>
<$view tiddler=<<assetInfo>> field="description"/>
</h1>
<h2><$view tiddler=<<assetInfo>> field="original-title"/></h2>
<div><em><$view tiddler=<<assetInfo>> field="version"/></em></div>
<div>
<%if [<assetInfo>get[stability]match[STABILITY_0_DEPRECATED]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-deprecated">DEPRECATED</span>
<%elseif [<assetInfo>get[stability]match[STABILITY_1_EXPERIMENTAL]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-experimental">EXPERIMENTAL</span>
<%elseif [<assetInfo>get[stability]match[STABILITY_2_STABLE]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-stable">STABLE</span>
<%elseif [<assetInfo>get[stability]match[STABILITY_3_LEGACY]] %>
<span class="tc-plugin-info-stability tc-plugin-info-stability-legacy">LEGACY</span>
<%endif%>
<em><$view tiddler=<<assetInfo>> field="version"/></em></div>
<$list filter="[<assetInfo>get[original-title]get[version]]" variable="installedVersion"><div><em>{{$:/language/ControlPanel/Plugins/AlreadyInstalled/Hint}}</em></div></$list>
</div>
<div class="tc-plugin-info-chunk tc-plugin-info-buttons">

View File

@@ -9,7 +9,7 @@ list-before:
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ControlPanel/Settings]]">
<div class="tc-control-panel-setting" data-setting-title=<<currentTiddler>> style="border-top:1px solid #eee;">
<div class="tc-control-panel-setting" data-setting-title=<<currentTiddler>> >
!!.tc-control-panel-accent <$link><$transclude field="caption"/></$link>

View File

@@ -1,7 +1,7 @@
title: $:/core/ui/PageTemplate
name: {{$:/language/PageTemplate/Name}}
description: {{$:/language/PageTemplate/Description}}
icon: $:/core/images/default-layout
icon: $:/core/images/standard-layout
code-body: yes
\whitespace trim

View File

@@ -5,6 +5,7 @@ title: $:/core/ui/TestCaseTemplate
<$let
linkTarget="yes"
displayFormat={{!!display-format}}
testcaseTiddler=<<currentTiddler>>
>
<$testcase
testOutput="Output"

View File

@@ -15,7 +15,7 @@ title: $:/core/ui/testcases/DefaultTemplate
<div class="tc-test-case-wrapper">
<div class="tc-test-case-header">
<h2>
<$genesis $type={{{ [<linkTarget>!match[]then[$link]else[div]] }}}>
<$genesis $type={{{ [<linkTarget>!match[]then[$link]else[span]] }}} to=<<testcaseTiddler>>>
<%if [<testResult>!match[]] %>
<span class={{{ tc-test-case-result-icon [<testResult>!match[fail]then[tc-test-case-result-icon-pass]] [<testResult>match[fail]then[tc-test-case-result-icon-fail]] +[join[ ]] }}}>
<%if [<testResult>!match[fail]] %>
@@ -27,6 +27,31 @@ title: $:/core/ui/testcases/DefaultTemplate
<%endif%>
<$view tiddler="Description" mode="inline"/>
</$genesis>
<span class="tc-test-case-toolbar">
<$button popup=`$(state)$-more`
tooltip={{$:/language/Buttons/More/Hint}}
aria-label={{$:/language/Buttons/More/Caption}}
class="tc-btn-invisible"
selectedClass="tc-selected"
>
{{$:/core/images/down-arrow}}
</$button>
<$let
tv-config-toolbar-icons="yes"
tv-config-toolbar-text="yes"
tv-config-toolbar-class="tc-btn-invisible"
>
<$reveal state=`$(state)$-more` type="popup" position="belowleft" animate="yes">
<div class="tc-drop-down">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/TestCase/Actions]!has[draft.of]]"
variable="listItem"
>
<$transclude tiddler=<<listItem>> mode="inline"/>
</$list>
</div>
</$reveal>
</$let>
</span>
</h2>
</div>
<%if [[Narrative]is[tiddler]] %>
@@ -46,7 +71,7 @@ title: $:/core/ui/testcases/DefaultTemplate
<%endif%>
<div class="tc-test-case-panes">
<div class="tc-test-case-source">
<$macrocall $name="tabs" tabsList="[all[tiddlers]sort[]] -[prefix<state>] -Description -Narrative -ExpectedResult -Output Output +[putfirst[]] -[has[plugin-type]]" state=<<state>> default="Output" template="$:/core/ui/testcases/DefaultTemplate/SourceTabs"/>
<$macrocall $name="tabs" tabsList="[all[tiddlers]sort[]] -[prefix<state>] -Description -Narrative -Output Output +[putfirst[]] -[has[plugin-type]]" state=<<state>> default="Output" template="$:/core/ui/testcases/DefaultTemplate/SourceTabs"/>
</div>
<div class="tc-test-case-divider">
</div>
@@ -55,7 +80,9 @@ title: $:/core/ui/testcases/DefaultTemplate
<pre><$view tiddler="Output" format="plainwikified" mode="block"/></pre>
<%else%>
<$linkcatcher actions=<<linkcatcherActions>>>
<$transclude $tiddler="Output" $mode="block"/>
<$tiddler tiddler="Output">
<$transclude $tiddler="Output" $mode="block"/>
</$tiddler>
</$linkcatcher>
<%endif%>
</div>

View File

@@ -19,6 +19,9 @@ title: $:/core/ui/testcases/DefaultTemplate/SourceTabs
</table>
</$list>
<$edit class="tc-edit-texteditor" tiddler=<<currentTab>>/>
<div class="tc-test-case-footer-toolbar">
<$macrocall $name="copy-to-clipboard" src={{{ [<currentTab>get[text]] }}}/>
</div>
\end
<$transclude $variable="body" $mode="inline"/>

View File

@@ -0,0 +1,4 @@
title: $:/core/ui/testcases/actions/Export
tags: $:/tags/TestCase/Actions
<$macrocall $name="exportButton" exportFilter="[all[tiddlers]sort[]] -[prefix[$:/state/]] -Description -Narrative -ExpectedResult -Output Output +[putfirst[]] -[has[plugin-type]]" lingoBase="$:/language/Buttons/ExportTiddlers/"/>

View File

@@ -0,0 +1,11 @@
title: $:/core/ui/testcases/actions/Import
tags: $:/tags/TestCase/Actions
\whitespace trim
<$button tooltip={{$:/language/Buttons/TestCaseImport/Hint}} aria-label={{$:/language/Buttons/TestCaseImport/Caption}} class=<<tv-config-toolbar-class>>>
<$action-sendmessage $message="tm-import-tiddlers" $param=<<payloadTiddlers>>/>
{{$:/core/images/input-button}}
<span class="tc-btn-text">
<$text text={{$:/language/Buttons/TestCaseImport/Caption}}/>
</span>
</$button>

View File

@@ -1,6 +1,6 @@
title: $:/config/OfficialPluginLibrary
tags: $:/tags/PluginLibrary
url: https://tiddlywiki.com/library/v5.3.3/index.html
url: https://tiddlywiki.com/library/v5.3.5/index.html
caption: {{$:/language/OfficialPluginLibrary}}
{{$:/language/OfficialPluginLibrary/Hint}}

View File

@@ -1,18 +1,17 @@
title: $:/core/macros/CSS
tags: $:/tags/Macro $:/tags/Global
\procedure colour(name)
<!-- Needs to stay that way for backwards compatibility. See GH issue: #8326 -->
\define colour(name)
\whitespace trim
<$transclude $tiddler={{$:/palette}} $index=`$(name)$`>
<$transclude $tiddler="$:/palettes/Vanilla" $index=`$(name)$`>
<$transclude $tiddler=`$:/config/DefaultColourMappings/$(name)$`/>
<$transclude tiddler={{$:/palette}} index="$name$">
<$transclude tiddler="$:/palettes/Vanilla" index="$name$">
<$transclude tiddler="$:/config/DefaultColourMappings/$name$"/>
</$transclude>
</$transclude>
\end
\procedure color(name)
<$macrocall $name=colour name=`$(name)$`/>
\end
\define color(name) <<colour $name$>>
\function box-shadow(shadow)
[[ -webkit-box-shadow: $(shadow)$;

View File

@@ -1,5 +1,5 @@
title: $:/core/macros/tag-picker
tags: tags: $:/tags/Macro $:/tags/Global
tags: $:/tags/Macro $:/tags/Global
first-search-filter: [subfilter<tagListFilter>!is[system]search:title<userInput>sort[]]
second-search-filter: [subfilter<tagListFilter>is[system]search:title<userInput>sort[]]
@@ -154,8 +154,10 @@ The second ESC tries to close the "draft tiddler"
\function _tf.getUserInput() [<storeTitle>get[text]]
\function _tf.getTag() [<newTagNameTiddler>get[text]]
<!-- Use this function if tag-picker is a stand alone macro. Otherwise use "newTagNameTiddler" defined for fieldmangler in EditTemplate -->
\function _tf.makeTagNameTiddler() [[$:/temp/NewTagName]] [<tagField>!match[tags]] +[join[/]] [<qualify>] +[join[]]
<!-- keep those variables because they may "blead" into macros using old syntax -->
<!-- keep those variables because they may "bleed" into macros using old syntax -->
<$let
palette={{$:/palette}}
colourA={{{ [<palette>getindex[foreground]] }}}
@@ -164,7 +166,7 @@ The second ESC tries to close the "draft tiddler"
saveTiddler={{{ [<tiddler>is[blank]then<currentTiddler>else<tiddler>] }}}
newTagNameTiddler={{{ [[$:/temp/NewTagName]] [<tagField>!match[tags]] +[join[/]] [<qualify>] +[join[]] }}}
newTagNameTiddler={{{ [[newTagNameTiddler]is[variable]then<newTagNameTiddler>] :else[<_tf.makeTagNameTiddler>] }}}
storeTitle={{{ [[$:/temp/NewTagName/input]] [<tagField>!match[tags]] +[join[/]] [<qualify>] +[join[]] }}}
newTagNameSelectionTiddlerQualified=<<qualify "$:/temp/NewTagName/selected-item">>
@@ -179,4 +181,4 @@ The second ESC tries to close the "draft tiddler"
>
<$macrocall $name="tag-picker-inner"/>
</$let>
\end
\end

View File

@@ -0,0 +1,2 @@
title: $:/tags/TestCase/Actions
list:

View File

@@ -0,0 +1,4 @@
title: $:/DefaultTiddlers
HelloThere
$:/plugins/tiddlywiki/geospatial

View File

@@ -0,0 +1,14 @@
title: GeoFeatures
tags: $:/tags/GeospatialDemo
This is a list of all the tiddlers containing ~GeoJSON feature collections in this wiki (identified by the tag <<tag "$:/tags/GeoFeature">>). A ~GeoJSON feature collection is a list of features, each of which consists of a geometry and associated metadata.
<ul>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoFeature]sort[caption]]">
<li>
<$link>
<$transclude field="caption"><$view field="title"/></$view>
</$link>
</li>
</$list>
</ul>

View File

@@ -0,0 +1,27 @@
title: Flickr Demo
caption: Flickr
tags: $:/tags/GeospatialDemo
! Retrieve Geotagged Flickr Photos
This demo will not work until you have set a Flickr API key in the [[Geospatial plugin settings|$:/plugins/tiddlywiki/geospatial/settings]].
<$button>
<$macrocall $name="flickr-get-album-items" albumID={{$:/config/flickr-param/album-id}}/>
Get Flickr album
</$button> <$edit-text tiddler="$:/config/flickr-param/album-id" tag="input"/> (parameter should be an album ID, e.g. 72157630297432522)
<$button>
<$macrocall $name="flickr-get-interesting-items"/>
Get Flickr interesting items
</$button>
<$button>
<$macrocall $name="flickr-get-photos-of-user-items" userID={{$:/config/flickr-param/user-id}}/>
Get Flickr photos of user
</$button> <$edit-text tiddler="$:/config/flickr-param/user-id" tag="input"/> (parameter should be a user ID, e.g. 35468148136@N01)
<$button>
<$macrocall $name="flickr-get-group-items" groupID={{$:/config/flickr-param/group-id}}/>
Get Flickr group
</$button> <$edit-text tiddler="$:/config/flickr-param/group-id" tag="input"/> (parameter should be an group ID, e.g. 22075379@N00)

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 KiB

View File

@@ -0,0 +1,2 @@
title: Geospatial Plugin Logo
type: image/png

View File

@@ -0,0 +1,37 @@
title: HelloThere
//The latest build of the Geospatial Plugin can be found at:// https://tiddlywiki5-git-geospatial-plugin-jermolene.vercel.app/plugins/tiddlywiki/geospatial/index.html
!! Introduction
{{$:/plugins/tiddlywiki/geospatial/readme}}
!! Prerequisites
This demo requires that the API keys needed to access external services be obtained by the end user and manually configured. These keys are stored in the browser and so only need to be set up once. See the ''Settings'' tab of [[the plugin|$:/plugins/tiddlywiki/geospatial]] for details.
!! Demos
* Visit the ~GeoFeatures and ~GeoMarkers tabs to see the data loaded into this wiki
* Click on a link to a layer or marker to open the corresponding tiddler that includes a map
* Use the Flickr tab to retrieve geotagged photographs from Flickr
* Visit a ~GeoMarker tiddler and use the "Call ~TravelTime" button to calculate an isochrone from that location using the ~TravelTime API
! Map Showing All Features and Markers
<$geomap
state=<<qualify "$:/state/demo-map">>
startPosition="bounds"
>
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoBaseLayer]]">
<$geobaselayer title=<<currentTiddler>>/>
</$list>
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoMarker]]">
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}} name={{!!caption}}/>
</$list>
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoFeature]]">
<$geolayer json={{!!text}} color={{!!color}} name={{!!caption}}/>
</$list>
</$geomap>
<<tabs tabsList:"[all[tiddlers+shadows]tag[$:/tags/GeospatialDemo]]" default:"GeoMarkers">>

View File

@@ -0,0 +1,53 @@
title: GeoMarkers
tags: $:/tags/GeospatialDemo
\procedure onsuccess()
<$action-setfield
$tiddler="CurrentLocation"
tags="$:/tags/GeoMarker"
timestamp=<<timestamp>>
lat=<<latitude>>
long=<<longitude>>
alt=<<altitude>>
accuracy=<<accuracy>>
altitudeAccuracy=<<altitudeAccuracy>>
heading=<<heading>>
speed=<<speed>>
/>
\end
\procedure onerror()
<$action-setfield
$tiddler="CurrentLocation"
$field="text"
$value=<<error>>
/>
\end
\procedure onclick()
<$action-sendmessage
$message="tm-request-geolocation"
actionsSuccess=<<onsuccess>>
actionsError=<<onerror>>
/>
\end
This is a list of all the tiddlers containing ~GeoJSON markers in this wiki (identified by the tag <<tag "$:/tags/GeoMarker">>). A ~GeoJSON marker identifies a location via latitude and longitude (and optional altitude) and may also contain associated metadata in JSON format.
Click this button to create a marker from the current location. Your browser will ask for permission before granting the request. On some browsers it takes a couple of seconds for the location to appear.
<$button actions=<<onclick>>>
Request location
</$button>
{{CurrentLocation}}
<ul>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoMarker]sort[caption]]">
<li>
<$link>
<$view field="caption"><$view field="title"/></$view>
</$link>
</li>
</$list>
</ul>

View File

@@ -0,0 +1,3 @@
title: $:/SiteSubtitle
Geographic Data Features for ~TiddlyWiki

View File

@@ -0,0 +1,3 @@
title: $:/SiteTitle
[img width=200 [Geospatial Plugin Logo]]<br>Geospatial Plugin

View File

@@ -0,0 +1,6 @@
title: $:/plugins/geospatial/demo/ViewTemplateBodyFilters
tags: $:/tags/ViewTemplateBodyFilter
list-before: $:/config/ViewTemplateBodyFilters/stylesheet
[tag[$:/tags/GeoFeature]then[ui/geofeature]]
[tag[$:/tags/GeoMarker]then[ui/geomarker]]

View File

@@ -0,0 +1,9 @@
title: cities/LimehouseTownHall
tags: $:/tags/GeoMarker
caption: Limehouse Town Hall
lat: 51.51216651476898
long: -0.03138562132137639
alt: 0
This is Limehouse Town Hall!

View File

@@ -0,0 +1,9 @@
title: cities/Motovun
tags: $:/tags/GeoMarker
icon: Motovun Jack.svg
caption: Motovun
lat: 45.336453407749225
long: 13.828231379455806
alt: 0
This is Motovun!

View File

@@ -0,0 +1,8 @@
title: cities/NewYork
tags: $:/tags/GeoMarker
caption: New York
lat: 40.712778
long: -74.006111
alt: 0
This is New York!

View File

@@ -0,0 +1,8 @@
title: cities/Oxford
tags: $:/tags/GeoMarker
caption: Oxford
lat: 51.751944
long: -1.257778
alt: 0
This is Oxford!

View File

@@ -0,0 +1,8 @@
title: cities/Toronto
tags: $:/tags/GeoMarker
caption: Toronto
lat: 43.651070
long: -79.347015
alt: 0
This is Toronto!

View File

@@ -0,0 +1,8 @@
title: cities/Winchester
tags: $:/tags/GeoMarker
caption: Winchester
lat: 51.0632
long: -1.308
alt: 0
This is Winchester!

View File

@@ -0,0 +1,5 @@
title: $:/config/flickr-param/
album-id: 72157630297432522
user-id: 35468148136@N01
group-id: 22075379@N00

View File

@@ -0,0 +1,4 @@
title: $:/config/plugins/tiddlywiki/xlsx-utils/default-import-spec
type: text/vnd.tiddlywiki
$:/_importspec/RealEstate/

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,2 @@
title: $:/favicon.ico
type: image/png

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
title: $:/geospatialdemo/features/canada-census-subdivision-millesime
caption: Canada Census Subdivisions Millesime
type: application/json
tags: $:/tags/GeoFeature
color: #f8f

View File

@@ -0,0 +1,109 @@
title: $:/geospatialdemo/features/denver/bikerental
caption: Denver bike rentals as ~GeoJSON points
tags: $:/tags/GeoFeature
type: application/json
color: blue
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9998241,
39.7471494
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 51
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9983545,
39.7502833
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 52
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9963919,
39.7444271
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 54
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9960754,
39.7498956
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 55
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9933717,
39.7477264
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 57
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9913392,
39.7432392
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 58
},
{
"geometry": {
"type": "Point",
"coordinates": [
-104.9788452,
39.6933755
]
},
"type": "Feature",
"properties": {
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
},
"id": 74
}
]
}

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