1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-22 10:54:46 +00:00

Compare commits

...

70 Commits

Author SHA1 Message Date
Jeremy Ruston
c11b04ae9a Fix broken merge 2024-06-06 16:39:06 +01:00
Jeremy Ruston
5d2a59d20d Merge branch 'master' into logging-improvements 2024-06-06 16:32:06 +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
Joshua Fontany
f1299120a6 Block Quotes - fix parsing error with spaces before reEndString (#8186)
* fix parsing error with spaces before reEndString, update docs to clarify block mode inside block quotes.

* additional advanced example

* oops, convert spaces back to tabs.

* reset indentation

* final tabs

* missed some

* wikitext classes are appended to other leading wikitext, no need to skip whitespace here.
2024-05-15 12:25:02 +01:00
Jeremy Ruston
0b475628de Merge branch 'tiddlywiki-com' 2024-05-14 09:17:22 +01:00
twMat
24dceb1bce Update Filter Run Prefix.tid (#8188)
add relevant links
2024-05-14 08:38:30 +01:00
Jeremy Ruston
64f5dd942c Update release note 2024-05-02 11:39:25 +01:00
Jeremy Ruston
9007e0b8c8 Merge branch 'tiddlywiki-com' 2024-05-01 12:46:20 +01:00
sarna
07a048975d Improve Polish date translation (#8170)
* Make month and weekday names lowercase

* Replace AM and PM with Polish words

* Adhere to recommendations wrt short weekday names

https://sjp.pwn.pl/poradnia/haslo/dni-tygodnia-i-inne-roznosci;1788.html

* Fix a typo

* Inflect month names

I assume they're always used as part of the full date,
and in this case months are always inflected in Polish.

* Use roman numerals in place of short month names

I could not find any actual use of short month names in Polish.
The only mentions are from people trying to translate English
conventions into Polish - typically in software.

In https://sjp.pwn.pl/poradnia/haslo/dni-tygodnia-i-inne-roznosci;1788.html
Mr. Bańko answered (translation mine):
  Abbreviations of month names are less common, numbers are used instead.
  Such abbreviations can be created [...]. However, one must take into account
  that the reader will not understand them.

I decided to go with a convention that's in actual use, rather than to
force an English convention which is alien to non-software dev Poles.
2024-04-28 19:23:31 +02:00
sarna
b4e0a9b28b Signing the CLA (#8171) 2024-04-28 19:22:58 +02:00
FSpark
67845f8ebe Fix: some plugin subtiddlers do not have title in savewikifolder command (#8151)
* fix: some plugin subtiddlers do not have title in savewikifolder command

* fix: following coding style
2024-04-25 18:29:09 +02:00
Matt Lauber
a081e58273 HTTP Client: Return success calls for all 2XX response codes (#8150)
APIs especially use 2XX response codes outside of 200, 201, 204 for responding to responses.  Treat all "Successful" response codes (i.e. anything between 200-299) as successes, and pass the responseText.
2024-04-16 16:24:53 +01:00
Jeremy Ruston
1d48909012 Docs: Remove reference to restrictions on field names
Fixes #8146
2024-04-16 10:34:49 +01:00
Joshua Fontany
d3722a6602 Docs for use-browser-cache (#8142)
* docs for use-browser-cache

* Update WebServer Parameter_ use-browse-cache.tid

remove timestamps

* revert last change

* move to webserver folder

* clarify, typos

* dedupe
2024-04-13 10:08:40 +01:00
andjar
1fb9098c76 Update cla-individual.md (#8133)
Signing the CLA
2024-04-09 22:22:18 +01:00
Jermolene
22a85e8fc7 Initial improvements 2019-01-17 15:20:24 +00:00
346 changed files with 24809 additions and 506 deletions

View File

@@ -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
}
]
}

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

@@ -206,6 +206,12 @@ Stylesheets/Caption: Stylesheets
Stylesheets/Expand/Caption: Expand All
Stylesheets/Hint: This is the rendered CSS of the current stylesheet tiddlers tagged with <<tag "$:/tags/Stylesheet">>
Stylesheets/Restore/Caption: Restore
TestCases/Caption: Test Cases
TestCases/Hint: Test cases are self contained examples for testing and learning
TestCases/All/Caption: All Test Cases
TestCases/All/Hint: All Test Cases
TestCases/Failed/Caption: Failed Test Cases
TestCases/Failed/Hint: Only Failed Test Cases
Theme/Caption: Theme
Theme/Prompt: Current theme:
TiddlerFields/Caption: Tiddler Fields

View File

@@ -65,6 +65,9 @@ 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
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
site-title-foreground: Site title foreground
static-alert-foreground: Static alert foreground
tab-background-selected: Tab background for selected tabs

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

@@ -120,7 +120,7 @@ Command.prototype.fetchFile = function(url,options,callback,redirectCount) {
}
});
response.on("error",function(e) {
console.log("Error on GET request: " + e);
self.commander.log("Error on GET request: " + e);
callback(e);
});
});

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

@@ -47,7 +47,7 @@ Render individual tiddlers and save the results to the specified files
$tw.utils.each(tiddlers,function(title) {
var filepath = path.resolve(self.commander.outputPath,wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]))[0]);
if(self.commander.verbose) {
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
self.commander.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
}
var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
@@ -63,4 +63,4 @@ Render individual tiddlers and save the results to the specified files
exports.Command = Command;
})();

View File

@@ -48,7 +48,7 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
}
});
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
self.commander.log("Saving \"" + title + "\" to \"" + filepath + "\"");
}
try {
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);

View File

@@ -176,7 +176,10 @@ WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
this.saveJSONFile(directory + path.sep + "plugin.info",pluginInfo);
self.log("Writing " + directory + path.sep + "plugin.info: " + JSON.stringify(pluginInfo,null,$tw.config.preferences.jsonSpaces));
var pluginTiddlers = $tw.utils.parseJSONSafe(pluginTiddler.fields.text).tiddlers; // A hashmap of tiddlers in the plugin
$tw.utils.each(pluginTiddlers,function(tiddler) {
$tw.utils.each(pluginTiddlers,function(tiddler,title) {
if(!tiddler.title) {
tiddler.title = title;
}
self.saveTiddler(directory,new $tw.Tiddler(tiddler));
});
};

View File

@@ -70,6 +70,9 @@ 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);

View File

@@ -3,30 +3,7 @@ title: $:/core/modules/parsers/wikiparser/rules/quoteblock.js
type: application/javascript
module-type: wikirule
Wiki text rule for quote blocks. For example:
```
<<<.optionalClass(es) optional cited from
a quote
<<<
<<<.optionalClass(es)
a quote
<<< optional cited from
```
Quotes can be quoted by putting more <s
```
<<<
Quote Level 1
<<<<
QuoteLevel 2
<<<<
<<<
```
Wiki text rule for quote blocks.
\*/
(function(){
@@ -47,16 +24,15 @@ exports.init = function(parser) {
exports.parse = function() {
var classes = ["tc-quote"];
// Get all the details of the match
var reEndString = "^" + this.match[1] + "(?!<)";
var reEndString = "^\\s*" + this.match[1] + "(?!<)";
// Move past the <s
this.parser.pos = this.matchRegExp.lastIndex;
// Parse any classes, whitespace and then the optional cite itself
classes.push.apply(classes, this.parser.parseClasses());
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var cite = this.parser.parseInlineRun(/(\r?\n)/mg);
// before handling the cite, parse the body of the quote
var tree= this.parser.parseBlocks(reEndString);
var tree = this.parser.parseBlocks(reEndString);
// If we got a cite, put it before the text
if(cite.length > 0) {
tree.unshift({

View File

@@ -33,7 +33,13 @@ function Server(options) {
this.routes = options.routes || [];
this.authenticators = options.authenticators || [];
this.wiki = options.wiki;
this.logger = new $tw.utils.Logger("server",{colour: "cyan"});
this.logger.setPrefix(":" + process.pid + "-" + (Number(new Date()) - 1095776640000));
this.boot = options.boot || $tw.boot;
// Name the server and init the boot state
this.servername = $tw.utils.transliterateToSafeASCII(this.get("server-name") || this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
this.boot.origin = this.get("origin")? this.get("origin"): this.protocol+"://"+this.get("host")+":"+this.get("port");
this.boot.pathPrefix = this.get("path-prefix") || "";
// Initialise the variables
this.variables = $tw.utils.extend({},this.defaultVariables);
if(options.variables) {
@@ -92,10 +98,6 @@ function Server(options) {
this.protocol = "https";
}
this.transport = require(this.protocol);
// Name the server and init the boot state
this.servername = $tw.utils.transliterateToSafeASCII(this.get("server-name") || this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
this.boot.origin = this.get("origin")? this.get("origin"): this.protocol+"://"+this.get("host")+":"+this.get("port");
this.boot.pathPrefix = this.get("path-prefix") || "";
}
/*
@@ -287,9 +289,9 @@ Server.prototype.requestHandler = function(request,response,options) {
var route = self.findMatchingRoute(request,state);
// Optionally output debug info
if(self.get("debug-level") !== "none") {
console.log("Request path:",JSON.stringify(state.urlInfo));
console.log("Request headers:",JSON.stringify(request.headers));
console.log("authenticatedUsername:",state.authenticatedUsername);
self.logger.log("Request path:",JSON.stringify(state.urlInfo.href));
self.logger.log("Request headers:",JSON.stringify(request.headers));
self.logger.log("authenticatedUsername:",state.authenticatedUsername);
}
// Return a 404 if we didn't find a route
if(!route) {

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

@@ -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(),
@@ -283,7 +295,7 @@ exports.httpRequest = function(options) {
// Set up the state change handler
request.onreadystatechange = function() {
if(this.readyState === 4) {
if(this.status === 200 || this.status === 201 || this.status === 204) {
if(this.status >= 200 && this.status < 300) {
// Success!
options.callback(null,this[returnProp],this);
return;
@@ -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

@@ -21,6 +21,7 @@ function Logger(componentName,options) {
options = options || {};
this.componentName = componentName || "";
this.colour = options.colour || "white";
this.prefix = options.prefix || "";
this.enable = "enable" in options ? options.enable : true;
this.save = "save" in options ? options.save : true;
this.saveLimit = options.saveLimit || 100 * 1024;
@@ -33,6 +34,20 @@ Logger.prototype.setSaveBuffer = function(logger) {
this.saveBufferLogger = logger;
};
/*
Change the output colour
*/
Logger.prototype.setColour = function(colour) {
this.colour = colour || "white";
};
/*
Change the prefix
*/
Logger.prototype.setPrefix = function(prefix) {
this.prefix = prefix || "";
};
/*
Log a message
*/

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

@@ -0,0 +1,182 @@
/*\
title: $:/core/modules/widgets/data.js
type: application/javascript
module-type: widget
Widget to dynamically represent one or more tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var DataWidget = function(parseTreeNode,options) {
this.dataWidgetTag = parseTreeNode.type;
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
DataWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
DataWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
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() {
// Nothing to do here
};
/*
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;
// 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;
}
});
// Deal with $tiddler, $filter or $compound-tiddler attributes
var tiddlers = [],title;
if(this.hasAttribute("$tiddler")) {
title = this.getAttribute("$tiddler");
if(title) {
var tiddler = this.wiki.getTiddler(title);
if(tiddler) {
tiddlers.push(tiddler);
}
}
}
if(this.hasAttribute("$filter")) {
var filter = this.getAttribute("$filter");
if(filter) {
var titles = this.wiki.filterTiddlers(filter);
$tw.utils.each(titles,function(title) {
var tiddler = self.wiki.getTiddler(title);
tiddlers.push(tiddler);
});
}
}
if(this.hasAttribute("$compound-tiddler")) {
title = this.getAttribute("$compound-tiddler");
if(title) {
tiddlers.push.apply(tiddlers,this.extractCompoundTiddler(title));
}
}
// 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 [new $tw.Tiddler(item)];
} else {
return [];
}
} else {
// 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;
}
};
/*
Helper to extract tiddlers from text/vnd.tiddlywiki-multiple tiddlers
*/
DataWidget.prototype.extractCompoundTiddler = function(title) {
var tiddler = this.wiki.getTiddler(title);
if(tiddler && tiddler.fields.type === "text/vnd.tiddlywiki-multiple") {
var text = tiddler.fields.text || "",
rawTiddlers = text.split(/\r?\n\+\r?\n/),
tiddlers = [];
$tw.utils.each(rawTiddlers,function(rawTiddler) {
var fields = Object.create(null),
split = rawTiddler.split(/\r?\n\r?\n/mg);
if(split.length >= 1) {
fields = $tw.utils.parseFields(split[0],fields);
}
if(split.length >= 2) {
fields.text = split.slice(1).join("\n\n");
}
tiddlers.push(new $tw.Tiddler(fields));
});
return tiddlers;
} else {
return [];
}
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DataWidget.prototype.refresh = function(changedTiddlers) {
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

@@ -0,0 +1,165 @@
/*\
title: $:/core/modules/widgets/testcase.js
type: application/javascript
module-type: widget
Widget to display a test case
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var TestCaseWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
TestCaseWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
TestCaseWidget.prototype.render = function(parent,nextSibling) {
var self = this;
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create container DOM node
var domNode = this.document.createElement("div");
this.domNodes.push(domNode);
parent.insertBefore(domNode,nextSibling);
// Render the children into a hidden DOM node
var parser = {
tree: [{
type: "widget",
attributes: {},
orderedAttributes: [],
children: this.parseTreeNode.children || []
}]
};
this.contentRoot = this.wiki.makeWidget(parser,{
document: $tw.fakeDocument,
parentWidget: this
});
this.contentContainer = $tw.fakeDocument.createElement("div");
this.contentRoot.render(this.contentContainer,null);
// Create a wiki
this.testcaseWiki = new $tw.Wiki();
// Always load the core plugin
var loadTiddler = function(title) {
var tiddler = self.wiki.getTiddler(title);
if(tiddler) {
self.testcaseWiki.addTiddler(tiddler);
}
}
loadTiddler("$:/core");
loadTiddler("$:/plugins/tiddlywiki/codemirror");
// Load tiddlers from child data widgets
var tiddlers = [];
this.findChildrenDataWidgets(this.contentRoot.children,"data",function(widget) {
Array.prototype.push.apply(tiddlers,widget.readDataTiddlerValues());
});
var jsonPayload = JSON.stringify(tiddlers);
this.testcaseWiki.addTiddlers(tiddlers);
// Unpack plugin tiddlers
this.testcaseWiki.readPluginInfo();
this.testcaseWiki.registerPluginTiddlers("plugin");
this.testcaseWiki.unpackPluginTiddlers();
this.testcaseWiki.addIndexersToWiki();
// Generate a `transclusion` variable that depends on the values of the payload tiddlers so that the template can easily make unique state tiddlers
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(shouldRunTests) {
var testcaseOutputContainer = $tw.fakeDocument.createElement("div");
var testcaseOutputWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTestOutput,{
document: $tw.fakeDocument,
parseAsInline: false,
parentWidget: this,
variables: {
currentTiddler: this.testcaseTestOutput
}
});
testcaseOutputWidget.render(testcaseOutputContainer);
}
// Clear changes queue
this.testcaseWiki.clearTiddlerEventQueue();
// Run the actions if provided
if(this.testcaseWiki.tiddlerExists(this.testcaseTestActions)) {
testcaseOutputWidget.invokeActionString(this.testcaseWiki.getTiddlerText(this.testcaseTestActions));
testcaseOutputWidget.refresh(this.testcaseWiki.changedTiddlers,testcaseOutputContainer);
}
// Set up the test result variables
var testResult = "",
outputHTML = "",
expectedHTML = "";
if(shouldRunTests) {
outputHTML = testcaseOutputContainer.children[0].innerHTML;
expectedHTML = this.testcaseWiki.getTiddlerText(this.testcaseTestExpectedResult);
if(outputHTML === expectedHTML) {
testResult = "pass";
} else {
testResult = "fail";
}
this.setVariable("outputHTML",outputHTML);
this.setVariable("expectedHTML",expectedHTML);
this.setVariable("testResult",testResult);
this.setVariable("currentTiddler",this.testcaseTestOutput);
}
// Don't display anything if testHideIfPass is "yes" and the tests have passed
if(this.testcaseHideIfPass === "yes" && testResult !== "fail") {
return;
}
// Render the page root template of the subwiki
var rootWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTemplate,{
document: this.document,
parseAsInline: false,
parentWidget: this
});
rootWidget.render(domNode);
// Trap changes in the wiki and refresh the rendering
this.testcaseWiki.addEventListener("change",function(changes) {
rootWidget.refresh(changes,domNode);
});
};
/*
Compute the internal state of the widget
*/
TestCaseWidget.prototype.execute = function() {
this.testcaseTemplate = this.getAttribute("template","$:/core/ui/testcases/DefaultTemplate");
this.testcaseTestOutput = this.getAttribute("testOutput");
this.testcaseTestActions = this.getAttribute("testActions");
this.testcaseTestExpectedResult = this.getAttribute("testExpectedResult");
this.testcaseHideIfPass = this.getAttribute("testHideIfPass");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
TestCaseWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if($tw.utils.count(changedAttributes) > 0) {
this.refreshSelf();
return true;
} else {
return this.contentRoot.refresh(changedTiddlers);
}
};
exports["testcase"] = TestCaseWidget;
})();

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) {
@@ -813,6 +811,21 @@ Widget.prototype.allowActionPropagation = function() {
return true;
};
/*
Find child <$data> widgets recursively. The tag name allows aliased versions of the widget to be found too
*/
Widget.prototype.findChildrenDataWidgets = function(children,tag,callback) {
var self = this;
$tw.utils.each(children,function(child) {
if(child.dataWidgetTag === tag) {
callback(child);
}
if(child.children) {
self.findChildrenDataWidgets(child.children,tag,callback);
}
});
};
/*
Evaluate a variable with parameters. This is a static convenience method that attempts to evaluate a variable as a function, returning an array of strings
*/

View File

@@ -95,6 +95,9 @@ table-footer-background: #a8a8a8
table-header-background: #f0f0f0
tag-background: #ec6
tag-foreground: #ffffff
testcase-accent-level-1: #84C5E6
testcase-accent-level-2: #E3B740
testcase-accent-level-3: #5FD564
tiddler-background: <<colour background>>
tiddler-border: <<colour background>>
tiddler-controls-foreground-hover: #888888

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

@@ -0,0 +1,10 @@
title: $:/core/ui/ControlPanel/TestCases
tags: $:/tags/ControlPanel/Advanced
caption: {{$:/language/ControlPanel/TestCases/Caption}}
\whitespace trim
{{$:/language/ControlPanel/TestCases/Hint}}
<div class="tc-control-panel">
<$macrocall $name="tabs" tabsList="[all[shadows+tiddlers]tag[$:/tags/ControlPanel/TestCases]!has[draft.of]]" default="$:/core/ui/ControlPanel/TestCases/All"/>
</div>

View File

@@ -0,0 +1,24 @@
title: $:/core/ui/ControlPanel/TestCases/All
tags: $:/tags/ControlPanel/TestCases
caption: {{$:/language/ControlPanel/TestCases/All/Caption}}
\define lingo-base() $:/language/ControlPanel/
<<lingo TestCases/All/Hint>>
<$list filter="[all[tiddlers+shadows]tag[$:/tags/wiki-test-spec]type[text/vnd.tiddlywiki-multiple]] [all[tiddlers+shadows]tag[$:/tags/wiki-test-spec-failing]type[text/vnd.tiddlywiki-multiple]]">
<h2>
<$link>
<$text text=<<currentTiddler>>/>
</$link>
</h2>
<$transclude
$tiddler="$:/core/ui/TestCaseTemplate"
/>
</$list>

View File

@@ -0,0 +1,15 @@
title: $:/core/ui/ControlPanel/TestCases/Failed
tags: $:/tags/ControlPanel/TestCases
caption: {{$:/language/ControlPanel/TestCases/Failed/Caption}}
\define lingo-base() $:/language/ControlPanel/
<<lingo TestCases/Failed/Hint>>
<$list filter="[all[tiddlers+shadows]tag[$:/tags/wiki-test-spec]type[text/vnd.tiddlywiki-multiple]] [all[tiddlers+shadows]tag[$:/tags/wiki-test-spec-failing]type[text/vnd.tiddlywiki-multiple]]">
<$transclude
$tiddler="$:/core/ui/TestCaseTemplate"
hideIfPass="yes"
/>
</$list>

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

@@ -0,0 +1,19 @@
title: $:/core/ui/TestCaseTemplate
\parameters (hideIfPass:"no")
\whitespace trim
<$let
linkTarget="yes"
displayFormat={{!!display-format}}
testcaseTiddler=<<currentTiddler>>
>
<$testcase
testOutput="Output"
testExpectedResult="ExpectedResult"
testActions="Actions"
testHideIfPass=<<hideIfPass>>
>
<$data $compound-tiddler=<<currentTiddler>>/>
<$data title="Description" text={{!!description}}/>
</$testcase>
</$let>

View File

@@ -0,0 +1,66 @@
title: $:/core/ui/testcases/DefaultTemplate
\whitespace trim
\procedure linkcatcherActions()
<%if [<navigateTo>has[title]] %>
<$qualify title=<<state>> name="qualifiedState">
<$action-setfield $tiddler=<<qualifiedState>> text=<<navigateTo>>/>
</$qualify>
<%endif%>
\end
<$let
state={{{ [<qualify "$:/state/testcase">] }}}
>
<div class="tc-test-case-wrapper">
<div class="tc-test-case-header">
<h2>
<$genesis $type={{{ [<linkTarget>!match[]then[$link]else[div]] }}} 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]] %>
{{$:/core/images/done-button}}
<%else%>
{{$:/core/images/close-button}}
<%endif%>
</span>
<%endif%>
<$view tiddler="Description" mode="inline"/>
</$genesis>
</h2>
</div>
<%if [[Narrative]is[tiddler]] %>
<div class="tc-test-case-narrative">
<$transclude $tiddler="Narrative" mode="block"/>
</div>
<%endif%>
<%if [<testResult>match[fail]] %>
<div class="tc-test-case-result-fail">
<div class="tc-test-case-result-fail-header">
TEST FAILED
</div>
<div class="tc-test-case-result-fail-body">
<$diff-text source=<<expectedHTML>> dest=<<outputHTML>>/>
</div>
</div>
<%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"/>
</div>
<div class="tc-test-case-divider">
</div>
<div class="tc-test-case-output">
<%if [<displayFormat>!match[]else[wikitext]match[plaintext]] %>
<pre><$view tiddler="Output" format="plainwikified" mode="block"/></pre>
<%else%>
<$linkcatcher actions=<<linkcatcherActions>>>
<$tiddler tiddler="Output">
<$transclude $tiddler="Output" $mode="block"/>
</$tiddler>
</$linkcatcher>
<%endif%>
</div>
</div>
</div>
</$let>

View File

@@ -0,0 +1,24 @@
title: $:/core/ui/testcases/DefaultTemplate/SourceTabs
\whitespace trim
\procedure body()
<$list filter="[<currentTab>fields[]] -text +[limit[1]]" variable="ignore">
<table class="tc-field-table">
<tbody>
<$list filter="[<currentTab>fields[]sort[]] -text -title title +[putfirst[]]" variable="fieldName">
<tr>
<td>
<$text text=<<fieldName>>/>
</td>
<td>
<$view tiddler=<<currentTab>> field=<<fieldName>>/>
</td>
</tr>
</$list>
</tbody>
</table>
</$list>
<$edit class="tc-edit-texteditor" tiddler=<<currentTab>>/>
\end
<$transclude $variable="body" $mode="inline"/>

View File

@@ -0,0 +1,4 @@
title: $:/core/ui/testcases/RawJSONTemplate
\whitespace trim
<$text text=<<payloadTiddlers>>/>

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.4/index.html
caption: {{$:/language/OfficialPluginLibrary}}
{{$:/language/OfficialPluginLibrary/Hint}}

View File

@@ -1,6 +1,7 @@
title: $:/config/ViewTemplateBodyFilters/
tags: $:/tags/ViewTemplateBodyFilter
testcase: [tag[$:/tags/wiki-test-spec]type[text/vnd.tiddlywiki-multiple]then[$:/core/ui/TestCaseTemplate]] [tag[$:/tags/wiki-test-spec-failing]type[text/vnd.tiddlywiki-multiple]then[$:/core/ui/TestCaseTemplate]]
stylesheet: [tag[$:/tags/Stylesheet]then[$:/core/ui/ViewTemplate/body/rendered-plain-text]]
core-ui-tags: [tag[$:/tags/PageTemplate]] [tag[$:/tags/EditTemplate]] [tag[$:/tags/ViewTemplate]] [tag[$:/tags/KeyboardShortcut]] [tag[$:/tags/ImportPreview]] [tag[$:/tags/EditPreview]][tag[$:/tags/EditorToolbar]] [tag[$:/tags/Actions]] :then[[$:/core/ui/ViewTemplate/body/code]]
system: [prefix[$:/boot/]] [prefix[$:/config/]] [prefix[$:/core/macros]] [prefix[$:/core/save/]] [prefix[$:/core/templates/]] [prefix[$:/info/]] [prefix[$:/language/]] [prefix[$:/languages/]] [prefix[$:/snippets/]] [prefix[$:/state/]] [prefix[$:/status/]] [prefix[$:/info/]] [prefix[$:/temp/]] +[!is[image]limit[1]then[$:/core/ui/ViewTemplate/body/code]]

View File

@@ -0,0 +1,10 @@
title: $:/core/macros/testcase
tags: $:/tags/Macro $:/tags/Global
\whitespace trim
\procedure testcase(tiddler)
<$tiddler tiddler=<<tiddler>>>
<$transclude $tiddler="$:/core/ui/TestCaseTemplate">
</$tiddler>
\end

View File

@@ -1,2 +1,2 @@
title: $:/tags/ViewTemplateBodyFilter
list: $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/code-body $:/config/ViewTemplateBodyFilters/stylesheet $:/config/ViewTemplateBodyFilters/core-ui-advanced-search $:/config/ViewTemplateBodyFilters/core-ui-tags $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/default
list: $:/config/ViewTemplateBodyFilters/testcase $:/config/ViewTemplateBodyFilters/hide-body $:/config/ViewTemplateBodyFilters/code-body $:/config/ViewTemplateBodyFilters/stylesheet $:/config/ViewTemplateBodyFilters/core-ui-advanced-search $:/config/ViewTemplateBodyFilters/core-ui-tags $:/config/ViewTemplateBodyFilters/system $:/config/ViewTemplateBodyFilters/import $:/config/ViewTemplateBodyFilters/plugin $:/config/ViewTemplateBodyFilters/default

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
}
]
}

View File

@@ -0,0 +1,63 @@
title: $:/geospatialdemo/features/denver/campus
caption: Denver Auraria West Campus as ~GeoJSON multipolygons
tags: $:/tags/GeoFeature
type: application/json
color: purple
{
"type": "Feature",
"properties": {
"popupContent": "This is the Auraria West Campus",
"style": {
"weight": 2,
"color": "#999",
"opacity": 1,
"fillColor": "#B0DE5C",
"fillOpacity": 0.8
}
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[-105.00432014465332, 39.74732195489861],
[-105.00715255737305, 39.74620006835170],
[-105.00921249389647, 39.74468219277038],
[-105.01067161560059, 39.74362625960105],
[-105.01195907592773, 39.74290029616054],
[-105.00989913940431, 39.74078835902781],
[-105.00758171081543, 39.74059036160317],
[-105.00346183776855, 39.74059036160317],
[-105.00097274780272, 39.74059036160317],
[-105.00062942504881, 39.74072235994946],
[-105.00020027160645, 39.74191033368865],
[-105.00071525573731, 39.74276830198601],
[-105.00097274780272, 39.74369225589818],
[-105.00097274780272, 39.74461619742136],
[-105.00123023986816, 39.74534214278395],
[-105.00183105468751, 39.74613407445653],
[-105.00432014465332, 39.74732195489861]
],[
[-105.00361204147337, 39.74354376414072],
[-105.00301122665405, 39.74278480127163],
[-105.00221729278564, 39.74316428375108],
[-105.00283956527711, 39.74390674342741],
[-105.00361204147337, 39.74354376414072]
]
],[
[
[-105.00942707061768, 39.73989736613708],
[-105.00942707061768, 39.73910536278566],
[-105.00685214996338, 39.73923736397631],
[-105.00384807586671, 39.73910536278566],
[-105.00174522399902, 39.73903936209552],
[-105.00041484832764, 39.73910536278566],
[-105.00041484832764, 39.73979836621592],
[-105.00535011291504, 39.73986436617916],
[-105.00942707061768, 39.73989736613708]
]
]
]
}
}

View File

@@ -0,0 +1,56 @@
title: $:/geospatialdemo/features/denver/freebus
caption: Denver free bus routes as ~GeoJSON linestrings
tags: $:/tags/GeoFeature
type: application/json
color: green
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.00341892242432, 39.75383843460583],
[-105.0008225440979, 39.751891803969535]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": false
},
"id": 1
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-105.0008225440979, 39.751891803969535],
[-104.99820470809937, 39.74979664004068]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": true
},
"id": 2
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-104.99820470809937, 39.74979664004068],
[-104.98689651489258, 39.741052354709055]
]
},
"properties": {
"popupContent": "This is a free bus line that will take you across downtown.",
"underConstruction": false
},
"id": 3
}
]
}

View File

@@ -0,0 +1,30 @@
title: $:/geospatialdemo/features/denver/lightrail
caption: Denver light rail stops as ~GeoJSON points
tags: $:/tags/GeoFeature
type: application/json
color: red
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"popupContent": "18th & California Light Rail Stop"
},
"geometry": {
"type": "Point",
"coordinates": [-104.98999178409576, 39.74683938093904]
}
},{
"type": "Feature",
"properties": {
"popupContent": "20th & Welton Light Rail Stop"
},
"geometry": {
"type": "Point",
"coordinates": [-104.98689115047453, 39.747924136466565]
}
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
title: $:/geospatialdemo/features/harvard-volcanoes-of-the-world
caption: Harvard Volcanoes of the World
type: application/json
tags: $:/tags/GeoFeature/Hidden
color: #f88

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
title: $:/geospatialdemo/features/us-states
caption: US State Boundaries
type: application/json
tags: $:/tags/GeoFeature
color: #88f

View File

@@ -0,0 +1,99 @@
title: real-estate-demo
caption: Real Estate Demo
tags: $:/tags/GeospatialDemo
\define default-display-filter() [<currentTiddler>get<fieldname>]
\define default-limit() 10
This is a list of all the tiddlers containing ~GeoJSON markers in this wiki (identified by the tag <<tag "$:/tags/GeoMarker">>) viewed as both a map and a table.
<$let
schema={{real-estate-demo/schema}}
>
<div>
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
<$let
config={{{ [<schema>jsonget[columns],<index>,[name]addprefix[$:/config/geospatial/demo/real-estate-demo/columns/]] }}}
>
<div>
<$checkbox tiddler=<<config>> field="visible" checked="yes" unchecked="no" default="yes">
<$text text={{{ [<schema>jsonget[columns],<index>,[caption]] }}}/>
</$checkbox>
</div>
</$let>
</$list>
</div>
<div>
Sorting by
<$select tiddler="$:/config/geospatial/demo/real-estate-demo/sort-field" default="title">
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
<option value={{{ [<schema>jsonget[columns],<index>,[name]] }}}>
<$text text={{{ [<schema>jsonget[columns],<index>,[caption]] }}}/>
</option>
</$list>
</$select>
<$checkbox tiddler="$:/config/geospatial/demo/real-estate-demo/sort-order" field="text" checked="reverse" unchecked="normal" default="normal">
Reverse sort order
</$checkbox>
</div>
<div>
Search: <$edit-text tiddler="$:/config/geospatial/demo/real-estate-demo/search" tag="input"/>
</div>
<div>
Limit: <$edit-text tiddler="$:/config/geospatial/demo/real-estate-demo/limit" tag="input" placeholder=<<default-limit>>/>
</div>
<table>
<thead>
<tr>
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
<$let
config={{{ [<schema>jsonget[columns],<index>,[name]addprefix[$:/config/geospatial/demo/real-estate-demo/columns/]] }}}
>
<$list filter="[<config>get[visible]else[yes]match[yes]]" variable="ignore">
<th>
<$text text={{{ [<schema>jsonget[columns],<index>,[caption]] }}}/>
</th>
</$list>
</$let>
</$list>
</tr>
</thead>
<tbody>
<$let
sortField={{{ [[$:/config/geospatial/demo/real-estate-demo/sort-field]get[text]else[title]] }}}
sortOrder={{{ [[$:/config/geospatial/demo/real-estate-demo/sort-order]get[text]else[normal]] }}}
limit={{{ [[$:/config/geospatial/demo/real-estate-demo/limit]get[text]] :else[<default-limit>] }}}
>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoMarker]search:*{$:/config/geospatial/demo/real-estate-demo/search}nsort<sortField>order<sortOrder>limit<limit>]">
<$let
rowTiddler=<<currentTiddler>>
>
<$setmultiplevariables
$names="[<schema>jsonindexes[variables]sort[]]"
$values="[<schema>jsonindexes[variables]sort[]] :map[<schema>jsonget[variables],<currentTiddler>] :map[subfilter<currentTiddler>]"
>
<tr>
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
<$let
config={{{ [<schema>jsonget[columns],<index>,[name]addprefix[$:/config/geospatial/demo/real-estate-demo/columns/]] }}}
>
<$list filter="[<config>get[visible]else[yes]match[yes]]" variable="ignore">
<td>
<$let
fieldname={{{ [<schema>jsonget[columns],<index>,[name]] }}}
displayFilter={{{ [<schema>jsonget[columns],<index>,[display]] :else[<default-display-filter>] }}}
>
<$text text={{{ [subfilter<displayFilter>] }}}/>
</$let>
</td>
</$list>
</$let>
</$list>
</tr>
</$setmultiplevariables>
</$let>
</$list>
</$let>
</tbody>
</table>
</$let>

View File

@@ -0,0 +1,22 @@
{
"columns": [
{"name": "address", "caption": "Address", "type": "string"},
{"name": "broker", "caption": "Broker", "type": "string"},
{"name": "city", "caption": "City", "type": "string"},
{"name": "lat", "caption": "Latitude", "type": "number"},
{"name": "long", "caption": "Longitude", "type": "number"},
{"name": "price", "caption": "Price", "type": "number"},
{"name": "salesagent", "caption": "Sales Agent", "type": "string"},
{"name": "state", "caption": "State", "type": "string"},
{"name": "title", "caption": "Title", "type": "string"},
{"name": "zipcode", "caption": "Zip Code", "type": "string"},
{"name": "census-province", "caption": "Census Province", "type": "string", "display": "[<census-data>jsonget[0],[prov_name_en],[0]]"},
{"name": "census-division", "caption": "Census Division", "type": "string", "display": "[<census-data>jsonget[0],[cd_name_en],[0]]"},
{"name": "census-subdivision", "caption": "Census Subdivision", "type": "string", "display": "[<census-data>jsonget[0],[csd_name_en],[0]]"},
{"name": "nearest-volcano", "caption": "Nearest Volcano", "type": "string", "display": "[{$:/geospatialdemo/features/harvard-volcanoes-of-the-world}geonearestpoint<coords>]"}
],
"variables": {
"coords": "[<rowTiddler>] :map[geopoint{!!long},{!!lat}]",
"census-data": "[<rowTiddler>] :map[geopoint{!!long},{!!lat}geolookup{$:/geospatialdemo/features/canada-census-subdivision-millesime}]"
}
}

View File

@@ -0,0 +1,3 @@
title: real-estate-demo/schema
type: application/json

View File

@@ -0,0 +1,5 @@
import-spec-role: row
list: $:/_importspec/RealEstate/PropertiesRow/Field/long $:/_importspec/RealEstate/PropertiesRow/Field/lat $:/_importspec/RealEstate/PropertiesRow/Field/price $:/_importspec/RealEstate/PropertiesRow/Field/broker $:/_importspec/RealEstate/PropertiesRow/Field/salesagent $:/_importspec/RealEstate/PropertiesRow/Field/zipcode $:/_importspec/RealEstate/PropertiesRow/Field/state $:/_importspec/RealEstate/PropertiesRow/Field/city $:/_importspec/RealEstate/PropertiesRow/Field/tags $:/_importspec/RealEstate/PropertiesRow/Field/title $:/_importspec/RealEstate/PropertiesRow/Field/address
tags:
title: $:/_importspec/RealEstate/PropertiesRow
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-field-column: Address
import-field-name: address
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/address
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-field-column: Broker
import-field-name: broker
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/broker
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-field-column: City
import-field-name: city
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/city
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,8 @@
import-field-column: Latitude
import-field-name: lat
import-field-type: number
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/lat
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,8 @@
import-field-column: Longitude
import-field-name: long
import-field-type: number
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/long
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,8 @@
import-field-column: Price
import-field-name: price
import-field-type: number
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/price
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-field-column: Sales Agent
import-field-name: salesagent
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/salesagent
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-field-column: State
import-field-name: state
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/state
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-spec-role: field
import-field-name: tags
import-field-type: string
import-field-source: constant
import-field-value: $:/tags/GeoMarker
title: $:/_importspec/RealEstate/PropertiesRow/Field/tags
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,8 @@
import-field-column: Address
import-field-name: title
import-field-source: column
import-spec-role: field
import-field-skip-tiddler-if-blank: yes
title: $:/_importspec/RealEstate/PropertiesRow/Field/title
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-field-column: Zip Code
import-field-name: zipcode
import-field-source: column
import-spec-role: field
title: $:/_importspec/RealEstate/PropertiesRow/Field/zipcode
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
import-sheet-name: Final Day 1 and 2
import-spec-role: sheet
list: [[$:/_importspec/RealEstate/PropertiesRow]]
tags:
title: $:/_importspec/RealEstate/PropertiesSheet
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,7 @@
caption: Real Estate Listing Demo
import-spec-role: workbook
list: [[$:/_importspec/RealEstate/PropertiesSheet]]
tags:
title: $:/_importspec/RealEstate/
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,2 @@
title: $:/themes/tiddlywiki/vanilla/options/sidebarlayout
text: fluid-fixed

View File

@@ -0,0 +1,39 @@
title: ui/geofeature
\define create-intersection()
<$let
intersectLayer={{{ =[<currentTiddler>get[text]] =[<otherFeature>get[text]] +[geointersect[]] }}}
>
<$action-createtiddler $basetitle="$:/temp/_IsochroneLayer" text={{{ [<intersectLayer>] }}} tags="$:/tags/GeoFeature" caption={{{ [<captionThisFeature>addsuffix[ intersected with ]addsuffix<captionOtherFeature>] }}}/>
</$let>
\end
!! Mapped
<$geomap
state=<<qualify "$:/state/demo-map">>
startPosition="bounds"
>
<$geolayer json={{!!text}} color={{!!color}}/>
</$geomap>
!! Intersect with other features
<$let
captionThisFeature={{{ [<currentTiddler>get[caption]else<currentTiddler>] }}}
>
<ul>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoFeature]sort[caption]] -[<currentTiddler>]" variable="otherFeature">
<$let
captionOtherFeature={{{ [<otherFeature>get[caption]else<otherFeature>] }}}
>
<li>
<$link to=<<otherFeature>>><$transclude tiddler=<<otherFeature>> field="caption"><$view tiddler=<<otherFeature>> field="title"/></$transclude></$link>
<$button actions=<<create-intersection>>>
Create intersection
</$button>
</li>
</$let>
</$list>
</ul>
</$let>

View File

@@ -0,0 +1,128 @@
title: ui/geomarker
\define default-traveltime-time() 5400
\define completion-actions()
<$action-log/>
<$action-setfield $tiddler="$:/temp/_StatusCode" text=<<status>>/>
<$action-setfield $tiddler="$:/temp/_StatusText" text=<<statusText>>/>
<$action-setfield $tiddler="$:/temp/_Error" text=<<error>>/>
<$action-setfield $tiddler="$:/temp/_Result" text=<<data>>/>
<$action-setfield $tiddler="$:/temp/_Headers" text=<<headers>>/>
<$list filter="[<status>compare:number:gteq[200]compare:number:lteq[299]]" variable="ignore">
<$action-createtiddler $basetitle="$:/temp/_IsochroneLayer" text={{{ [<data>] }}} tags="$:/tags/GeoFeature" caption={{{ [<currentTiddler>get[caption]else<currentTiddler>addprefix[Travel time from ]] }}}/>
</$list>
\end
\define progress-actions()
<$action-log message="In progress-actions"/>
<$action-log/>
\end
\define payload-source()
\rules only transcludeinline transcludeblock filteredtranscludeinline filteredtranscludeblock
{
"departure_searches": [
{
"id": "My first isochrone",
"coords": {
"lat": {{!!lat}},
"lng": {{!!long}}
},
"departure_time": "2023-02-27T08:00:00Z",
"travel_time": {{{ [[$:/config/plugins/geospatial/traveltime/time]get[text]else<default-traveltime-time>] }}},
"transportation": {
"type": "driving"
}
}
]
}
\end
\define get-traveltime-actions()
<$wikify name="payload" text=<<payload-source>>>
<$action-log $message="Making payload"/>
<$action-log/>
<$action-sendmessage
$message="tm-http-request"
url="https://api.traveltimeapp.com/v4/time-map"
method="POST"
header-accept="application/geo+json"
header-Content-Type="application/json"
password-header-X-Api-Key="traveltime-secret-key"
password-header-X-Application-Id="traveltime-application-id"
body=<<payload>>
var-currentTiddler=<<currentTiddler>>
bind-status="$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/status"
bind-progress="$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/progress"
oncompletion=<<completion-actions>>
onprogress=<<progress-actions>>
/>
</$wikify>
\end
!! Mapped
<$geomap
state=<<qualify "$:/state/demo-map">>
startPosition="bounds"
>
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
</$geomap>
!! Distance to other markers
<$let
thisLocation={{{ [geopoint{!!long},{!!lat}] }}}
>
<ul>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoMarker]sort[caption]] -[<currentTiddler>]">
<li>
<$link><$view field="caption"><$view field="title"/></$view></$link>
--
<$let
otherLocation={{{ [geopoint{!!long},{!!lat}] }}}
>
<$text text={{{ [geodistance<thisLocation>,<otherLocation>,[miles]fixed[0]] }}}/> miles
</$let>
</li>
</$list>
</ul>
</$let>
!! GeoFeature Lookups
<$let
thisLocation={{{ [geopoint{!!long},{!!lat}] }}}
>
<ul>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoFeature]sort[caption]]">
<li>
<$text text={{{ [<currentTiddler>get[caption]] :else[<currentTiddler>] }}}/> --
<$text text={{{ [<thisLocation>geolookup{!!text}] }}}/>
</li>
</$list>
</ul>
</$let>
!! Travel Time
<$button actions=<<get-traveltime-actions>>>
Call ~TravelTime
</$button>
Maximum time: <$edit-text tiddler="$:/config/plugins/geospatial/traveltime/time" default=<<default-traveltime-time>> tag="input"/> seconds
|Status |<$text text={{$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/status}}/> |
|Progress |<$text text={{$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/progress}}/> |
|Status Code |<$text text={{$:/temp/_StatusCode}}/> |
|Status Text |<$text text={{$:/temp/_StatusText}}/> |
|Error |<$text text={{$:/temp/_Error}}/> |
<$list filter="[<currentTiddler>has[photo-url]]" variable="ignore">
!! Photo
<img src={{!!photo-url}}/>
</$list>

View File

@@ -0,0 +1,23 @@
{
"description": "Demo of the geospatial plugin for TiddlyWiki",
"plugins": [
"tiddlywiki/geospatial",
"tiddlywiki/jszip",
"tiddlywiki/xlsx-utils",
"tiddlywiki/codemirror"
],
"themes": [
"tiddlywiki/vanilla",
"tiddlywiki/snowwhite"
],
"includeWikis": [
],
"build": {
"index": [
"--render","$:/core/save/all","index.html","text/plain"],
"favicon": [],
"static": [],
"empty": [],
"encrypted": []
}
}

View File

@@ -1,6 +1,6 @@
caption: 5.3.4
created: 20231223102229103
modified: 20231223102229103
created: 20240529100240232
modified: 20240529100240232
tags: ReleaseNotes
title: Release 5.3.4
type: text/vnd.tiddlywiki
@@ -10,36 +10,105 @@ description: Under development
! Major Improvements
!! Tour Plugin
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7734">> several new features that together allow interactive learning tours to be created and presented in TiddlyWiki.
The demo TiddlyWiki interactive tour can be seen at https://tiddlywiki.com/prerelease/tour
The new features include:
* The new Tour Plugin itself
* The new Confetti Plugin that allows animated bursts of confetti to be displayed
* Improvements to the Dynannotate Plugin to add the ability to highlight screen elements using an animated spotlight effect
!! Geospatial Plugin
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7406">> new Geospatial Plugin that adds new primitives to the TiddlyWiki platform to enable non-developers to build sophisticated interactive geospatial applications.
The Geospatial Plugin incorporates a number of third party libraries and online services:
* [[Leaflet.js|https://leafletjs.com/]], an open source library to display interactive maps
* [[Turf.js|https://turfjs.org/]], an open source library to perform geospatial calculations with [[GeoJSON|https://en.wikipedia.org/wiki/GeoJSON]] objects
* [[TravelTime|https://traveltime.com/]], a commercial API for [[geocoding|https://traveltime.com/features/geocoding]], [[routing|https://traveltime.com/features/multi-modal-routing]] and [[isochrones|https://traveltime.com/features/isochrones]]
* [[Flickr|https://www.flickr.com/services/api/]], a free API for retrieving geotagged photographs
* [[OpenLocationCode|https://github.com/google/open-location-code]], Google's open source library for converting to and from Open Location Codes (also known as [[PlusCodes|https://maps.google.com/pluscodes/]])
Try it out at https://tiddlywiki.com/prerelease/plugins/tiddlywiki/geospatial/
!! <<.wlink TestCaseWidget>> Widget
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7817">> new <<.wlink TestCaseWidget>> widget that is intended to solve a problem with the examples that we feature in the documentation. The existing macros are workable for simple, self-contained examples, but can be hard to follow in cases where the examples use additional tiddlers. The <<.wlink TestCaseWidget>> widget displays complete, self-contained interactive examples showing the output together with a tabbed display of the constituent tiddlers that produce it:
<<testcase "TestCases/TestCaseWidget/TwoPlusTwo">>
The payload tiddlers for a test case are specified with the <<.wlink DataWidget>> widget. Test cases are run as an independent, self-contained nested wiki in a similar way to the [[Innerwiki Plugin]], but are much more lightweight. The disadvantage is that test cases are rendered as part of the main page, and so any styling changes will leak out to the rest of the page.
Test cases can also specify the raw HTML of the expected result which causes them to be executed as tests, with success or failure indicated by an icon:
<<testcase "TestCases/TestCaseWidget/FailingTest">>
The easiest way to use the <<.wlink TestCaseWidget>> is by creating TestCaseTiddlers using the new CompoundTiddlers format. There are also many test cases to view in the TiddlyWiki test edition at https://tiddlywiki.com/prerelease/test.html
! Translation improvements
Improvements to the following translations:
*
* Chinese
* French
* Macedonian
* Polish
! Plugin Improvements
*
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/8198">> badges to the core plugins to indicate their [[stability level|Plugin Stability]] from "deprecated", "experimental", "stable" and "legacy". These badges are shown in the plugin library and in the control panel
! Widget Improvements
*
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/8115">> ''$timestamp'' attribute to ActionDeleteFieldWidget
! Filter Improvements
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7966">> new [[backtranscludes Operator]]
! Usability Improvements
*
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/issues/8121">> new keyboard shortcut for refreshing the page
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/commit/f3614c1e47e6ac5d5fec221b060699e975cd5ef6">> and simplified the splash screen for tiddlywiki.com. See [[Creating a splash screen]] for instructions on creating your own splash screen
! Hackability Improvements
*
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7882">> infinite recursion handling using a custom exception
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7966">> button to the JavaScript error popup allowing tiddlers to be saved to a local JSON file
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/issues/8120">> to latest version of modern-normalize 2.0.0
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/8211">> [[tm-permalink|WidgetMessage: tm-permalink]], [[tm-permaview|WidgetMessage: tm-permaview]] and [[tm-copy-to-clipboard|WidgetMessage: tm-copy-to-clipboard]] messages to allow the notification text to be customised
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/8225">> [[WidgetMessage: tm-http-request]] to allow the default headers to be suppressed
! Bug Fixes
*
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8186">> nested [[Block Quotes in WikiText]]
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7933">> TiddlyWikiClassic build process
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7935">> LinkWidget not refreshing when the `to` attribute changes
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/3460">> parsing bug with empty procedures/macros
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7907">> functions to use variables set by filter runs
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7943">> edit widget not refreshing when the editor type changes
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7922">> editor preview width
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/9bf3c0602d4fd3fe5ac7411db697b51f87a79056">> [[WidgetMessage: tm-http-request]] not returning data in the event of an error
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/8150">> [[WidgetMessage: tm-http-request]] incorrectly interpreting 2XX status codes
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7949">> processing of path separators in `tiddlywiki.files` files on Windows
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7975">> incorrect state reference in advanced search
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7985">> clipping of popups in preview pane
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/8039">> JavaScript error when attempting to export missing tiddlers to a CSV file
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7909">> imported procedures defaulting to `\whitespace trim`
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/801ed0ea1164aab4f88547322f9d73704388143f">> crash with [[cycle Operator]] if the the step size is larger than the number of operands
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/8095">> proper DOCTYPE for the open window template
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7945">> theme font size settings to open in new window CSS
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8098">> backlink parser to prevent it parsing binary tiddlers
! Node.js Improvements
*
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/8141">> usage of "Cache-Control" header
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7878">> SaveCommand not overwriting files when required
! Performance Improvements
@@ -47,7 +116,9 @@ Improvements to the following translations:
! Developer Improvements
*
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8195">> issue with fakedom TW_Node inheritence
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8099">> SJCL library creating variables in global scope
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/8179">> fix `widget.getVariableInfo()` to always return a `params` property
! Infrastructure Improvements
@@ -58,4 +129,32 @@ Improvements to the following translations:
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
<<.contributors """
andjar
AnthonyMuscio
bimlas
BramChen
btheado
BurningTreeC
catter-fly
Drevarr
eschlon
etardiff
flibbles
FSpark
hoelzro
jinix6
joshuafontany
linonetwo
mateuszwilczek
mklauber
oeyoews
pmario
PotOfCoffee2Go
rmunn
saqimtiaz
sarna
Telumire
twMat
xcazin
yaisog
""">>

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