1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-23 11:24:40 +00:00

Compare commits

..

197 Commits

Author SHA1 Message Date
jeremy@jermolene.com
5f213567dd Add a cascade for dynamically choosing tiddler icons 2021-11-10 14:27:14 +00:00
jeremy@jermolene.com
a1ab220df6 Avoid unwanted whitespace 2021-11-10 10:42:25 +00:00
jeremy@jermolene.com
88d8057b38 Add a cascade for the view template title 2021-11-08 20:55:35 +00:00
jeremy@jermolene.com
a4e0cf31b0 Add a cascade for the editor template body 2021-11-08 17:52:36 +00:00
jeremy@jermolene.com
4bb12379eb Standardise "Story Tiddler Template" nomenclature 2021-11-08 17:50:06 +00:00
jeremy@jermolene.com
4697718e7b Tweak control panel wording 2021-11-08 09:29:05 +00:00
jeremy@jermolene.com
a624ed24e2 Add demo of custom story tiddler template 2021-11-06 14:48:30 +00:00
jeremy@jermolene.com
2059464276 Fix typo in previous commit 2021-11-05 17:59:53 +00:00
jeremy@jermolene.com
2a3a6dd558 Refer to $:/core/ui/{View|Edit}Template via their associated config tiddlers 2021-11-05 17:56:52 +00:00
jeremy@jermolene.com
e0b7dcded1 Refactor import listing and plugin listing as alternate body templates
As suggested by @pmario
2021-11-05 16:42:57 +00:00
jeremy@jermolene.com
478d90acec Add control panel UI for inspecting the template cascades 2021-11-05 14:45:02 +00:00
jeremy@jermolene.com
3aacf0fe72 Simplify cascade filter
Thanks @saqimtiaz
2021-11-05 14:44:26 +00:00
jeremy@jermolene.com
72c77f42da Use the cascade mechanism to choose between the edit and view templates 2021-11-05 09:20:46 +00:00
jeremy@jermolene.com
52907b98f9 Merge branch 'master' into cascade-filter-run-prefix 2021-11-05 08:29:08 +00:00
jeremy@jermolene.com
9caba544eb Fix refreshing of codeblock widget
Fixes #6171
2021-11-05 08:28:56 +00:00
jeremy@jermolene.com
b1cb211f21 Use the cascade filter run prefix to choose the view template body template 2021-11-04 20:40:59 +00:00
jeremy@jermolene.com
2475e1b501 Merge branch 'tiddlywiki-com' 2021-11-04 20:34:01 +00:00
Marxsal
193628d63f Add note about exporting variables to 'Environmental Variables on Node.js' (#6169) 2021-11-04 17:53:09 +00:00
jeremy@jermolene.com
ee32eb909f Add explicit test for empty result when no filter passes 2021-11-04 17:36:02 +00:00
jeremy@jermolene.com
b47a3ab585 Precompile the filters for performance 2021-11-04 16:43:06 +00:00
jeremy@jermolene.com
9e41d410ee Set currentTiddler and ..currentTiddler for filter evaulation 2021-11-04 16:20:37 +00:00
jeremy@jermolene.com
fc3a764199 Initial Commit 2021-11-04 15:51:13 +00:00
Saq Imtiaz
b6ce353a7d Fix: resolved search-replace operator regexp encoding bug (#6162)
* fix: resolved search-replace operator bug with $ character in replacement strings, added test and more examples

* fix: reset regexp after each title
2021-11-01 13:24:30 +00:00
btheado
7a50603d9d Added MessageHandlerWidgets and TriggeringWidgets tags (#6161) 2021-11-01 12:56:52 +00:00
btheado
d21fabca4b Docs: Fix filters selection constructors tag (#6154)
Add constructor tag to these filter operators:
* deserializers
* range
* storyviews

Remove constructor tag from
* enlist-input
2021-10-31 10:36:45 +00:00
btheado
daa9a8ae45 Add subfilter operator examples and mention when it is a constructor (#6155) 2021-10-31 10:36:03 +00:00
btheado
d9eb5499a3 Ensure the operator examples have unique id (#6153)
The first parameter of the operator examples macro is used for
constructing unique state tiddler titles. The cycle, log, and
match operators had duplicates, causing examples to share state
with each other.
2021-10-30 15:54:57 +01:00
jeremy@jermolene.com
870c7897ad Fix docs typos 2021-10-30 15:28:54 +01:00
jeremy@jermolene.com
95da1c2907 Update release note 2021-10-30 11:44:58 +01:00
Cameron Fischer
2bfe522b72 Add $let widget (#6148)
* $let widget added and tested

* Documentation for $let, doc improvements for $vars

* let properly avoids refreshing when possible

* $let Changes as recommended by others

* Removed superfluous super method call

Also improved $let test
2021-10-30 11:42:22 +01:00
Saq Imtiaz
c099bf9893 Extends :map filter run prefix to provide missing variables (#6149)
* Extends :map filter run prefix to provide the variables index, revIndex and length to bring it into line with :reduce

* update :maps examples

* docs: fix formatting issue with documentation
2021-10-30 10:04:50 +01:00
jeremy@jermolene.com
ab0dda1177 Merge branch 'tiddlywiki-com' 2021-10-30 09:54:55 +01:00
Saq Imtiaz
4f65953da9 Added zero based zth[] operator and documentation (#6150) 2021-10-30 09:52:38 +01:00
jeremy@jermolene.com
d77de61a06 Update docs for per-tiddler preview pane 3287cf56bb 2021-10-29 10:04:08 +01:00
Simon Huber
3287cf56bb Make editor-preview open on a per-tiddler basis (#5998)
* make editor-preview open on a per-tiddler basis

* use qualified state for showeditpreview

* fix added p tag

* Make tiddler-preview per-tiddler configurable

* Create ShowEditPreviewPerTiddler.tid

* Update ControlPanel.multids

* Create ShowEditPreviewPerTiddler.tid

* Update body.tid

* Update ShowEditPreviewPerTiddler.tid

* Update ControlPanel.multids

* Delete ShowEditPreviewPerTiddler.tid

* Delete ShowEditPreviewPerTiddler.tid

* Create Hidden Setting ShowEditPreviewPerTiddler.tid
2021-10-28 19:17:15 +01:00
Saq Imtiaz
b5c81d2721 Provide actionValue variable to actions fired by EditTextWidget (#6145)
* feat: provide actionValue variable to actions fired by EditTextWidget

* also extend CodeMirror engine to set actionValue variable when invoking actions
2021-10-28 19:15:50 +01:00
Maurycy Zarzycki
d3522854b6 Polish translation fixes (#6144)
* fix word used for the sidebar's "Open" tab header

"Otwórz" is a verb (to open), while "Otwarte" is an adjective (the ones which are open)

* fix "shadow tiddler" declension

* fix declension

* fix missing space

* fix declension

* fix invalid plugin version message to read better

Co-authored-by: Maurycy Zarzycki <maurycy@evidentlycube.com>
2021-10-28 09:59:27 +01:00
jeremy@jermolene.com
2f3f9de7be Fix typo in d5f72cb282
Fixes #6143
2021-10-28 09:18:54 +01:00
Simon Huber
6890952357 Make image-picker in theme tweaks not dismiss popup ... (#6015)
when clicking the system-images checkbox
2021-10-27 14:13:49 +01:00
Simon Huber
d695fca301 Add focus-editor text operation and use it where sensible (#6012)
* add and use focus-editor text operation

* add docs
2021-10-27 11:37:40 +01:00
Simon Huber
a0d2392f01 Update link-widget refresh method (#6013)
* update link-widget refresh method

* update link-widget refresh method
2021-10-27 11:37:08 +01:00
Jeremy Ruston
23b4e03cd5 Extend HTML tag parser to maintain an ordered array of attribute names (#6132)
* Extend HTML tag parser to maintain an ordered array of attribute names

* Add some tests for repeated attributes

* Record entire attribute in orderedAttributes array so that we can work with duplicated attributes
2021-10-27 11:35:12 +01:00
Jeremy Ruston
d5f72cb282 Set multiple fields/variables/params using filters (#6130)
* Add action-setmultiplefields and setmultiplevariables, and extend action-sendmessage

* Add getfield operator

* Remove getfield operator

See discussion at https://github.com/Jermolene/TiddlyWiki5/pull/6130#issuecomment-949911439

* Add docs

* Adjust whitespace

* Add support for assigning multiple indexes to action-setmultiplefields
2021-10-27 11:20:11 +01:00
jeremy@jermolene.com
5f57bf81cd Merge branch 'pr/4977' 2021-10-27 11:18:57 +01:00
Joshua Fontany
e32c9e4658 Feature tiddlywiki.files "searchSubdirectories" flag (#5275)
* experimenting

* recurse flag for directories in tiddlywiki.files

* searchSubdirectories docs

* filesystem cleanup to seperate PR

* cleanup

* improved docs
2021-10-27 11:16:05 +01:00
Joshua Fontany
2a73505508 Fix overwriting of modification fields when PUTting a tiddler #6075 (#6084)
* call self.displayError

* Revert "call self.displayError"

This reverts commit 5d599aa979.

* fix PUT bug with created/modified fields
2021-10-27 11:15:30 +01:00
jeremy@jermolene.com
4d87ef4231 Add a comment on the default value of tv-action-refresh-policy 2021-10-26 09:51:00 +01:00
jeremy@jermolene.com
71be167592 Clarify ActionWidget Execution Modes to include default value 2021-10-26 09:50:02 +01:00
Telumire
c543036a0f Add missing parameter to atan2 operator (#6142)
* Added missing trigonometrics filter operators

This PR adds support to trigonometry operators, allowing to create spider graphs and other geometric shapes with filters.

* Adds the missing trigonometric filter operators

This PR adds support to the missing trigonometric filter operators (cos, sin, tan, acos, asin, atan, atan2), allowing to create spider graphs, [pie charts, donut charts, polar charts](https://ffoodd.github.io/chaarts/pie-charts.html) and other geometric shapes with filters, which was previously not possible without add-ons.

Example :

`[[2]cos[]] = -0.4161468365471424`

See also this radar chart made in wikitext by @saqimtiaz using the new trigonometric operators :
https://saqimtiaz.github.io/sq-tw/temp/radar-chart-demo.html

* Add documentation for the Trigonometric Operators 

Accompanies code changes #6127

* Fix formatting of atan2 Operator.tid

Removed two empty lines at the end of the tiddler

* Add examples for the trigonometric operators 

Accompanies code changes Jermolene#6127

* Fix version in the doc for trigonometric operators

This PR fix the content of the documentation tiddlers regarding trigonometric operators (#6131). 

<<.from-version "5.1.20">> was changed to <<.from-version "5.1.21">>

* Fix formatting of atan2 Operator.tid

Removed two empty lines at the end of the tiddler

* Add missing parameter to atan2 operator

The atan2 operator needs two parameters (Binary Mathematics Operators), this PR adds the second one that was missing.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2 for more technical info on the atan2 function.
2021-10-25 21:13:18 +01:00
btheado
989947b99a Make filter operater examples live-editable (#6139)
* Make filter operator examples easily editable

* Add 'Reset' button to filter operator examples

* Only display the reset button when filter has changed

* Introduce '.doc-example input' class rather than re-use tc-advanced-search to make input wider

* Grab focus for the filter text box

* Fix firefox ctrl-z/undo issue by replacing list widget with filter transclusion

* Replace spaced indent with tabs to make it consistent with the other code
2021-10-25 16:35:57 +01:00
jeremy@jermolene.com
3d86d62a6e Minor tweaks to 0cfe6597d4 2021-10-25 16:29:53 +01:00
Mario Pietsch
0cfe6597d4 Add new improved "Icon Gallery" (#6112)
* add a core icon selector to the docs

* Add Icon Gallery and improve links to expose the function

* re-add the ImageGallery Example tiddler
2021-10-25 16:23:57 +01:00
jeremy@jermolene.com
8ae4428332 Fix $timestamp ignored for action-setfield widget when setting index values 2021-10-24 20:19:42 +01:00
Marxsal
81b4e99ccc Update LazyLoading.tid (#6099) 2021-10-22 14:35:25 +01:00
Telumire
2f133a08aa Add documentation and examples for the trigonometric filter operators (#6131)
* Added missing trigonometrics filter operators

This PR adds support to trigonometry operators, allowing to create spider graphs and other geometric shapes with filters.

* Adds the missing trigonometric filter operators

This PR adds support to the missing trigonometric filter operators (cos, sin, tan, acos, asin, atan, atan2), allowing to create spider graphs, [pie charts, donut charts, polar charts](https://ffoodd.github.io/chaarts/pie-charts.html) and other geometric shapes with filters, which was previously not possible without add-ons.

Example :

`[[2]cos[]] = -0.4161468365471424`

See also this radar chart made in wikitext by @saqimtiaz using the new trigonometric operators :
https://saqimtiaz.github.io/sq-tw/temp/radar-chart-demo.html

* Add documentation for the Trigonometric Operators 

Accompanies code changes #6127

* Fix formatting of atan2 Operator.tid

Removed two empty lines at the end of the tiddler

* Add examples for the trigonometric operators 

Accompanies code changes Jermolene#6127

* Fix version in the doc for trigonometric operators

This PR fix the content of the documentation tiddlers regarding trigonometric operators (#6131). 

<<.from-version "5.1.20">> was changed to <<.from-version "5.1.21">>

* Fix formatting of atan2 Operator.tid

Removed two empty lines at the end of the tiddler
2021-10-22 11:35:47 +01:00
jeremy@jermolene.com
6b17e688da Merge branch 'tiddlywiki-com' 2021-10-21 09:21:29 +01:00
jeremy@jermolene.com
8654066f03 Remove docs about editing a field of the containing tiddler
Doesn't apply post v5.2.0
2021-10-21 09:21:00 +01:00
Joshua Fontany
56dae90425 Fix $tw.utils.decodeURISafe and $tw.utils.decodeURIComponentSafe not available during boot process (#6107)
* call self.displayError

* Revert "call self.displayError"

This reverts commit 5d599aa979.

* fix 5999 URI utils bug
2021-10-20 16:25:05 +01:00
Telumire
1f6ef07860 Add trigonometric filter operators (#6127)
* Added missing trigonometrics filter operators

This PR adds support to trigonometry operators, allowing to create spider graphs and other geometric shapes with filters.

* Adds the missing trigonometric filter operators

This PR adds support to the missing trigonometric filter operators (cos, sin, tan, acos, asin, atan, atan2), allowing to create spider graphs, [pie charts, donut charts, polar charts](https://ffoodd.github.io/chaarts/pie-charts.html) and other geometric shapes with filters, which was previously not possible without add-ons.

Example :

`[[2]cos[]] = -0.4161468365471424`

See also this radar chart made in wikitext by @saqimtiaz using the new trigonometric operators :
https://saqimtiaz.github.io/sq-tw/temp/radar-chart-demo.html
2021-10-19 15:56:08 +01:00
Telumire
f30a455ee3 Signing the CLA (#6128)
see https://github.com/Jermolene/TiddlyWiki5/pull/6127
2021-10-18 09:06:49 +01:00
btheado
03bd99cd11 Docs: fix invalid html comment in operator template #6100 2021-10-11 12:01:34 +01:00
btheado
cc389ec82b Improve $action-listops attribute docs (#6104)
* Added comparisons of $filter, $subfilter, and $tags attributes

* Added comparison between action-listops and action-setfield widgets
2021-10-11 11:59:47 +01:00
btheado
f85678b6dc Signing the CLA (#6103) 2021-10-11 11:52:29 +01:00
Marxsal
8d7c869072 Changes to TiddlyServer by Matt Lauber (#6094)
This version of the project is not maintained. I've noted this and added a link to Arlen Beiler's community reference. I suppose it could be deleted entirely, but might be useful for historical purposes?
2021-10-08 19:09:17 +01:00
Marxsal
8f592d3f0a Documentation - Installing Nodejs fixes (#6085) 2021-10-04 09:48:44 +01:00
jeremy@jermolene.com
1f2e0ed189 Placeholder banner image for v5.2.1 2021-10-03 16:17:15 +01:00
jeremy@jermolene.com
4d6c428ba9 Preparation for v5.2.1-prerelease 2021-10-03 15:46:25 +01:00
jeremy@jermolene.com
d095aa0182 Version number update for 5.2.0 2021-10-03 15:29:21 +01:00
jeremy@jermolene.com
15bf850280 Update plugin library for prerelease 2021-10-03 15:28:40 +01:00
jeremy@jermolene.com
62b273266e Update readme.md and contributing.md for v5.2.0 2021-10-03 15:26:45 +01:00
jeremy@jermolene.com
1d058177be Move v5.2.0 release note and prepare v5.2.1 release note 2021-10-03 15:25:36 +01:00
jeremy@jermolene.com
14676b345a Update modified dates for release note and hellothere 2021-10-03 15:21:02 +01:00
jeremy@jermolene.com
a50e6eed38 Merge branch 'tiddlywiki-com' 2021-10-03 15:12:55 +01:00
Saq Imtiaz
073a064ae8 Fixed typo in relese notes (#6083) 2021-10-03 15:11:03 +01:00
jeremy@jermolene.com
e00a3d3cb4 Update release note with an "Other Notable Improvements" section 2021-10-03 13:06:08 +01:00
jeremy@jermolene.com
68d9200a6b Breakup the action widgets execution modes documentation 2021-10-03 13:05:48 +01:00
jeremy@jermolene.com
2551bb3e3f Update release note 2021-10-03 11:40:35 +01:00
jeremy@jermolene.com
80b18e6315 Update JSON store area docs 2021-10-03 11:40:27 +01:00
Maurycy Zarzycki
e0561397f1 Added Polish translation (#6079)
* add Polish translation

* tweak Polish translations to make certain things moree readable

primarily changed translation of "story river" to keep using the English
phrase, but also some other phraes that were awkward when I used the
translation

* add polish flag icon

* add polish translation notes

* replace 'ukryte tiddlery' with 'tiddlery-cienie'

Co-authored-by: Maurycy Zarzycki <maurycy@evidentlycube.com>
2021-10-03 09:19:48 +01:00
jeremy@jermolene.com
b9c3c38edc List widget: Clarify performance optimisation impact of counter attribute 2021-10-02 18:27:50 +01:00
lin onetwo
077ced0d1a Fix: add text to QR Code button caption (#6082) 2021-10-02 18:09:11 +01:00
jeremy@jermolene.com
e5ff84035c Minor fixes to introduction edition 2021-10-02 17:31:02 +01:00
jeremy@jermolene.com
e18a983209 Update dynaview demo viewtemplate with latest core changes 2021-10-02 17:22:24 +01:00
jeremy@jermolene.com
6f61fa07fb Update view template to use whitespace trim 2021-10-02 17:22:10 +01:00
jeremy@jermolene.com
d5d73e02e9 Fix bug with innerwiki template
The problem was that the innerwiki template included the tiddler $:/plugins/tiddlywiki/railroad, which was omitted from the wiki. Unexpectedly, missing tiddlers were rendered by the jsontiddler widget as an empty object {}. The fix is to always include the title when the tiddler is missing.

Also cleaned up the template to remove unneeded tiddlers
2021-10-02 16:17:07 +01:00
Maurycy Zarzycki
4ba7454d8d Signing the CLA (#6078) 2021-10-01 13:26:00 +01:00
Mario Pietsch
5192a39830 Update German translations (#6077) 2021-09-30 15:46:33 +01:00
jeremy@jermolene.com
aa5413b942 Fix incomplete sentence in MessageCatcherWidget docs 2021-09-30 10:34:27 +01:00
Xavier Cazin
ef284e9bde Update the Android section in Saving via WebDAV (#6069) 2021-09-28 10:22:35 +01:00
Cameron Fischer
9c41fe1d18 JSONTiddler a little more extensible (#6057)
As per discussion #6043
2021-09-27 14:23:52 +01:00
jeremy@jermolene.com
e577cf7302 Render command: verbose mode should print title before rendering
Fixes #6067
2021-09-24 18:40:34 +01:00
jeremy@jermolene.com
ebf563ac70 Additional transliteration pairs
Fixes #6066
2021-09-24 18:29:40 +01:00
jeremy@jermolene.com
909340c6fe Release note tweaks 2021-09-24 12:15:19 +01:00
jeremy@jermolene.com
df6d38df65 Update release note 2021-09-24 12:00:07 +01:00
jeremy@jermolene.com
59a53e695b Further refine date format tokens for day of year and weekday number
See f223896c26
2021-09-23 10:09:27 +01:00
jeremy@jermolene.com
6d17505f7b Fix typo in DateFormat docs 2021-09-23 07:41:06 +01:00
Jeremy Ruston
36dd8ea1d2 Optimise wiki.sortTiddlers() (#6053)
* Optimise wiki.sortTiddlers()

* Remove local changes to test-filters.js that have now been made on master

Makes the subsequent merge easier

* Fix bug with numeric sorts of textual values
2021-09-22 13:44:35 +01:00
Saq Imtiaz
b965ae926b Fix(action-confirm): check if event is defined before accessing its properties (#6063) 2021-09-22 13:43:02 +01:00
jeremy@jermolene.com
f6eadbd1c9 Fix crash with reading invalid JSON files 2021-09-22 12:56:55 +01:00
jeremy@jermolene.com
bdbb884be0 MessageCatcher: Fix stack overflow when re-issuing a trapped message
This makes it possible to trap a message and then re-issue the same message within the action string without an infinite loop.
2021-09-20 16:46:26 +01:00
jeremy@jermolene.com
0be39cfbc2 More sorting tests to help with #6053 2021-09-20 11:04:37 +01:00
Saq Imtiaz
ef2aeac7de Added modulesproperty filter operator and extended modules operator (#6055)
* Added modulesproperty filter operator and extended modules operator. Docs included

* Removed spurious new line
2021-09-20 08:25:53 +01:00
Cameron Fischer
157afda2fc Change backlinks to use LinkedList (#6050) 2021-09-19 19:58:45 +01:00
jeremy@jermolene.com
fb4d77ef46 Improved fix for #5701
Reverts dbd3f835bf

Fixes #6042
2021-09-19 13:28:58 +01:00
Cameron Fischer
575c233597 Update untagged filter to avoid $tw.utils.pushTop (#6034) 2021-09-18 16:47:46 +01:00
Saq Imtiaz
2e59d770f7 Fix eventcatcher widget: check for event properties before accessing (#6048) 2021-09-18 15:08:15 +01:00
Soren Bjornstad
baf0ee9cde Remove stray characters in example of :map prefix (#5963)
The `get[` here isn't valid and looks like a copy-paste error.
2021-09-18 15:04:50 +01:00
Soren Bjornstad
af89bb591d Sign CLA (#6049) 2021-09-18 15:03:42 +01:00
Mario Pietsch
d0dec741ad katex-plugin: fix #6041 add automatic numbering reset to KaTex style-sheet (#6046)
* katex-plugin: fix #6041 add automatic numbering reset to KaTex style-sheet

* fix typo
2021-09-18 09:45:17 +01:00
jeremy@jermolene.com
33a82e395e Revert tiddlylink font weight to match v5.1.23
Otherwise links to missing tiddlers are too skinny
2021-09-17 15:11:29 +01:00
jeremy@jermolene.com
f223896c26 Refine date format tokens for weekday number, and add support for day of year
See discussion at https://groups.google.com/g/tiddlywiki/c/tf23ByDXzxM/m/5Wx7PV36AwAJ
2021-09-17 14:52:08 +01:00
Saq Imtiaz
de33b365ae Fixed refresh bug with radio widget where the tc-radio-selected class is not correctly updated (#6044) 2021-09-17 12:52:27 +01:00
Cameron Fischer
e9d8547a81 Optimise LinkedList filter ops to return iterator instead of array (#6035)
* filter ops don't LinkedList to array anymore

* LL.tiddlerIterator -> LL.makeTiddlerIterator

LinkedList method name change.
2021-09-16 22:22:44 +01:00
Cameron Fischer
dcff318a98 Fix wiki.eachShadow returns overridden sources (#6036)
It was returning the underlying shadows before, even if overridden, which
was causing some bugs.

Fixes #6033
2021-09-16 20:08:11 +01:00
jeremy@jermolene.com
f725123690 Simplify freelinks regexp
As discussed here: https://github.com/Jermolene/TiddlyWiki5/issues/6029#issuecomment-917612980
2021-09-14 10:22:27 +01:00
jeremy@jermolene.com
e9e5d37ff0 Draggable widget: Add option to hide drag image
Thanks @ericshulman

Fixes #6027
2021-09-12 14:20:03 +01:00
jeremy@jermolene.com
f70cee6907 Add new date format tokens for weekday number
See https://en.wikipedia.org/wiki/ISO_8601#Week_dates
2021-09-12 11:53:46 +01:00
jeremy@jermolene.com
1491339f50 Update KaTeX version number 2021-09-12 10:56:39 +01:00
jeremy@jermolene.com
8a5ed59ff4 Release note update for KaTeX 2021-09-12 10:55:33 +01:00
jeremy@jermolene.com
a2ca5e4d1e Update KaTeX to v0.13.18 2021-09-12 10:54:54 +01:00
jeremy@jermolene.com
fba993502d Revert some of the UI changes for downloading external-js
See https://github.com/Jermolene/TiddlyWiki5/pull/5570#issuecomment-892127428
2021-09-12 10:48:17 +01:00
jeremy@jermolene.com
9fae3a932b Release note: Emphasise more flexible parsing of macros 2021-09-12 09:07:15 +01:00
Jieao Song
62610f0666 Add custom macro editor for KaTeX plugin (#5933)
* Add custom macro editor for KaTeX plugin

* Use list

* Better escape

* Tweaks

* Remove const

* Catch bad macros

* Capitalize tags

* Name KaTeX-macro tiddlers properly

* UI tweaks

* Move input string to temp

* Improve UI; import macros using LaTeX cmd directly
2021-09-10 21:28:13 +01:00
Cameron Fischer
7282ec5286 Fix getCacheForTiddler to cache falsy values (#5413)
* getCacheForTiddler can cache falsy values

* Switch to "!== undefined" for getCacheForTiddler
2021-09-10 21:17:35 +01:00
Simon Huber
9830e0104f Fix the EditTabIndex value applied to DomNodes which was '1\n' (#6022) 2021-09-08 14:50:11 +01:00
jeremy@jermolene.com
e6fd0caf6b Update range operator to use multiple operands
We still also support the old way of packing all three parameters into one operand with a delimiter
2021-09-07 17:16:09 +01:00
jeremy@jermolene.com
137df37bc7 Merge branch 'tiddlywiki-com' 2021-09-07 11:02:03 +01:00
Bram Chen
d895706199 Revise chinese translations in Imports.multids (#6024) 2021-09-06 08:16:14 +01:00
Xavier Cazin
6ed7d418b5 A few updates to the fr-FR translation + a typo correction in core Imports.multids (#6023) 2021-09-05 19:51:48 +01:00
jeremy@jermolene.com
62b8a83741 Avoid MSIE crash
Fixes #6014
2021-09-01 09:56:17 +01:00
Marxsal
e795b501ac Update Saving via WebDAV (#6011) 2021-08-31 09:19:10 +01:00
Marxsal
03228d8d20 Allow compare operator to appear on filter list (#6008) 2021-08-30 08:58:26 +01:00
jeremy@jermolene.com
c9c5d4cf79 Remove new docs from #5648
See https://github.com/Jermolene/TiddlyWiki5/pull/5648#issuecomment-907845331
2021-08-29 19:36:23 +01:00
Simon Huber
f5cc5bc6a1 Make stamp-dropdown items that are suffixed and prefixed ... (#6003)
... work for shadow tiddlers, too
2021-08-29 18:04:32 +01:00
Mario Pietsch
447494ad4d Fix some typos in the ViewTolbar button docs (#5974)
* fix some typos in the ViewTolbar button docs

* add missing fields to shadow. closes #5980
2021-08-29 17:50:28 +01:00
Simon Huber
c9f178ec87 Make Stamp-Dropdown sortable by Drag&Drop (#5981)
* Make stamp-dropdown reorderable by list-tagged-draggable macro

* Add stamp-dropdown ItemTemplate tiddler

* Make stamp-entries editable by ctrl-click

* Update stamp-dropdown-item-template.tid

* Add `tc-editortoolbar-stamp-button` class to stamp button

* Make stamp-dropdown look like before

* Update base.tid
2021-08-29 17:48:32 +01:00
jeremy@jermolene.com
33be326ef6 Add from-version banner to search-replace operator "m" flag 2021-08-29 17:45:59 +01:00
Simon Huber
c13f04d838 Add m flag for multiline matches to search-replace filter operator (#5968)
* add m flag to search-replace operator and add tests

* update documentation

* Update test-filters.js

* Update test-filters.js

* Update search-replace Operator (Examples).tid

* Fix "Hello There" title (HelloThere)
2021-08-29 17:44:34 +01:00
Mohammad Rahmani
737685149c Plugins tab in control panel display tabs using tag filter instead of hardcoded list (#5694)
* Plugins tab in control panel display tabs using filter instead of hard coded list

* Update ControlPanelPlugins.tid

The two entries `[[$:/core/ui/ControlPanel/Plugins/Installed]] [[$:/core/ui/ControlPanel/Plugins/Add]]` were removed from list filed as per @Jermelon confirmation!

* Create SystemTag_ $__tags_ControlPanel_Plugins.tid

Update the SystemTags documentation tiddler
2021-08-29 17:35:18 +01:00
Joshua Fontany
33eef0202d Adds $tw.utils.decodeURISafe and $tw.utils.decodeURIComponentSafe (#5999)
* call self.displayError

* Revert "call self.displayError"

This reverts commit 5d599aa979.

* fixes decodeURI & decodeURIComponent
2021-08-29 13:39:32 +01:00
jeremy@jermolene.com
a67b1b8bb5 Fileserver: Check for valid file paths 2021-08-28 13:16:54 +01:00
jeremy@jermolene.com
124b49456a MessageCatcher: Expose lists of the message property names 2021-08-21 12:50:38 +01:00
Saq Imtiaz
24956087cc Do not add X-Requested-With header for simple requests (#5931) 2021-08-17 09:56:52 +01:00
jeremy@jermolene.com
199ca57f1c Release note tweaks 2021-08-15 18:13:02 +01:00
jeremy@jermolene.com
64d53ac533 Release note: Optimised Refreshing of Transclusions
A first attempt to write up the consequences, including the impact on broken JS macros. The problem is that there's not really a simple fix that we can give.

The best I can think of is not good enough: a $:/config/ tiddler that globally controls whether the transclude widget uses the new selective refreshing.
2021-08-15 13:17:59 +01:00
Cameron Fischer
b3accbf9e0 Fakedom: use text encoder for html text (#5950) 2021-08-12 16:46:11 +01:00
Joshua Fontany
99249a3160 Fix syncer logout alert (#5936)
* call self.displayError

* Revert "call self.displayError"

This reverts commit 5d599aa979.

* fix Syncer logout alert
2021-08-05 14:50:22 +01:00
Jieao Song
f7cd8bad3a Signing the CLA (#5938) 2021-08-05 14:42:28 +01:00
jeremy@jermolene.com
e9613d7f12 eventcatcher widget: Add viewport-relative coordinates
This is useful because we get viewport relative coordinates from the link and action-navigate widgets
2021-08-05 08:35:44 +01:00
jeremy@jermolene.com
97dff042f7 Reveal widget: fix crash when popup tiddler is refreshed but the popup is not displayed 2021-08-04 17:00:42 +01:00
jeremy@jermolene.com
32b36fb2af Update New Release Banner with winning artwork from Frank B 2021-08-04 11:58:04 +01:00
jeremy@jermolene.com
41535150dd Fix docs typos in "Customising Tiddler File Naming" 2021-08-03 20:47:44 +01:00
jeremy@jermolene.com
8e69284e8c Updated Catalan translation from Paco Riviere 2021-08-01 15:19:14 +01:00
jeremy@jermolene.com
61cfac4eeb Fix typo in release note
Thanks @twMat
2021-07-30 16:33:00 +01:00
jeremy@jermolene.com
2720072b23 Text editor: fix crash when assigning new value to file input controls
Fixes #5911
2021-07-30 16:31:42 +01:00
Joshua Fontany
0413c3a38e Fix syncer error handling for getStatus (#5914) 2021-07-30 16:21:02 +01:00
Mario Pietsch
f2b30c1fe0 tabs-macro: improve info about the "default" parameter (#5904) 2021-07-30 16:19:23 +01:00
Simon Huber
3c86cf7d2e Add pop storyview to ViewToolbar buttons (#5910)
* Add pop storyview to ViewToolbar buttons

* Update title.tid
2021-07-30 16:11:27 +01:00
jeremy@jermolene.com
451074f7ed Fix typo in release note
Thanks @twMat
2021-07-29 12:41:26 +01:00
Saq Imtiaz
1e5601ca31 Fix inaccuracies in documentation for duplicateslugs[] (#5918) 2021-07-29 11:39:20 +01:00
jeremy@jermolene.com
75c99cd235 Merge branch 'tiddlywiki-com' 2021-07-27 19:33:36 +01:00
jeremy@jermolene.com
bb2c2be9b6 Remove file erroneously committed in c4a7ae3164 2021-07-27 19:33:20 +01:00
jeremy@jermolene.com
53c247b9a1 Merge branch 'tiddlywiki-com' 2021-07-27 19:30:44 +01:00
Mario Pietsch
82667d9d16 Add indentation to $:/core/ui/Components/plugin-info (#5777)
* Add indentation to plugin-info, to make the macros readable.

* add missing indent
2021-07-26 21:59:02 +01:00
Bram Chen
97ed2757f0 Revise chinese translations (#5915) 2021-07-26 14:31:43 +01:00
jeremy@jermolene.com
19fd5ca5f2 Remove erroneous \s from field name check
Fixes #5905
2021-07-22 16:55:17 +01:00
jeremy@jermolene.com
6ae78a770f Fix erroneous bolding of links
An accident from f97850dd05
2021-07-19 14:03:12 +01:00
jeremy@jermolene.com
04962b4cd6 Update release note 2021-07-19 12:56:18 +01:00
jeremy@jermolene.com
f97850dd05 Update "Snow White" font-family and font-weight
Fixes #5896
2021-07-19 12:54:57 +01:00
jeremy@jermolene.com
2cb3ed3ab9 Change tab switching shortcuts to alt-ctrl-left/right
Fixes #5889
2021-07-16 13:06:49 +01:00
jeremy@jermolene.com
a4421f50c6 Git{hub|ea|lab} saver should wikify commit messages
Proposed in discussion https://github.com/Jermolene/TiddlyWiki5/discussions/5886#discussioncomment-1012593
2021-07-16 12:04:05 +01:00
Saq Imtiaz
cb726f40fa Fix: bug with List Widget where the counter-last variable is not always accurately updated on refresh (#5883) 2021-07-15 21:59:07 +01:00
Arlen22
be026aa308 Revert "Add server sent events (#5279)" (#5880)
This reverts commit 17b4f53ba2 according to Github Desktop.

git checkout that commit
revert commit in GitHub Desktop
git switch -c revert-sse
uncommit in Github Desktop
switch to master, bringing changes
resolve deletions with command line
2021-07-14 17:16:57 +01:00
RJ Skerry-Ryan
b95f6ca084 Signing the CLA (#5847) 2021-07-04 11:57:38 +01:00
twMat
4a7f078abd Update qualify.tid (#5845)
superfluous blockquoting
2021-07-03 17:43:20 +01:00
Tejasvi S. Tomar
54d8b8a373 Correct term usage (#5417) 2021-06-29 12:24:09 +01:00
GHSRobert Ciang
dd6bd58140 Update TiddlyWiki in the Sky for Dropbox.tid (#5832) 2021-06-29 12:09:16 +01:00
Álvaro González Rincón
4c56bd771a Signing the CLA (#5794) 2021-06-14 17:42:26 +01:00
Frank
a70b26cd55 Sign the CLA (#5774) 2021-06-09 21:32:31 +01:00
jeremy@jermolene.com
c4a7ae3164 Add demo of drag and drop from a standalone HTML file 2021-06-03 14:14:11 +01:00
Joe Bordes
8b8f654c9c Signing the CLA (#5730) 2021-05-30 18:47:34 +01:00
Miha Lunar
9b247f6d63 Removed fallback range logic 2021-05-29 20:30:04 +02:00
Mario Pietsch
f342fdc41d improve setwidget examples and add a link to and from enlist operator (#5666) 2021-05-25 22:19:28 +01:00
Mario Pietsch
ca96f7f62b contain the long list inside a div which is 50% of vertical height (#5385) 2021-05-25 22:19:09 +01:00
Saq Imtiaz
2f31eab8f4 Update docs for tabs macro (#5722) 2021-05-25 22:16:02 +01:00
Saq Imtiaz
c8528fd1f7 Update keyboard-driven-input_Macro.tid (#5712) 2021-05-21 10:02:35 +01:00
Chris Nicoll
07ac85d9fa Add demo for keyboard-driven-input (#5710) 2021-05-21 09:54:11 +01:00
jeremy@jermolene.com
e84f214280 Add link to @sobjornstad's "Grok TiddlyWiki" 2021-05-19 11:08:48 +01:00
ualich
9cd65efad9 Signing the CLA (#5671) 2021-05-06 12:24:08 +01:00
Chris Nicoll
41200ab6d7 Fix #5310: docs for unique[] filter operator (#5651)
Co-authored-by: clutterstack <clutterstack@gmail.com>
2021-04-29 13:14:28 +01:00
Miha Lunar
62fdaa633a Fixed fallback range logic + added ranges to tests 2021-04-25 16:03:35 +02:00
Miha Lunar
79f5e6b498 Merge remote-tracking branch 'origin/master' into parser-ranges 2021-04-25 13:17:44 +02:00
Miha Lunar
23bd7e7817 Replaced restructuring and added fallback comment 2021-04-25 13:12:45 +02:00
Simon Baird
792171c8fc Two typo fixups related to surplus tilde chars (#5627) 2021-04-24 15:42:02 +01:00
Simon Baird
051a468c63 Add info on TiddlyHost saving & revised TiddlySpot (#5622)
I updated the English text only. Will need some help with the
translations.

Summary:
- Mention that TiddlySpot is deprecated and doesn't allow site
  creation any more. Suggest using TiddlyHost instead.
- Remove obsolete intructions about creating TiddlySpot sites.
- Misc editing/rewording/tweaking of existing TiddlySpot info
  for tidiness and clarity.
- Add new information about saving on TiddlyHost.
- Add logos because why not..

Note: I usually prefer the non-camel case versions of Tiddlyspot and
Tiddlyhost, but decided to go with the CamelCase WikiWords here to
fit in with the existing conventions.
2021-04-23 17:45:44 +01:00
Miha Lunar
1b226c7556 Fixed coding standard nits 2020-11-06 19:56:20 +01:00
Miha Lunar
2bd9cc45fa Added more start/end parser ranges 2020-11-04 21:02:17 +01:00
462 changed files with 8573 additions and 5254 deletions

View File

@@ -256,6 +256,28 @@ $tw.utils.deepDefaults = function(object /*, sourceObjectList */) {
return object;
};
/*
Convert a URIComponent encoded string to a string safely
*/
$tw.utils.decodeURIComponentSafe = function(s) {
var v = s;
try {
v = decodeURIComponent(s);
} catch(e) {}
return v;
};
/*
Convert a URI encoded string to a string safely
*/
$tw.utils.decodeURISafe = function(s) {
var v = s;
try {
v = decodeURI(s);
} catch(e) {}
return v;
};
/*
Convert "&amp;" to &, "&nbsp;" to nbsp, "&lt;" to <, "&gt;" to > and "&quot;" to "
*/
@@ -757,12 +779,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
tiddler = $tw.wiki.getTiddler(name),
_exports = {},
sandbox = {
module: {
exports: _exports,
setStringHandler: function(handler) {
moduleInfo.stringHandler = handler;
}
},
module: {exports: _exports},
//moduleInfo: moduleInfo,
exports: _exports,
console: console,
@@ -826,7 +843,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
moduleInfo.definition(moduleInfo,moduleInfo.exports,sandbox.require);
} else if(typeof moduleInfo.definition === "string") { // String
moduleInfo.exports = _exports;
$tw.utils.evalSandboxed(moduleInfo.definition,sandbox,name);
$tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title);
if(sandbox.module.exports) {
moduleInfo.exports = sandbox.module.exports; //more codemirror workaround
}
@@ -923,20 +940,6 @@ $tw.modules.createClassesFromModules = function(moduleType,subType,baseClass) {
return classes;
};
/*
Return a specified module string for a module, null if the module or string is missing
*/
$tw.modules.getModuleString = function(moduleName,stringName,language) {
if(moduleName in $tw.modules.titles) {
$tw.modules.execute(moduleName);
var stringHandler = $tw.modules.titles[moduleName].stringHandler;
if(stringHandler) {
return stringHandler(stringName,language);
}
}
return null;
};
/////////////////////////// Barebones tiddler object
/*
@@ -1231,8 +1234,12 @@ $tw.Wiki = function(options) {
index,titlesLength,title;
for(index = 0, titlesLength = titles.length; index < titlesLength; index++) {
title = titles[index];
var shadowInfo = shadowTiddlers[title];
callback(shadowInfo.tiddler,title);
if(tiddlers[title]) {
callback(tiddlers[title],title);
} else {
var shadowInfo = shadowTiddlers[title];
callback(shadowInfo.tiddler,title);
}
}
};
@@ -1621,8 +1628,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
}
for(var f in data) {
if($tw.utils.hop(data,f)) {
// Check field name doesn't contain whitespace or control characters
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
// Check field name doesn't contain control characters
if(typeof(data[f]) !== "string" || /[\x00-\x1F]/.test(f)) {
return false;
}
}
@@ -1637,7 +1644,12 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
}
return true;
},
data = JSON.parse(text);
data = {};
try {
data = JSON.parse(text);
} catch(e) {
// Ignore JSON parse errors
}
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
return data;
} else if(isTiddlerValid(data)) {
@@ -1904,13 +1916,13 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
value = path.basename(filename);
break;
case "filename-uri-decoded":
value = decodeURIComponent(path.basename(filename));
value = $tw.utils.decodeURIComponentSafe(path.basename(filename));
break;
case "basename":
value = path.basename(filename,path.extname(filename));
break;
case "basename-uri-decoded":
value = decodeURIComponent(path.basename(filename,path.extname(filename)));
value = $tw.utils.decodeURIComponentSafe(path.basename(filename,path.extname(filename)));
break;
case "extname":
value = path.extname(filename);
@@ -1938,6 +1950,20 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
tiddlers.push({tiddlers: fileTiddlers});
}
};
// Helper to recursively search subdirectories
var getAllFiles = function(dirPath, recurse, arrayOfFiles) {
recurse = recurse || false;
arrayOfFiles = arrayOfFiles || [];
var files = fs.readdirSync(dirPath);
files.forEach(function(file) {
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));
}
});
return arrayOfFiles;
}
// Process the listed tiddlers
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
if(tidInfo.prefix && tidInfo.suffix) {
@@ -1961,13 +1987,14 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
// Process directory specifier
var dirPath = path.resolve(filepath,dirSpec.path);
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
var files = fs.readdirSync(dirPath),
var files = getAllFiles(dirPath, dirSpec.searchSubdirectories),
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
metaRegExp = /^.*\.meta$/;
for(var t=0; t<files.length; t++) {
var filename = files[t];
var thisPath = path.relative(filepath, files[t]),
filename = path.basename(thisPath);
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile);
}
}
} else {

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +0,0 @@
title: $:/core/images/publish
tags: $:/tags/Image
<svg width="22pt" height="22pt" class="tc-image-publish tc-image-button" viewBox="0 0 128 128"><g fill-rule="evenodd">
<path d="M64.0434107,46.2358498 C65.8048912,45.8955184 67.6195684,46.7809274 68.4102078,48.4458716 L68.4937877,48.6340507 L98.8972485,122.034498 C99.7426494,124.075476 98.7734424,126.415349 96.7324641,127.26075 C94.7552664,128.079732 92.4975633,127.195747 91.5897922,125.284145 L91.5062123,125.095966 L88.403,117.605598 L79.5048497,126.50485 C78.775871,127.233828 77.8355254,127.622617 76.8810886,127.671216 L76.6764226,127.676423 C75.6527333,127.676423 74.6290441,127.285898 73.8479955,126.50485 L63.999,116.656598 L54.1520045,126.50485 C53.4230259,127.233828 52.4826802,127.622617 51.5282434,127.671216 L51.3235774,127.676423 C50.2998881,127.676423 49.2761989,127.285898 48.4951503,126.50485 L39.596,117.605598 L36.4937877,125.095966 C35.6483868,127.136944 33.3085142,128.106151 31.2675359,127.26075 C29.2265576,126.415349 28.2573506,124.075476 29.1027515,122.034498 L59.5062123,48.6340507 C60.2518688,46.8338766 62.1601511,45.867488 64.0005148,46.2445933 L64.0434107,46.2358498 Z M77.679,102.976598 L69.656,110.999598 L76.676,118.018598 L84.699,109.996598 L77.679,102.976598 Z M50.326,102.983598 L43.307,110.002598 L51.323,118.018598 L58.342,110.999598 L50.326,102.983598 Z M64.006,89.3035977 L55.983,97.3265977 L63.999,105.342598 L72.022,97.3195977 L64.006,89.3035977 Z M55.035,80.3325977 L50.348,91.6475977 L58.349,83.6465977 L55.035,80.3325977 Z M72.968,80.3415977 L69.663,83.6465977 L77.642,91.6255977 L72.968,80.3415977 Z M64,58.6895977 L58.3344072,72.3699713 C58.4295481,72.4423583 58.5221874,72.5195778 58.6119911,72.6016299 L58.7445283,72.7283325 L64.006,77.9895977 L69.2684411,72.7283325 C69.3957231,72.6010505 69.5294489,72.4841397 69.6685683,72.3775999 L64,58.6895977 Z M38.5026635,2.59571369 C40.7118025,2.59571369 42.5026635,4.38657469 42.5026635,6.59571369 C42.5026635,7.7643162 42.0015346,8.8158738 41.2024517,9.54721162 L41.372583,9.372583 C35.581722,15.163444 32,23.163444 32,32 C32,40.8370609 35.5821314,48.8374703 41.3735757,54.6284097 C42.0884306,55.3520538 42.531226,56.3471171 42.531226,57.4456008 C42.531226,59.6547398 40.740365,61.4456008 38.531226,61.4456008 C37.4327422,61.4456008 36.4376789,61.0028055 35.7147885,60.2859673 L35.7048234,60.2963403 C28.472656,53.0586276 24,43.0631255 24,32.0229786 C24,21.1046577 28.3744907,11.2080539 35.4664167,3.99022262 C36.2004724,3.13678606 37.2883808,2.59571369 38.5026635,2.59571369 Z M89.3688013,2.48959773 C90.5097745,2.48959773 91.5391719,2.96731026 92.2678917,3.73363348 L92.2733617,3.72780197 C99.5183488,10.9672382 104,20.9717355 104,32.0229786 C104,42.8488024 99.6993143,52.6701472 92.7132398,59.8717162 C91.9816831,60.8152368 90.8371876,61.4223982 89.5508819,61.4223982 C87.3417429,61.4223982 85.5508819,59.6315372 85.5508819,57.4223982 C85.5508819,56.3502862 85.9726717,55.3766885 86.6593633,54.6584932 L86.627417,54.627417 C92.418278,48.836556 96,40.836556 96,32 C96,23.2702193 92.5043135,15.3568999 86.8363661,9.5834674 C85.9399594,8.85136737 85.3688013,7.73718311 85.3688013,6.48959773 C85.3688013,4.28045873 87.1596623,2.48959773 89.3688013,2.48959773 Z M50.0871028,13.6297119 C52.2962418,13.6297119 54.0871028,15.4205729 54.0871028,17.6297119 C54.0871028,18.8506134 53.5401157,19.9437593 52.6778337,20.6774573 L52.6862915,20.6862915 C49.790861,23.581722 48,27.581722 48,32 C48,36.4187838 49.791271,40.4191937 52.6872859,43.3147028 L52.6777105,43.3251493 C53.4423082,44.0537041 53.918794,45.0819221 53.918794,46.2214294 C53.918794,48.4305684 52.127933,50.2214294 49.918794,50.2214294 C48.6900999,50.2214294 47.5907975,49.6674376 46.8570439,48.7956109 L47.0304281,48.9715536 C42.6867001,44.6283295 40,38.627921 40,32 C40,25.372583 42.6862915,19.372583 47.0294373,15.0294373 L47.0395567,15.0387468 C47.7732533,14.1766 48.8663118,13.6297119 50.0871028,13.6297119 Z M77.9823819,13.700452 C79.1679628,13.700452 80.2330731,14.2162483 80.9655529,15.0356811 L80.9715536,15.0304281 C85.314117,19.3734956 88,25.373087 88,32 C88,38.4619387 85.4461804,44.3274009 81.2927766,48.6421512 L80.9933974,48.9476975 C80.2638884,49.7186971 79.2309977,50.2000547 78.08568,50.2000547 C75.876541,50.2000547 74.08568,48.4091937 74.08568,46.2000547 C74.08568,45.0665777 74.557136,44.0432152 75.314649,43.3153662 L75.3137085,43.3137085 C78.209139,40.418278 80,36.418278 80,32 C80,27.5822253 78.209547,23.5826334 75.314698,20.6872811 C74.4981782,19.9511432 73.9823819,18.8860329 73.9823819,17.700452 C73.9823819,15.491313 75.7732429,13.700452 77.9823819,13.700452 Z M64,24 C68.418278,24 72,27.581722 72,32 C72,36.418278 68.418278,40 64,40 C59.581722,40 56,36.418278 56,32 C56,27.581722 59.581722,24 64,24 Z"></path>
</g>
</svg>

View File

@@ -32,8 +32,6 @@ ExportTiddler/Caption: export tiddler
ExportTiddler/Hint: Export tiddler
ExportTiddlers/Caption: export tiddlers
ExportTiddlers/Hint: Export tiddlers
ExportTiddlyWikiCore/Caption: export TiddlyWiki core
ExportTiddlyWikiCore/Hint: Export the ~TiddlyWiki core code for running with external ~JavaScript
SidebarSearch/Hint: Select the sidebar search field
Fold/Caption: fold tiddler
Fold/Hint: Fold the body of this tiddler
@@ -85,8 +83,6 @@ Permaview/Caption: permaview
Permaview/Hint: Set browser address bar to a direct link to all the tiddlers in this story
Print/Caption: print page
Print/Hint: Print the current page
Publish/Caption: publish
Publish/Hint: Publish from the wiki
Refresh/Caption: refresh
Refresh/Hint: Perform a full refresh of the wiki
Save/Caption: ok

View File

@@ -27,10 +27,15 @@ Basics/Tiddlers/Prompt: Number of tiddlers
Basics/Title/Prompt: Title of this ~TiddlyWiki
Basics/Username/Prompt: Username for signing edits
Basics/Version/Prompt: ~TiddlyWiki version
Cascades/Caption: Cascades
Cascades/Hint: These global rules are used to dynamically choose certain templates. The result of the cascade is the result of the first filter in the sequence that returns a result
Cascades/TagPrompt: Filters tagged <$macrocall $name="tag" tag=<<currentTiddler>>/>
EditorTypes/Caption: Editor Types
EditorTypes/Editor/Caption: Editor
EditorTypes/Hint: These tiddlers determine which editor is used to edit specific tiddler types.
EditorTypes/Type/Caption: Type
EditTemplateBody/Caption: Edit Template Body
EditTemplateBody/Hint: This rule cascade is used by the default edit template to dynamically choose the template for editing the body of a tiddler.
Info/Caption: Info
Info/Hint: Information about this TiddlyWiki
KeyboardShortcuts/Add/Prompt: Type shortcut here
@@ -96,8 +101,6 @@ Plugins/Updates/Caption: Updates
Plugins/Updates/Hint: Available updates to installed plugins
Plugins/Updates/UpdateAll/Caption: Update <<update-count>> plugins
Plugins/SubPluginPrompt: With <<count>> sub-plugins available
Publishing/Caption: Publishing
Publishing/Hint: Settings used for publishing extracts from this TiddlyWiki as separate files through a "publisher" module
Saving/Caption: Saving
Saving/DownloadSaver/AutoSave/Description: Permit automatic saving for the download saver
Saving/DownloadSaver/AutoSave/Hint: Enable Autosave for Download Saver
@@ -193,6 +196,8 @@ Settings/TitleLinks/Yes/Description: Display tiddler titles as links
Settings/MissingLinks/Caption: Wiki Links
Settings/MissingLinks/Hint: Choose whether to link to tiddlers that do not exist yet
Settings/MissingLinks/Description: Enable links to missing tiddlers
StoryTiddler/Caption: Story Tiddler
StoryTiddler/Hint: This rule cascade is used to dynamically choose the template for displaying a tiddler in the story river.
StoryView/Caption: Story View
StoryView/Prompt: Current view:
Stylesheets/Caption: Stylesheets
@@ -203,6 +208,8 @@ Theme/Caption: Theme
Theme/Prompt: Current theme:
TiddlerFields/Caption: Tiddler Fields
TiddlerFields/Hint: This is the full set of TiddlerFields in use in this wiki (including system tiddlers but excluding shadow tiddlers).
TiddlerIcon/Caption: Tiddler Icon
TiddlerIcon/Hint: This rules cascade is used to dynamically choose the icon for a tiddler.
Toolbars/Caption: Toolbars
Toolbars/EditToolbar/Caption: Edit Toolbar
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode. Drag and drop to change the ordering
@@ -214,3 +221,7 @@ Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor to
Toolbars/ViewToolbar/Caption: View Toolbar
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode. Drag and drop to change the ordering
Tools/Download/Full/Caption: Download full wiki
ViewTemplateBody/Caption: View Template Body
ViewTemplateBody/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the body of a tiddler.
ViewTemplateTitle/Caption: View Template Title
ViewTemplateTitle/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the title of a tiddler.

View File

@@ -22,8 +22,6 @@ All parameters are optional with safe defaults, and can be specified in any orde
* ''readers'' - comma-separated list of principals allowed to read from this wiki
* ''writers'' - comma-separated list of principals allowed to write to this wiki
* ''csrf-disable'' - set to "yes" to disable CSRF checks (defaults to "no")
* ''sse-enabled'' - set to "yes" to enable Server-sent events (defaults to "no")
* ''sitemap'' - optional sitemap describing how the tiddlers will be served. See [[Publishing]] for more details
* ''root-tiddler'' - the tiddler to serve at the root (defaults to "$:/core/save/all")
* ''root-render-type'' - the content type to which the root tiddler should be rendered (defaults to "text/plain")
* ''root-serve-type'' - the content type with which the root tiddler should be served (defaults to "text/html")

View File

@@ -30,5 +30,5 @@ Upgrader/System/Warning: Core module tiddler.
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable.
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>.
Upgrader/Tiddler/Disabled: Disabled tiddler.
Upgrader/Tiddler/Selected: User selected.
Upgrader/Tiddler/Selected: Selected tiddler.
Upgrader/Tiddler/Unselected: Unselected tiddler.

View File

@@ -1,5 +0,0 @@
title: $:/language/Publishing/Modal
subtitle: Publishing: ''<$transclude field="caption"><$view field="title"/></$transclude>''
footer: <$button message="tm-close-tiddler">Cancel</$button>
Publishing <$text text=<<totalFiles>>/> files via the "{{!!publisher}}" publisher.

View File

@@ -1,46 +0,0 @@
/*\
title: $:/core/modules/commands/publish.js
type: application/javascript
module-type: command
Publish static files
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "publish",
synchronous: false
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
var self = this,
wiki = this.commander.wiki,
jobTiddler = this.params[0],
variableList = this.params.slice(1),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.publisherHandler.publish(jobTiddler,this.callback,{commander: this.commander,variables: variables});
return null;
};
exports.Command = Command;
})();

View File

@@ -8,58 +8,59 @@ Render individual tiddlers and save the results to the specified files
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "render",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing tiddler filter";
}
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
type = this.params[2] || "text/html",
template = this.params[3],
variableList = this.params.slice(4),
tiddlers = wiki.filterTiddlers(tiddlerFilter),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.utils.each(tiddlers,function(title) {
var parser = wiki.parseTiddler(template || title);
var widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent,
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 + "\"");
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "render",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing tiddler filter";
}
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,text,"utf8");
});
return null;
};
exports.Command = Command;
})();
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
type = this.params[2] || "text/html",
template = this.params[3],
variableList = this.params.slice(4),
tiddlers = wiki.filterTiddlers(tiddlerFilter),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.utils.each(tiddlers,function(title) {
var 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 + "\"");
}
var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title})}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent;
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,text,"utf8");
});
return null;
};
exports.Command = Command;
})();

View File

@@ -135,7 +135,11 @@ FramedEngine.prototype.setText = function(text,type) {
Update the DomNode with the new text
*/
FramedEngine.prototype.updateDomNodeText = function(text) {
this.domNode.value = text;
try {
this.domNode.value = text;
} catch(e) {
// Ignore
}
};
/*
@@ -201,7 +205,7 @@ FramedEngine.prototype.handleInputEvent = function(event) {
this.widget.saveChanges(this.getText());
this.fixHeight();
if(this.widget.editInputActions) {
this.widget.invokeActionString(this.widget.editInputActions);
this.widget.invokeActionString(this.widget.editInputActions,this,event,{actionValue: this.getText()});
}
return true;
};

View File

@@ -85,7 +85,11 @@ SimpleEngine.prototype.setText = function(text,type) {
Update the DomNode with the new text
*/
SimpleEngine.prototype.updateDomNodeText = function(text) {
this.domNode.value = text;
try {
this.domNode.value = text;
} catch(e) {
// Ignore
}
};
/*
@@ -129,7 +133,7 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
this.widget.saveChanges(this.getText());
this.fixHeight();
if(this.widget.editInputActions) {
this.widget.invokeActionString(this.widget.editInputActions);
this.widget.invokeActionString(this.widget.editInputActions,this,event,{actionValue: this.getText()});
}
return true;
};

View File

@@ -332,7 +332,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
};
EditTextWidget.prototype.handlePasteEvent = function(event) {
if(event.clipboardData.files.length) {
if(event.clipboardData && event.clipboardData.files && event.clipboardData.files.length) {
event.preventDefault();
event.stopPropagation();
this.dispatchDOMEvent(this.cloneEvent(event,["clipboardData"]));

View File

@@ -0,0 +1,17 @@
/*\
title: $:/core/modules/editor/operations/text/focus-editor.js
type: application/javascript
module-type: texteditoroperation
Simply focus the Text editor
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports["focus-editor"] = function(event,operation) {
operation = null;
};
})();

View File

@@ -0,0 +1,51 @@
/*\
title: $:/core/modules/filterrunprefixes/cascade.js
type: application/javascript
module-type: filterrunprefix
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.cascade = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length !== 0) {
var filterList = operationSubFunction(source,widget),
filterFnList = [];
var inputResults = results.toArray();
results.clear();
$tw.utils.each(inputResults,function(title) {
var result = ""; // If no filter matches, we return an empty string
$tw.utils.each(filterList,function(filter,index) {
if(!filterFnList[index]) {
filterFnList[index] = options.wiki.compileFilter(filter);
}
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),{
getVariable: function(name) {
switch(name) {
case "currentTiddler":
return "" + title;
case "..currentTiddler":
return widget.getVariable("currentTiddler");
default:
return widget.getVariable(name);
}
}
});
if(output.length !== 0) {
result = output[0];
return false;
}
});
results.push(result);
});
}
}
};
})();

View File

@@ -15,7 +15,8 @@ Export our filter prefix function
exports.map = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
var inputTitles = results.toArray();
var inputTitles = results.toArray(),
index = 0;
results.clear();
$tw.utils.each(inputTitles,function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),{
@@ -25,12 +26,19 @@ exports.map = function(operationSubFunction,options) {
return "" + title;
case "..currentTiddler":
return widget.getVariable("currentTiddler");
case "index":
return "" + index;
case "revIndex":
return "" + (inputTitles.length - 1 - index);
case "length":
return "" + inputTitles.length;
default:
return widget.getVariable(name);
}
}
});
results.push(filtered[0] || "");
++index;
});
}
}

View File

@@ -52,7 +52,7 @@ exports.all = function(source,operator,options) {
results.pushTop(subop(source,operator.prefix,options));
}
}
return results.toArray();
return results.makeTiddlerIterator(options.wiki);
};
})();

View File

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

View File

@@ -19,12 +19,7 @@ Export our filter functions
exports.decodeuricomponent = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
var value = title;
try {
value = decodeURIComponent(title);
} catch(e) {
}
results.push(value);
results.push($tw.utils.decodeURIComponentSafe(title));
});
return results;
};
@@ -40,12 +35,7 @@ exports.encodeuricomponent = function(source,operator,options) {
exports.decodeuri = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
var value = title;
try {
value = decodeURI(title);
} catch(e) {
}
results.push(value);
results.push($tw.utils.decodeURISafe(title));
});
return results;
};

View File

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

View File

@@ -103,4 +103,16 @@ exports.nth = function(source,operator,options) {
return results.slice(count - 1,count);
};
/*
The zero based nth member of the list
*/
exports.zth = function(source,operator,options) {
var count = $tw.utils.getInt(operator.operand,0),
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(count,count + 1);
};
})();

View File

@@ -165,6 +165,35 @@ exports["standard-deviation"] = makeNumericReducingOperator(
}
);
//trigonometry
exports.cos = makeNumericBinaryOperator(
function(a) {return Math.cos(a)}
);
exports.sin = makeNumericBinaryOperator(
function(a) {return Math.sin(a)}
);
exports.tan = makeNumericBinaryOperator(
function(a) {return Math.tan(a)}
);
exports.acos = makeNumericBinaryOperator(
function(a) {return Math.acos(a)}
);
exports.asin = makeNumericBinaryOperator(
function(a) {return Math.asin(a)}
);
exports.atan = makeNumericBinaryOperator(
function(a) {return Math.atan(a)}
);
exports.atan2 = makeNumericBinaryOperator(
function(a,b) {return Math.atan2(a,b)}
);
//Calculate the variance of a population of numbers in an array given its mean
function getVarianceFromArray(values,mean) {
var deviationTotal = values.reduce(function(accumulator,value) {

View File

@@ -17,14 +17,7 @@ Export our filter function
*/
exports.modules = function(source,operator,options) {
var results = [];
if(operator.operands.length === 1) {
// Return all the module names without filtering
source(function(tiddler,title) {
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
results.push(moduleName);
});
});
} else if(operator.operands.length >= 2) {
if(operator.operands.length >= 2) {
// Return the modules that have the module property specified in the first operand with the value in the second operand
source(function(tiddler,title) {
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
@@ -33,6 +26,13 @@ exports.modules = function(source,operator,options) {
}
});
});
} else {
// Return all the module names without filtering
source(function(tiddler,title) {
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
results.push(moduleName);
});
});
}
results.sort();
return results;

View File

@@ -1,30 +0,0 @@
/*\
title: $:/core/modules/filters/modulestring.js
type: application/javascript
module-type: filteroperator
Filter [[module-name]modulestring[en-gb]] retrieve a module strings in a particular language
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.modulestring = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
var s = $tw.modules.getModuleString(title,operator.operands[0] || "",operator.operands[1] || "");
if(s !== null) {
results.push(s);
}
});
results.sort();
return results;
};
})();

View File

@@ -17,9 +17,13 @@ Export our filter function
*/
exports.range = function(source,operator,options) {
var results = [];
// Split the operand into numbers delimited by these symbols
var parts = operator.operand.split(/[,:;]/g),
beg, end, inc, i, fixed = 0;
// For backwards compatibility, if there is only one operand, try to split it using one of the delimiters
var parts = operator.operands || [];
if(parts.length === 1) {
parts = operator.operand.split(/[,:;]/g);
}
// Process the parts
var beg, end, inc, i, fixed = 0;
for (i=0; i<parts.length; i++) {
// Validate real number
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {

View File

@@ -119,23 +119,25 @@ exports["search-replace"] = function(source,operator,options) {
var results = [],
suffixes = operator.suffixes || [],
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : ""),
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : "") + (flagSuffix.indexOf("m") !== -1 ? "m" : ""),
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
searchTerm,
//Escape regexp characters if the operand is not a regular expression
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand),
//Escape $ character in replacement string if not in regular expression mode
replacement = isRegExp ? operator.operands[1] : (operator.operands[1]||"").replace(/\$/g,"$$$$"),
regExp;
try {
regExp = new RegExp(searchTerm,flags);
} catch(ex) {
return ["RegExp error: " + ex];
}
source(function(tiddler,title) {
if(title && (operator.operands.length > 1)) {
//Escape regexp characters if the operand is not a regular expression
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand);
try {
regExp = new RegExp(searchTerm,flags);
} catch(ex) {
return ["RegExp error: " + ex];
}
results.push(
title.replace(regExp,operator.operands[1])
title.replace(regExp,replacement)
);
regExp.lastIndex = 0;
} else {
results.push(title);
}

View File

@@ -16,20 +16,13 @@ Filter operator returning all the selected tiddlers that are untagged
Export our filter function
*/
exports.untagged = function(source,operator,options) {
var results = [];
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) {
$tw.utils.pushTop(results,title);
}
});
} else {
source(function(tiddler,title) {
if(!tiddler || !tiddler.hasField("tags") || ($tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length === 0)) {
$tw.utils.pushTop(results,title);
}
});
}
var results = [],
expected = (operator.prefix === "!");
source(function(tiddler,title) {
if((tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0) === expected) {
results.push(title);
}
});
return results;
};

View File

@@ -66,7 +66,7 @@ exports.parse = function() {
};
/*
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: {}, orderedAttributes: [], isSelfClosing:, start:, end:,}
*/
exports.parseTag = function(source,pos,options) {
options = options || {};
@@ -74,7 +74,8 @@ exports.parseTag = function(source,pos,options) {
node = {
type: "element",
start: pos,
attributes: {}
attributes: {},
orderedAttributes: []
};
// Define our regexps
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
@@ -106,6 +107,7 @@ exports.parseTag = function(source,pos,options) {
// Process attributes
var attribute = $tw.utils.parseAttribute(source,pos);
while(attribute) {
node.orderedAttributes.push(attribute);
node.attributes[attribute.name] = attribute;
pos = attribute.end;
// Get the next attribute

View File

@@ -231,7 +231,10 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
return nextMatch.rule.parse();
}
// Treat it as a paragraph if we didn't find a block rule
return [{type: "element", tag: "p", children: this.parseInlineRun(terminatorRegExp)}];
var start = this.pos;
var children = this.parseInlineRun(terminatorRegExp);
var end = this.pos;
return [{type: "element", tag: "p", children: children, start: start, end: end }];
};
/*
@@ -307,7 +310,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
while(this.pos < this.sourceLength && nextMatch) {
// Process the text preceding the run rule
if(nextMatch.matchIndex > this.pos) {
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex));
this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex),this.pos,nextMatch.matchIndex);
this.pos = nextMatch.matchIndex;
}
// Process the run rule
@@ -317,7 +320,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
}
// Process the remaining text
if(this.pos < this.sourceLength) {
this.pushTextWidget(tree,this.source.substr(this.pos));
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
}
this.pos = this.sourceLength;
return tree;
@@ -337,7 +340,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
if(terminatorMatch) {
if(!inlineRuleMatch || inlineRuleMatch.matchIndex >= terminatorMatch.index) {
if(terminatorMatch.index > this.pos) {
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index));
this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index),this.pos,terminatorMatch.index);
}
this.pos = terminatorMatch.index;
if(options.eatTerminator) {
@@ -350,7 +353,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
if(inlineRuleMatch) {
// Preceding text
if(inlineRuleMatch.matchIndex > this.pos) {
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex));
this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex),this.pos,inlineRuleMatch.matchIndex);
this.pos = inlineRuleMatch.matchIndex;
}
// Process the inline rule
@@ -364,7 +367,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
}
// Process the remaining text
if(this.pos < this.sourceLength) {
this.pushTextWidget(tree,this.source.substr(this.pos));
this.pushTextWidget(tree,this.source.substr(this.pos),this.pos,this.sourceLength);
}
this.pos = this.sourceLength;
return tree;
@@ -373,12 +376,12 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
/*
Push a text widget onto an array, respecting the configTrimWhiteSpace setting
*/
WikiParser.prototype.pushTextWidget = function(array,text) {
WikiParser.prototype.pushTextWidget = function(array,text,start,end) {
if(this.configTrimWhiteSpace) {
text = $tw.utils.trim(text);
}
if(text) {
array.push({type: "text", text: text});
array.push({type: "text", text: text, start: start, end: end});
}
};

View File

@@ -1,181 +0,0 @@
/*\
title: $:/core/modules/publisherhandler.js
type: application/javascript
module-type: global
The publisher manages publishing extracts of wikis as external files
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var PUBLISHING_MODAL_TITLE = "$:/language/Publishing/Modal";
/*
Instantiate the publisher manager with the following options
wiki: wiki object to be used
commander: commander object to be used for output
*/
function PublisherHandler(options) {
this.wiki = options.wiki;
this.commander = options.commander;
}
/*
Publish a job
jobTitle: title of tiddler containing details of the job
callback: completion callback invoked callback(err)
options: Include:
commander: commander object associated with publishing under Node.js
variables: hashmap of variables to be passed to renderings
*/
PublisherHandler.prototype.publish = function(jobTitle,callback,options) {
if(jobTitle) {
var job = new PublishingJob(jobTitle,this,options);
job.publish(callback);
}
};
function PublishingJob(jobTitle,publisherHandler,options) {
options = options || {};
// Save params
this.jobTitle = jobTitle;
this.publisherHandler = publisherHandler;
this.commander = options.commander;
this.publishVariables = options.variables || Object.create(null);
}
/*
Start publishing
*/
PublishingJob.prototype.publish = function(callback) {
var self = this;
// Get the job tiddler and check it is enabled
this.jobTiddler = this.publisherHandler.wiki.getTiddler(this.jobTitle);
if(this.jobTiddler && this.jobTiddler.fields.enabled === "yes") {
// Get the list of tiddlers to be exported, defaulting to all non-system tiddlers
this.exportList = this.publisherHandler.wiki.filterTiddlers(this.jobTiddler.fields["export-filter"] || "[!is[system]]");
// Get publisher
this.publisher = this.getPublisher(this.jobTiddler.fields.publisher);
if(this.publisher) {
// Get the sitemap
this.sitemap = new $tw.Sitemap(this.jobTiddler.fields.sitemap,{
wiki: this.publisherHandler.wiki,
variables: this.publishVariables
});
this.sitemap.load();
// Get the output operations
this.operations = this.sitemap.getAllFileDetails(this.exportList);
// Display the progress modal
if($tw.modal) {
this.progressModal = $tw.modal.display(PUBLISHING_MODAL_TITLE,{
progress: true,
variables: {
currentTiddler: this.jobTitle,
totalFiles: this.operations.length + ""
},
onclose: function(event) {
if(event !== self) {
// The modal was closed other than by us programmatically
self.isCancelled = true;
}
}
});
}
// Send the operations to the publisher
this.executeOperations(function(err) {
if(self.progressModal) {
self.progressModal.closeHandler(self);
}
callback(err);
});
} else {
return callback("Unrecognised publisher");
}
} else {
return callback("Missing or disabled job tiddler");
}
};
/*
Instantiate the required publisher object
*/
PublishingJob.prototype.getPublisher = function(publisherName) {
var publisher;
$tw.modules.forEachModuleOfType("publisher",function(title,module) {
if(module.name === publisherName) {
publisher = module;
}
});
return publisher && publisher.create(this.jobTiddler.fields,this.publisherHandler,this);
};
/*
Execute the operations for this job
*/
PublishingJob.prototype.executeOperations = function(callback) {
var self = this,
report = {overwrites: []},
nextOperation = 0,
performNextOperation = function() {
// Check for having been cancelled
if(self.isCancelled) {
if(self.publisher.publishCancel) {
self.publisher.publishCancel();
}
return callback("CANCELLED");
}
// Update progress
if(self.progressModal) {
self.progressModal.setProgress(nextOperation,self.operations.length);
}
// Check for having finished
if(nextOperation >= self.operations.length) {
$tw.utils.nextTick(function() {
self.publisher.publishEnd(callback);
});
} else {
// Execute this operation
var fileDetails = self.operations[nextOperation]();
nextOperation += 1;
self.publisher.publishFile(fileDetails,function() {
$tw.utils.nextTick(performNextOperation);
});
}
};
// Tell the publisher to start, and get back an array of the existing paths
self.publisher.publishStart(function(existingPaths) {
var paths = {};
$tw.utils.each(self.operations,function(operation) {
if(operation.path in paths) {
report.overwrites.push(operation.path);
}
paths[operation.path] = true;
});
// Run the operations
performNextOperation();
});
};
PublishingJob.prototype.saveReport = function(report) {
// Create the report tiddler
var reportTitle = this.wiki.generateNewTitle("$:/temp/publish-report");
$tw.wiki.addTiddler({
title: reportTitle,
text: "* " + report.overwrites.join("\n* ")
});
// Add the report tiddler title to the list field of the publisher parameters tiddler
var paramsTiddler = $tw.wiki.getTiddler(this.publisherParamsTitle),
list = (paramsTiddler.fields.list || []).slice(0);
list.unshift(reportTitle);
$tw.wiki.addTiddler(new $tw.Tiddler(paramsTiddler,{list: list}));
};
exports.PublisherHandler = PublisherHandler;
})();

View File

@@ -1,52 +0,0 @@
/*\
title: $:/core/modules/publishers/filesystem.js
type: application/javascript
module-type: publisher
Handles publishing to the Node.js filesystem
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.name = "filesystem";
exports.create = function(params,publisherHandler,publishingJob) {
return new FileSystemPublisher(params,publisherHandler,publishingJob);
};
function FileSystemPublisher(params,publisherHandler,publishingJob) {
this.params = params;
this.publisherHandler = publisherHandler;
this.publishingJob = publishingJob;
};
FileSystemPublisher.prototype.publishStart = function(callback) {
console.log("publishStart");
// Returns a list of the previously published files
callback([]);
};
FileSystemPublisher.prototype.publishFile = function(item,callback) {
var fs = require("fs"),
path = require("path"),
filepath = path.resolve(this.publishingJob.commander.outputPath,item.path);
$tw.utils.createFileDirectories(filepath);
fs.writeFile(filepath,item.text,item.isBase64 ? "base64" : "utf8",function(err) {
if(err) {
console.log("File writing error",err)
}
callback(err);
});
};
FileSystemPublisher.prototype.publishEnd = function(callback) {
console.log("publishEnd");
callback(null);
};
})();

View File

@@ -42,7 +42,7 @@ AndTidWiki.prototype.save = function(text,method,callback,options) {
window.twi.saveWiki(text);
} else {
// Get the pathname of this document
var pathname = decodeURIComponent(document.location.toString().split("#")[0]);
var pathname = $tw.utils.decodeURIComponentSafe(document.location.toString().split("#")[0]);
// Strip the file://
if(pathname.indexOf("file://") === 0) {
pathname = pathname.substr(7);

View File

@@ -26,7 +26,7 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
var p = document.location.pathname.lastIndexOf("/");
if(p !== -1) {
// We decode the pathname because document.location is URL encoded by the browser
filename = decodeURIComponent(document.location.pathname.substr(p+1));
filename = $tw.utils.decodeURIComponentSafe(document.location.pathname.substr(p+1));
}
}
if(!filename) {

View File

@@ -72,7 +72,7 @@ GiteaSaver.prototype.save = function(text,method,callback) {
}
}
var data = {
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
content: $tw.utils.base64Encode(text),
sha: sha
};

View File

@@ -69,7 +69,7 @@ GitHubSaver.prototype.save = function(text,method,callback) {
});
}
var data = {
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
content: $tw.utils.base64Encode(text),
branch: branch,
sha: sha

View File

@@ -67,7 +67,7 @@ GitLabSaver.prototype.save = function(text,method,callback) {
});
}
var data = {
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
commit_message: $tw.language.getString("ControlPanel/Saving/GitService/CommitMessage"),
content: text,
branch: branch,
sha: sha

View File

@@ -43,7 +43,7 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
}
// Create the message element and put it in the message box
var message = document.createElement("div");
message.setAttribute("data-tiddlyfox-path",decodeURIComponent(pathname));
message.setAttribute("data-tiddlyfox-path",$tw.utils.decodeURIComponentSafe(pathname));
message.setAttribute("data-tiddlyfox-content",text);
messageBox.appendChild(message);
// Add an event handler for when the file has been saved

View File

@@ -21,7 +21,7 @@ TWEditSaver.prototype.save = function(text,method,callback) {
return false;
}
// Get the pathname of this document
var pathname = decodeURIComponent(document.location.pathname);
var pathname = $tw.utils.decodeURIComponentSafe(document.location.pathname);
// Strip any query or location part
var p = pathname.indexOf("?");
if(p !== -1) {

View File

@@ -17,7 +17,7 @@ exports.method = "DELETE";
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
exports.handler = function(request,response,state) {
var title = decodeURIComponent(state.params[0]);
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
state.wiki.deleteTiddler(title);
response.writeHead(204, "OK", {
"Content-Type": "text/plain"

View File

@@ -20,22 +20,29 @@ exports.handler = function(request,response,state) {
var path = require("path"),
fs = require("fs"),
util = require("util"),
suppliedFilename = decodeURIComponent(state.params[0]),
filename = path.resolve(state.boot.wikiPath,"files",suppliedFilename),
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
baseFilename = path.resolve(state.boot.wikiPath,"files"),
filename = path.resolve(baseFilename,suppliedFilename),
extension = path.extname(filename);
fs.readFile(filename,function(err,content) {
var status,content,type = "text/plain";
if(err) {
console.log("Error accessing file " + filename + ": " + err.toString());
status = 404;
content = "File '" + suppliedFilename + "' not found";
} else {
status = 200;
content = content;
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
}
state.sendResponse(status,{"Content-Type": type},content);
});
// Check that the filename is inside the wiki files folder
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
// Send the file
fs.readFile(filename,function(err,content) {
var status,content,type = "text/plain";
if(err) {
console.log("Error accessing file " + filename + ": " + err.toString());
status = 404;
content = "File '" + suppliedFilename + "' not found";
} else {
status = 200;
content = content;
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
}
state.sendResponse(status,{"Content-Type": type},content);
});
} else {
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
}
};
}());

View File

@@ -14,7 +14,7 @@ GET /
exports.method = "GET";
exports.path = /^\/index.html$/;
exports.path = /^\/$/;
exports.handler = function(request,response,state) {
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),

View File

@@ -21,7 +21,6 @@ exports.handler = function(request,response,state) {
username: state.authenticatedUsername || state.server.get("anon-username") || "",
anonymous: !state.authenticatedUsername,
read_only: !state.server.isAuthorized("writers",state.authenticatedUsername),
sse_enabled: state.server.get("sse-enabled") === "yes",
space: {
recipe: "default"
},

View File

@@ -17,7 +17,7 @@ exports.method = "GET";
exports.path = /^\/([^\/]+)$/;
exports.handler = function(request,response,state) {
var title = decodeURIComponent(state.params[0]),
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
tiddler = state.wiki.getTiddler(title);
if(tiddler) {
var renderType = tiddler.getFieldString("_render_type"),

View File

@@ -17,7 +17,7 @@ exports.method = "GET";
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
exports.handler = function(request,response,state) {
var title = decodeURIComponent(state.params[0]),
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
tiddler = state.wiki.getTiddler(title),
tiddlerFields = {},
knownFields = [

View File

@@ -17,7 +17,7 @@ exports.method = "PUT";
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
exports.handler = function(request,response,state) {
var title = decodeURIComponent(state.params[0]),
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
fields = JSON.parse(state.data);
// Pull up any subfields in the `fields` object
if(fields.fields) {
@@ -30,7 +30,7 @@ exports.handler = function(request,response,state) {
if(fields.revision) {
delete fields.revision;
}
state.wiki.addTiddler(new $tw.Tiddler(state.wiki.getCreationFields(),fields,{title: title},state.wiki.getModificationFields()));
state.wiki.addTiddler(new $tw.Tiddler(fields,{title: title}));
var changeCount = state.wiki.getChangeCount(title).toString();
response.writeHead(204, "OK",{
Etag: "\"default/" + encodeURIComponent(title) + "/" + changeCount + ":\"",

View File

@@ -1,70 +0,0 @@
/*\
title: $:/core/modules/server/server-sent-events.js
type: application/javascript
module-type: library
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
parameters:
prefix - usually the plugin path, such as `plugins/tiddlywiki/tiddlyweb`. The
route will match `/events/${prefix}` exactly.
handler - a function that will be called each time a request comes in with the
request and state from the route and an emit function to call.
*/
var ServerSentEvents = function ServerSentEvents(prefix, handler) {
this.handler = handler;
this.prefix = prefix;
};
ServerSentEvents.prototype.getExports = function() {
return {
bodyFormat: "stream",
method: "GET",
path: new RegExp("^/events/" + this.prefix + "$"),
handler: this.handleEventRequest.bind(this)
};
};
ServerSentEvents.prototype.handleEventRequest = function(request,response,state) {
if(ServerSentEvents.prototype.isEventStreamRequest(request)) {
response.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
});
this.handler(request,state,this.emit.bind(this,response),this.end.bind(this,response));
} else {
response.writeHead(406,"Not Acceptable",{});
response.end();
}
};
ServerSentEvents.prototype.isEventStreamRequest = function(request) {
return request.headers.accept &&
request.headers.accept.match(/^text\/event-stream/);
};
ServerSentEvents.prototype.emit = function(response,event,data) {
if(typeof event !== "string" || event.indexOf("\n") !== -1) {
throw new Error("Type must be a single-line string");
}
if(typeof data !== "string" || data.indexOf("\n") !== -1) {
throw new Error("Data must be a single-line string");
}
response.write("event: " + event + "\ndata: " + data + "\n\n", "utf8");
};
ServerSentEvents.prototype.end = function(response) {
response.end();
};
exports.ServerSentEvents = ServerSentEvents;
})();

View File

@@ -63,7 +63,10 @@ function Server(options) {
self.addAuthenticator(authenticatorDefinition.AuthenticatorClass);
});
// Load route handlers
this.addRouteHandlers();
$tw.modules.forEachModuleOfType("route", function(title,routeDefinition) {
// console.log("Loading server route " + title);
self.addRoute(routeDefinition);
});
// Initialise the http vs https
this.listenOptions = null;
this.protocol = "http";
@@ -179,43 +182,11 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
}
};
Server.prototype.addRouteHandlers = function() {
var self = this;
// Load route handlers from sitemap if present, or just load all route modules
if(this.variables.sitemap) {
this.sitemap = new $tw.Sitemap(this.variables.sitemap,{
wiki: this.wiki,
variables: {}
});
this.sitemap.load();
$tw.utils.each(this.sitemap.getServerRoutes(),function(routeInfo) {
self.addRoute({
method: "GET",
path: routeInfo.regexp,
handler: function(request,response,state) {
var fileDetails = routeInfo.handler(state.params);
if(fileDetails) {
response.writeHead(200, {"Content-Type": fileDetails.type});
response.end(fileDetails.text,fileDetails.isBase64 ? "base64" : "utf8");
} else {
response.writeHead(404);
response.end();
}
}
});
});
} else {
$tw.modules.forEachModuleOfType("route",function(title,routeDefinition) {
self.addRoute(routeDefinition);
});
}
};
Server.prototype.findMatchingRoute = function(request,state,options) {
options = options || {};
Server.prototype.findMatchingRoute = function(request,state) {
for(var t=0; t<this.routes.length; t++) {
var potentialRoute = this.routes[t],
pathname = options.pathname || state.urlInfo.pathname,
pathRegExp = potentialRoute.path,
pathname = state.urlInfo.pathname,
match;
if(state.pathPrefix) {
if(pathname.substr(0,state.pathPrefix.length) === state.pathPrefix) {
@@ -292,15 +263,6 @@ Server.prototype.requestHandler = function(request,response,options) {
}
// Find the route that matches this path
var route = self.findMatchingRoute(request,state);
if(!route) {
// Try with the default document
var defaultDocumentPathname = state.urlInfo.pathname;
if(defaultDocumentPathname.substr(-1) !== "/") {
defaultDocumentPathname = defaultDocumentPathname + "/";
}
defaultDocumentPathname = defaultDocumentPathname + "index.html";
route = self.findMatchingRoute(request,state,{pathname: defaultDocumentPathname});
}
// Optionally output debug info
if(self.get("debug-level") !== "none") {
console.log("Request path:",JSON.stringify(state.urlInfo));

View File

@@ -1,236 +0,0 @@
/*\
title: $:/core/modules/sitemap.js
type: application/javascript
module-type: global
Sitemaps are used for static publishing and web serving
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function Sitemap(sitemapTitle,options) {
options = options || {};
this.sitemapTitle = sitemapTitle;
this.wiki = options.wiki;
this.routes = [];
this.variables = $tw.utils.extend({},options.variables);
}
Sitemap.prototype.load = function(sitemapTitle) {
var self = this;
// Get the sitemap
var sitemapTiddler = this.wiki.getTiddler(this.sitemapTitle);
if(sitemapTiddler) {
// Collect each route
$tw.utils.each(sitemapTiddler.fields.list,function(routeTitle) {
var routeTiddler = self.wiki.getTiddler(routeTitle);
if(routeTiddler) {
// Convert the path into a regexp and an array of {field:,function:} for each capture group
var regexpurgatedParameterisedPath = self.regexpurgateParameterisedPath(routeTiddler.fields["route-path"]);
self.routes.push({
title: routeTitle,
params: routeTiddler.getFieldStrings({prefix: "route-"}),
variables: routeTiddler.getFieldStrings({prefix: "var-"}),
regexp: regexpurgatedParameterisedPath.regexp,
captureGroups: regexpurgatedParameterisedPath.captureGroups
});
}
});
}
};
Sitemap.prototype.renderRoute = function(title,route) {
var tiddler = this.wiki.getTiddler(title);
switch(route.params.type) {
case "raw":
return {
path: this.resolveParameterisedPath(route.params.path,title),
text: tiddler.fields.text || "",
type: tiddler.fields.type || "",
isBase64: ($tw.config.contentTypeInfo[tiddler.fields.type] || {}).encoding === "base64"
};
break;
case "render":
var parser = {
tree: [
{
"type": "importvariables",
"attributes": {
"tiddler": {
"name": "tiddler",
"type": "string",
"value": this.sitemapTitle,
}
},
"tag": "$importvariables",
"isBlock": false,
"children": [
{
"type": "importvariables",
"attributes": {
"tiddler": {
"name": "tiddler",
"type": "string",
"value": route.title,
}
},
"tag": "$importvariables",
"isBlock": false,
"children": this.wiki.parseTiddler(route.params.template,{parseAsInline: true}).tree
}
]
}
]
},
widgetNode = this.wiki.makeWidget(parser,{
variables: $tw.utils.extend({},this.variables,{currentTiddler: title})
}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
return {
path: this.resolveParameterisedPath(route.params.path,title),
text: container.textContent,
type: route.params["output-type"] || "text/html"
};
break;
}
};
/*
Returns an array of functions that return {path:,text:,type:,isBase64:} for each path
*/
Sitemap.prototype.getAllFileDetails = function(exportTiddlers) {
var self = this,
output = [];
$tw.utils.each(this.routes,function(route) {
var routeFilter = route.params["tiddler-filter"] || "DUMMY_RESULT", // If no filter is provided, use a dummy filter that returns a single result
routeTiddlers = self.wiki.filterTiddlers(routeFilter,null,self.wiki.makeTiddlerIterator(exportTiddlers));
$tw.utils.each(routeTiddlers,function(title) {
output.push(self.renderRoute.bind(self,title,route));
});
});
return output;
};
/*
Returns an array of server routes {regexp:, handler:}
*/
Sitemap.prototype.getServerRoutes = function() {
var self = this,
output = [];
$tw.utils.each(this.routes,function(route) {
output.push({
regexp: route.regexp,
handler: function(params) {
// Locate the tiddler identified by the capture groups, if any
var title = null,
nextParam = 0;
$tw.utils.each(route.captureGroups,function(captureGroup) {
var param = params[nextParam++];
if(captureGroup.field === "title") {
switch(captureGroup.function) {
case "slugify":
var titles = self.wiki.unslugify(param);
if(titles && titles.length > 0) {
title = titles[0];
}
break;
}
}
})
// Check that the tiddler passes the route filter
if(route.params["tiddler-filter"]) {
if(!title) {
return null;
}
var routeTiddlers = self.wiki.filterTiddlers(route.params["tiddler-filter"],null,self.wiki.makeTiddlerIterator([title]));
if(routeTiddlers.indexOf(title) === -1) {
return null;
}
}
// Return the rendering or raw tiddler
return self.renderRoute(title,route);
}
});
});
return output;
};
/*
Apply a tiddler to a parameterised path to create a usable path
*/
Sitemap.prototype.resolveParameterisedPath = function(parameterisedPath,title) {
var self = this;
// Split the path on $*_*$ markers
var tiddler = this.wiki.getTiddler(title),
output = [];
$tw.utils.each(parameterisedPath.split(/(\$[a-z_]+\$)/),function(part) {
var match = part.match(/\$([a-z]+)_([a-z]+)\$/);
if(match) {
var value;
// Get the base value
switch(match[1]) {
case "uri":
case "title":
value = title;
break;
case "type":
value = tiddler.fields.type || "text/vnd.tiddlywiki";
break;
}
// Apply the encoding function
switch(match[2]) {
case "encoded":
value = encodeURIComponent(value);
break;
case "doubleencoded":
value = encodeURIComponent(encodeURIComponent(value));
break;
case "slugify":
value = self.wiki.slugify(value);
break;
case "extension":
value = ($tw.config.contentTypeInfo[value] || {extension: "."}).extension.slice(1);
break;
}
output.push(value);
} else {
output.push(part);
}
});
return output.join("");
};
/*
// Convert the path into a regexp and an array of {field:,function:} for each capture group
*/
Sitemap.prototype.regexpurgateParameterisedPath = function(parameterisedPath) {
var regexpParts = ["\\/"],
captureGroups = [];
$tw.utils.each(parameterisedPath.split(/(\$[a-z_]+\$)/),function(part) {
var match = part.match(/\$([a-z]+)_([a-z]+)\$/);
if(match) {
regexpParts.push("(.+)");
captureGroups.push({
field: match[1],
function: match[2]
});
} else {
regexpParts.push($tw.utils.escapeRegExp(part));
}
});
return {
regexp: new RegExp("^" + regexpParts.join("") + "$"),
captureGroups: captureGroups
};
};
exports.Sitemap = Sitemap;
})();

View File

@@ -73,12 +73,6 @@ exports.startup = function() {
}
});
}
// Hook up events for the publisher handler
$tw.rootWidget.addEventListener("tm-publish",function(event) {
$tw.publisherHandler.publish(event.paramObject.job,function(err) {
console.log("Finished publishing with result:",err);
});
});
// If we're being viewed on a data: URI then give instructions for how to save
if(document.location.protocol === "data:") {
$tw.rootWidget.dispatchEvent({

View File

@@ -129,10 +129,6 @@ exports.startup = function() {
dirtyTracking: !$tw.syncadaptor,
preloadDirty: $tw.boot.preloadDirty || []
});
// Install the publisher handler
$tw.publisherHandler = new $tw.PublisherHandler({
wiki: $tw.wiki
});
// Host-specific startup
if($tw.browser) {
// Install the popup manager

View File

@@ -120,10 +120,10 @@ function openStartupTiddlers(options) {
var hash = $tw.locationHash.substr(1),
split = hash.indexOf(":");
if(split === -1) {
target = decodeURIComponent(hash.trim());
target = $tw.utils.decodeURIComponentSafe(hash.trim());
} else {
target = decodeURIComponent(hash.substr(0,split).trim());
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
target = $tw.utils.decodeURIComponentSafe(hash.substr(0,split).trim());
storyFilter = $tw.utils.decodeURIComponentSafe(hash.substr(split + 1).trim());
}
}
// If the story wasn't specified use the current tiddlers or a blank story

View File

@@ -20,7 +20,6 @@ Syncer.prototype.titleIsAnonymous = "$:/status/IsAnonymous";
Syncer.prototype.titleIsReadOnly = "$:/status/IsReadOnly";
Syncer.prototype.titleUserName = "$:/status/UserName";
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
Syncer.prototype.titleSyncDisablePolling = "$:/config/SyncDisablePolling";
Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
@@ -90,7 +89,7 @@ function Syncer(options) {
if(filteredChanges.length > 0) {
self.processTaskQueue();
} else {
// Look for deletions of tiddlers we're already syncing
// Look for deletions of tiddlers we're already syncing
var outstandingDeletion = false
$tw.utils.each(changes,function(change,title,object) {
if(change.deleted && $tw.utils.hop(self.tiddlerInfo,title)) {
@@ -122,7 +121,7 @@ function Syncer(options) {
self.login(username,password,function() {});
} else {
// No username and password, so we display a prompt
self.handleLoginEvent();
self.handleLoginEvent();
}
});
$tw.rootWidget.addEventListener("tm-logout",function() {
@@ -139,7 +138,7 @@ function Syncer(options) {
if(!this.disableUI && this.wiki.getTiddlerText(this.titleSyncDisableLazyLoading) !== "yes") {
this.wiki.addEventListener("lazyLoad",function(title) {
self.handleLazyLoadEvent(title);
});
});
}
// Get the login status
this.getStatus(function(err,isLoggedIn) {
@@ -174,8 +173,8 @@ Syncer.prototype.getTiddlerRevision = function(title) {
if(this.syncadaptor && this.syncadaptor.getTiddlerRevision) {
return this.syncadaptor.getTiddlerRevision(title);
} else {
return this.wiki.getTiddler(title).fields.revision;
}
return this.wiki.getTiddler(title).fields.revision;
}
};
/*
@@ -268,9 +267,9 @@ Syncer.prototype.getStatus = function(callback) {
// Mark us as not logged in
this.wiki.addTiddler({title: this.titleIsLoggedIn,text: "no"});
// Get login status
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous,isPollingDisabled) {
this.syncadaptor.getStatus(function(err,isLoggedIn,username,isReadOnly,isAnonymous) {
if(err) {
self.logger.alert(err);
self.displayError("Get Status Error",err);
} else {
// Set the various status tiddlers
self.wiki.addTiddler({title: self.titleIsReadOnly,text: isReadOnly ? "yes" : "no"});
@@ -279,9 +278,6 @@ Syncer.prototype.getStatus = function(callback) {
if(isLoggedIn) {
self.wiki.addTiddler({title: self.titleUserName,text: username || ""});
}
if(isPollingDisabled) {
self.wiki.addTiddler({title: self.titleSyncDisablePolling, text: "yes"});
}
}
// Invoke the callback
if(callback) {
@@ -305,15 +301,12 @@ Syncer.prototype.syncFromServer = function() {
}
},
triggerNextSync = function() {
if(pollingEnabled) {
self.pollTimerId = setTimeout(function() {
self.pollTimerId = null;
self.syncFromServer.call(self);
},self.pollTimerInterval);
}
self.pollTimerId = setTimeout(function() {
self.pollTimerId = null;
self.syncFromServer.call(self);
},self.pollTimerInterval);
},
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes"),
pollingEnabled = (self.wiki.getTiddlerText(self.titleSyncDisablePolling) !== "yes");
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
this.logger.log("Retrieving updated tiddler list");
cancelNextSync();
@@ -336,7 +329,7 @@ Syncer.prototype.syncFromServer = function() {
});
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
self.processTaskQueue();
}
}
}
});
} else if(this.syncadaptor && this.syncadaptor.getSkinnyTiddlers) {
@@ -479,7 +472,7 @@ Syncer.prototype.handleLogoutEvent = function() {
if(this.syncadaptor.logout) {
this.syncadaptor.logout(function(err) {
if(err) {
self.logger.alert(err);
self.displayError("Logout Error",err);
} else {
self.getStatus();
}
@@ -516,7 +509,7 @@ Syncer.prototype.processTaskQueue = function() {
} else {
self.updateDirtyStatus();
// Process the next task
self.processTaskQueue.call(self);
self.processTaskQueue.call(self);
}
});
} else {
@@ -524,11 +517,11 @@ Syncer.prototype.processTaskQueue = function() {
this.updateDirtyStatus();
// And trigger a timeout if there is a pending task
if(task === true) {
this.triggerTimeout();
this.triggerTimeout();
}
}
} else {
this.updateDirtyStatus();
this.updateDirtyStatus();
}
};
@@ -562,7 +555,7 @@ Syncer.prototype.chooseNextTask = function() {
isReadyToSave = !tiddlerInfo || !tiddlerInfo.timestampLastSaved || tiddlerInfo.timestampLastSaved < thresholdLastSaved;
if(hasChanged) {
if(isReadyToSave) {
return new SaveTiddlerTask(this,title);
return new SaveTiddlerTask(this,title);
} else {
havePending = true;
}

View File

@@ -54,27 +54,15 @@ exports.getFieldList = function(field) {
/*
Get all the fields as a hashmap of strings. Options:
exclude: an array of field names to exclude
prefix: an optional field name prefix. Only fields with the prefix are included, and the prefix is stripped from the name
*/
exports.getFieldStrings = function(options) {
options = options || {};
var exclude = options.exclude || [],
fields = {},
field;
if(options.prefix) {
for(field in this.fields) {
if($tw.utils.hop(this.fields,field)) {
if(exclude.indexOf(field) === -1 && field.substring(0,options.prefix.length) === options.prefix) {
fields[field.substring(options.prefix.length)] = this.getFieldString(field);
}
}
}
} else {
for(field in this.fields) {
if($tw.utils.hop(this.fields,field)) {
if(exclude.indexOf(field) === -1) {
fields[field] = this.getFieldString(field);
}
var exclude = options.exclude || [];
var fields = {};
for(var field in this.fields) {
if($tw.utils.hop(this.fields,field)) {
if(exclude.indexOf(field) === -1) {
fields[field] = this.getFieldString(field);
}
}
}

View File

@@ -16,7 +16,7 @@ Browser data transfer utilities, used with the clipboard and drag and drop
Options:
domNode: dom node to make draggable
dragImageType: "pill" or "dom"
dragImageType: "pill", "blank" or "dom" (the default)
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
widget: widget to use as the contect for the filter
@@ -73,6 +73,9 @@ exports.makeDraggable = function(options) {
if(dataTransfer.setDragImage) {
if(dragImageType === "pill") {
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
} else if (dragImageType === "blank") {
dragImage.removeChild(dragImage.firstChild);
dataTransfer.setDragImage(dragImage,0,0);
} else {
var r = domNode.getBoundingClientRect();
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
@@ -164,7 +167,7 @@ var importDataTypes = [
}},
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
// Check for tiddler data URI
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
if(match) {
return parseJSONTiddlers(match[1],fallbackTitle);
} else {
@@ -173,7 +176,7 @@ var importDataTypes = [
}},
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
// Check for tiddler data URI
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
var match = $tw.utils.decodeURIComponentSafe(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
if(match) {
return parseJSONTiddlers(match[1],fallbackTitle);
} else {

View File

@@ -34,6 +34,23 @@ exports.httpRequest = function(options) {
});
return result;
},
getHeader = function(targetHeader) {
return headers[targetHeader] || headers[targetHeader.toLowerCase()];
},
isSimpleRequest = function(type,headers) {
if(["GET","HEAD","POST"].indexOf(type) === -1) {
return false;
}
for(var header in headers) {
if(["accept","accept-language","content-language","content-type"].indexOf(header.toLowerCase()) === -1) {
return false;
}
}
if(hasHeader("Content-Type") && ["application/x-www-form-urlencoded","multipart/form-data","text/plain"].indexOf(getHeader["Content-Type"]) === -1) {
return false;
}
return true;
},
returnProp = options.returnProp || "responseText",
request = new XMLHttpRequest(),
data = "",
@@ -76,7 +93,7 @@ exports.httpRequest = function(options) {
if(data && !hasHeader("Content-Type")) {
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
}
if(!hasHeader("X-Requested-With")) {
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
request.setRequestHeader("X-Requested-With","TiddlyWiki");
}
try {

View File

@@ -12,9 +12,8 @@ Modal message mechanism
/*global $tw: false */
"use strict";
var widget = require("$:/core/modules/widgets/widget.js"),
navigator = require("$:/core/modules/widgets/navigator.js"),
dm = $tw.utils.domMaker;
var widget = require("$:/core/modules/widgets/widget.js");
var navigator = require("$:/core/modules/widgets/navigator.js");
var Modal = function(wiki) {
this.wiki = wiki;
@@ -27,10 +26,6 @@ Display a modal dialogue
options: see below
Options include:
downloadLink: Text of a big download link to include
variables: variables to be passed to the modal
event: optional DOM event that initiated the modal
progress: set to true to add a progress bar
onclose: callback for when the modal is closed
*/
Modal.prototype.display = function(title,options) {
options = options || {};
@@ -52,6 +47,7 @@ Modal.prototype.display = function(title,options) {
"tv-story-list": (options.event && options.event.widget ? options.event.widget.getVariable("tv-story-list") : ""),
"tv-history-list": (options.event && options.event.widget ? options.event.widget.getVariable("tv-history-list") : "")
},options.variables);
// Create the wrapper divs
var wrapper = this.srcDocument.createElement("div"),
modalBackdrop = this.srcDocument.createElement("div"),
@@ -59,7 +55,6 @@ Modal.prototype.display = function(title,options) {
modalHeader = this.srcDocument.createElement("div"),
headerTitle = this.srcDocument.createElement("h3"),
modalBody = this.srcDocument.createElement("div"),
modalProgress = this.srcDocument.createElement("div"),
modalLink = this.srcDocument.createElement("a"),
modalFooter = this.srcDocument.createElement("div"),
modalFooterHelp = this.srcDocument.createElement("span"),
@@ -76,7 +71,6 @@ Modal.prototype.display = function(title,options) {
$tw.utils.addClass(modalWrapper,"tc-modal");
$tw.utils.addClass(modalHeader,"tc-modal-header");
$tw.utils.addClass(modalBody,"tc-modal-body");
$tw.utils.addClass(modalProgress,"tc-modal-progress");
$tw.utils.addClass(modalFooter,"tc-modal-footer");
// Join them together
wrapper.appendChild(modalBackdrop);
@@ -84,15 +78,6 @@ Modal.prototype.display = function(title,options) {
modalHeader.appendChild(headerTitle);
modalWrapper.appendChild(modalHeader);
modalWrapper.appendChild(modalBody);
if(options.progress) {
var modalProgressBar = this.srcDocument.createElement("div");
modalProgressBar.className = "tc-modal-progress-bar";
modalProgress.appendChild(modalProgressBar);
var modalProgressPercent = this.srcDocument.createElement("div");
modalProgressPercent.className = "tc-modal-progress-percent";
modalProgress.appendChild(modalProgressPercent);
modalWrapper.appendChild(modalProgress);
}
modalFooter.appendChild(modalFooterHelp);
modalFooter.appendChild(modalFooterButtons);
modalWrapper.appendChild(modalFooter);
@@ -120,6 +105,7 @@ Modal.prototype.display = function(title,options) {
parentWidget: $tw.rootWidget
});
navigatorWidgetNode.render(modalBody,null);
// Render the title of the message
var headerWidgetNode = this.wiki.makeTranscludeWidget(title,{
field: "subtitle",
@@ -196,10 +182,6 @@ Modal.prototype.display = function(title,options) {
this.wiki.addEventListener("change",refreshHandler);
// Add the close event handler
var closeHandler = function(event) {
// Call the onclose handler
if(options.onclose) {
options.onclose(event);
}
// Remove our refresh handler
self.wiki.removeEventListener("change",refreshHandler);
// Decrease the modal count and adjust the body class
@@ -254,22 +236,6 @@ Modal.prototype.display = function(title,options) {
$tw.utils.setStyle(modalWrapper,[
{transform: "translateY(0px)"}
]);
// Return the wrapper node
return {
domNode: wrapper,
closeHandler: closeHandler,
setProgress: function(numerator,denominator) {
// Remove old progress
while(modalProgressPercent.hasChildNodes()) {
modalProgressPercent.removeChild(modalProgressPercent.firstChild);
}
// Set new text
var percent = (numerator * 100 /denominator).toFixed(2) + "%";
modalProgressPercent.appendChild(self.srcDocument.createTextNode(percent));
// Set bar width
modalProgressBar.style.width = percent;
}
};
};
Modal.prototype.adjustPageClass = function() {

View File

@@ -235,7 +235,7 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
if(node instanceof TW_Element) {
b.push(node.outerHTML);
} else if(node instanceof TW_TextNode) {
b.push($tw.utils.htmlEncode(node.textContent));
b.push($tw.utils.htmlTextEncode(node.textContent));
}
});
return b.join("");

View File

@@ -95,6 +95,15 @@ LinkedList.prototype.toArray = function() {
return output;
};
LinkedList.prototype.makeTiddlerIterator = function(wiki) {
var self = this;
return function(callback) {
self.each(function(title) {
callback(wiki.getTiddler(title),title);
});
};
};
function _removeOne(list,value) {
var prevEntry = list.prev[value],
nextEntry = list.next[value],

View File

@@ -199,6 +199,8 @@ exports.transliterationPairs = {
"Nj":"N",
"Ñ":"N",
"NJ":"NJ",
"ð":"d",
"Ð":"D",
"Ó":"O",
"Ŏ":"O",
"Ǒ":"O",
@@ -265,6 +267,8 @@ exports.transliterationPairs = {
"Ɽ":"R",
"Ꜿ":"C",
"Ǝ":"E",
"ß":"ss",
"ẞ":"SS",
"Ś":"S",
"Ṥ":"S",
"Š":"S",
@@ -275,6 +279,8 @@ exports.transliterationPairs = {
"Ṡ":"S",
"Ṣ":"S",
"Ṩ":"S",
"þ": "th",
"Þ": "TH",
"Ť":"T",
"Ţ":"T",
"Ṱ":"T",
@@ -907,7 +913,8 @@ exports.transliterationPairs = {
"т":"t",
"ь":"'",
"б":"b",
"ю":"yu"
"ю":"yu",
"…":"..."
};
exports.transliterate = function(str) {

View File

@@ -383,6 +383,15 @@ exports.formatDateString = function(date,template) {
[/^0WW/, function() {
return $tw.utils.pad($tw.utils.getWeek(date));
}],
[/^0ddddd/, function() {
return $tw.utils.pad(Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24),3);
}],
[/^ddddd/, function() {
return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
}],
[/^dddd/, function() {
return [7,1,2,3,4,5,6][date.getDay()];
}],
[/^ddd/, function() {
return $tw.language.getString("Date/Short/Day/" + date.getDay());
}],

View File

@@ -59,7 +59,7 @@ Invoke the action associated with this widget
ConfirmWidget.prototype.invokeAction = function(triggeringWidget,event) {
var invokeActions = true,
handled = true,
win = event.event && event.event.view ? event.event.view : window;
win = event && event.event && event.event.view ? event.event.view : window;
if(this.prompt) {
invokeActions = win.confirm(this.message);
}

View File

@@ -39,6 +39,8 @@ SendMessageWidget.prototype.execute = function() {
this.actionParam = this.getAttribute("$param");
this.actionName = this.getAttribute("$name");
this.actionValue = this.getAttribute("$value","");
this.actionNames = this.getAttribute("$names");
this.actionValues = this.getAttribute("$values");
};
/*
@@ -59,13 +61,20 @@ Invoke the action associated with this widget
SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
// Get the string parameter
var param = this.actionParam;
// Assemble the attributes as a hashmap
// Assemble the parameters as a hashmap
var paramObject = Object.create(null);
var count = 0;
// Add names/values pairs if present
if(this.actionNames && this.actionValues) {
var names = this.wiki.filterTiddlers(this.actionNames,this),
values = this.wiki.filterTiddlers(this.actionValues,this);
$tw.utils.each(names,function(name,index) {
paramObject[name] = values[index] || "";
});
}
// Add raw parameters
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.charAt(0) !== "$") {
paramObject[name] = attribute;
count++;
}
});
// Add name/value pair if present
@@ -73,14 +82,15 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
paramObject[this.actionName] = this.actionValue;
}
// Dispatch the message
this.dispatchEvent({
var params = {
type: this.actionMessage,
param: param,
paramObject: paramObject,
event: event,
tiddlerTitle: this.getVariable("currentTiddler"),
navigateFromTitle: this.getVariable("storyTiddler"),
event: event
});
navigateFromTitle: this.getVariable("storyTiddler")
};
this.dispatchEvent(params);
return true; // Action was invoked
};

View File

@@ -0,0 +1,86 @@
/*\
title: $:/core/modules/widgets/action-setmultiplefields.js
type: application/javascript
module-type: widget
Action widget to set multiple fields or indexes on a tiddler
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var SetMultipleFieldsWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
SetMultipleFieldsWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
SetMultipleFieldsWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
};
/*
Compute the internal state of the widget
*/
SetMultipleFieldsWidget.prototype.execute = function() {
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
this.actionFields = this.getAttribute("$fields");
this.actionIndexes = this.getAttribute("$indexes");
this.actionValues = this.getAttribute("$values");
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
};
/*
Refresh the widget by ensuring our attributes are up to date
*/
SetMultipleFieldsWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes["$tiddler"] || changedAttributes["$fields"] || changedAttributes["$indexes"] || changedAttributes["$values"] || changedAttributes["$timestamp"]) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
/*
Invoke the action associated with this widget
*/
SetMultipleFieldsWidget.prototype.invokeAction = function(triggeringWidget,event) {
var tiddler = this.wiki.getTiddler(this.actionTiddler),
names, values = this.wiki.filterTiddlers(this.actionValues,this);
if(this.actionFields) {
var additions = {};
names = this.wiki.filterTiddlers(this.actionFields,this);
$tw.utils.each(names,function(fieldname,index) {
additions[fieldname] = values[index] || "";
});
var creationFields = this.actionTimestamp ? this.wiki.getCreationFields() : undefined,
modificationFields = this.actionTimestamp ? this.wiki.getModificationFields() : undefined;
this.wiki.addTiddler(new $tw.Tiddler(creationFields,tiddler,{title: this.actionTiddler},modificationFields,additions));
} else if(this.actionIndexes) {
var data = this.wiki.getTiddlerData(this.actionTiddler,Object.create(null));
names = this.wiki.filterTiddlers(this.actionIndexes,this);
$tw.utils.each(names,function(name,index) {
data[name] = values[index] || "";
});
this.wiki.setTiddlerData(this.actionTiddler,data,{},{suppressTimestamp: !this.actionTimestamp});
}
return true; // Action was invoked
};
exports["action-setmultiplefields"] = SetMultipleFieldsWidget;
})();

View File

@@ -52,7 +52,13 @@ CodeBlockWidget.prototype.execute = function() {
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
CodeBlockWidget.prototype.refresh = function(changedTiddlers) {
return false;
var changedAttributes = this.computeAttributes();
if(changedAttributes.code || changedAttributes.language) {
this.refreshSelf();
return true;
} else {
return false;
}
};
exports.codeblock = CodeBlockWidget;

View File

@@ -54,6 +54,7 @@ DraggableWidget.prototype.render = function(parent,nextSibling) {
dragFilterFn: function() {return self.getAttribute("filter");},
startActions: self.startActions,
endActions: self.endActions,
dragImageType: self.dragImageType,
widget: this
});
// Insert the link into the DOM and render any children
@@ -71,6 +72,7 @@ DraggableWidget.prototype.execute = function() {
this.draggableClasses = this.getAttribute("class");
this.startActions = this.getAttribute("startactions");
this.endActions = this.getAttribute("endactions");
this.dragImageType = this.getAttribute("dragimagetype");
// Make the child widgets
this.makeChildWidgets();
};

View File

@@ -76,16 +76,22 @@ EventWidget.prototype.render = function(parent,nextSibling) {
variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();
if(event.clientX && event.clientY) {
//Add variables for event X and Y position relative to selected node
selectedNodeRect = selectedNode.getBoundingClientRect();
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
//Add variables for event X and Y position relative to selected node
selectedNodeRect = selectedNode.getBoundingClientRect();
variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();
//Add variables for event X and Y position relative to event catcher node
catcherNodeRect = self.domNode.getBoundingClientRect();
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
//Add variables for event X and Y position relative to event catcher node
catcherNodeRect = self.domNode.getBoundingClientRect();
variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
//Add variables for event X and Y position relative to the viewport
variables["event-fromviewport-posx"] = event.clientX.toString();
variables["event-fromviewport-posy"] = event.clientY.toString();
}
}
} else {
return false;

View File

@@ -40,8 +40,10 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
var widgetPointer = this;
// Got to flush all the accumulated variables
this.variables = new this.variablesConstructor();
// Get our parameters
this.filter = this.getAttribute("filter");
// Compute the filter
this.tiddlerList = tiddlerList || this.getTiddlerList();
this.tiddlerList = tiddlerList || this.wiki.filterTiddlers(this.filter,this);
// Accumulate the <$set> widgets from each tiddler
$tw.utils.each(this.tiddlerList,function(title) {
var parser = widgetPointer.wiki.parseTiddler(title);
@@ -84,6 +86,7 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
}
}
});
if (widgetPointer != this) {
widgetPointer.parseTreeNode.children = this.parseTreeNode.children;
} else {
@@ -91,21 +94,13 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
}
};
ImportVariablesWidget.prototype.getTiddlerList = function() {
var filter = this.getAttribute("filter"),
title = this.getAttribute("tiddler");
return (filter && this.wiki.filterTiddlers(filter,this)) || (title && [title]) || [];
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ImportVariablesWidget.prototype.refresh = function(changedTiddlers) {
// Recompute our attributes and the filter list
var changedAttributes = this.computeAttributes(),
filter = this.getAttribute("filter"),
title = this.getAttribute("tiddler"),
tiddlerList = this.getTiddlerList();
tiddlerList = this.wiki.filterTiddlers(this.getAttribute("filter"),this);
// Refresh if the filter has changed, or the list of tiddlers has changed, or any of the tiddlers in the list has changed
function haveListedTiddlersChanged() {
var changed = false;
@@ -116,7 +111,7 @@ ImportVariablesWidget.prototype.refresh = function(changedTiddlers) {
});
return changed;
}
if(changedAttributes.filter || changedAttributes.tiddler || !$tw.utils.isArrayEqual(this.tiddlerList,tiddlerList) || haveListedTiddlersChanged()) {
if(changedAttributes.filter || !$tw.utils.isArrayEqual(this.tiddlerList,tiddlerList) || haveListedTiddlersChanged()) {
// Compute the filter
this.removeChildDomNodes();
this.execute(tiddlerList);

View File

@@ -32,13 +32,7 @@ JSONTiddlerWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
// Collect the fields from the optional base tiddler
var fields = {};
if(this.attTiddler) {
var tiddler = this.wiki.getTiddler(this.attTiddler);
if(tiddler) {
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
}
}
var fields = this.getTiddlerFields();
// Add custom fields specified in attributes starting with $
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.charAt(0) === "$") {
@@ -79,6 +73,19 @@ JSONTiddlerWidget.prototype.refresh = function(changedTiddlers) {
}
};
JSONTiddlerWidget.prototype.getTiddlerFields = function() {
var fields = {};
if(this.attTiddler) {
var tiddler = this.wiki.getTiddler(this.attTiddler);
if(tiddler) {
fields = tiddler.getFieldStrings({exclude: this.attExclude.split(" ")});
} else {
fields = {title: this.attTiddler};
}
}
return fields;
};
exports.jsontiddler = JSONTiddlerWidget;
})();

View File

@@ -0,0 +1,96 @@
/*\
title: $:/core/modules/widgets/let.js
type: application/javascript
module-type: widget
This widget allows defining multiple variables at once, while allowing
the later variables to depend upon the earlier ones.
```
\define helloworld() Hello world!
<$let currentTiddler="target" value={{!!value}} currentTiddler="different">
{{!!value}} will be different from <<value>>
</$let>
```
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var LetWidget = function(parseTreeNode,options) {
// Initialise
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
LetWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
LetWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
};
LetWidget.prototype.computeAttributes = function() {
// Before computing attributes, we must make clear that none of the
// existing attributes are staged for lookup, even on a refresh
var changedAttributes = {},
self = this;
this.currentValueFor = Object.create(null);
$tw.utils.each(this.parseTreeNode.orderedAttributes,function(attribute,index) {
var value = self.computeAttribute(attribute),
name = attribute.name;
if(name.charAt(0) !== "$") {
// Now that it's prepped, we're allowed to look this variable up
// when defining later variables
self.currentValueFor[name] = value;
}
});
// Run through again, setting variables and looking for differences
$tw.utils.each(this.currentValueFor,function(value,name) {
if (self.attributes[name] !== value) {
self.attributes[name] = value;
self.setVariable(name,value);
changedAttributes[name] = true;
}
});
return changedAttributes;
};
LetWidget.prototype.getVariableInfo = function(name,options) {
// Special handling: If this variable exists in this very $let, we can
// use it, but only if it's been staged.
if ($tw.utils.hop(this.currentValueFor,name)) {
return {
text: this.currentValueFor[name]
};
}
return Widget.prototype.getVariableInfo.call(this,name,options);
};
/*
Refresh the widget by ensuring our attributes are up to date
*/
LetWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if($tw.utils.count(changedAttributes) > 0) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
exports["let"] = LetWidget;
})();

View File

@@ -98,7 +98,6 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$";
wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",encodeURIComponent(this.to));
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$title_slugify$",this.wiki.slugify(this.to));
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
}
// Override with the value of tv-get-export-link if defined
@@ -208,7 +207,8 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
LinkWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip) {
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes["aria-label"] || changedAttributes.tooltip ||
changedAttributes["class"] || changedAttributes.tabindex || changedAttributes.draggable || changedAttributes.tag) {
this.refreshSelf();
return true;
}

View File

@@ -236,6 +236,11 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
hasRefreshed = hasRefreshed || refreshed;
}
}
// If there are items to remove and we have not refreshed then recreate the item that will now be at the last position
if(!hasRefreshed && this.children.length > this.list.length) {
this.removeListItem(this.list.length-1);
this.insertListItem(this.list.length-1,this.list[this.list.length-1]);
}
} else {
// Cycle through the list, inserting and removing list items as needed
for(t=0; t<this.list.length; t++) {

View File

@@ -36,28 +36,38 @@ MessageCatcherWidget.prototype.render = function(parent,nextSibling) {
// Helper to add an event handler
var addEventHandler = function(type,actions) {
if(type && actions) {
var isActionStringExecuting = false;
self.addEventListener(
type,
function(event) {
// Don't trap the event if it came from one of our action handlers
if(isActionStringExecuting) {
return true;
}
// Collect all the event properties into variables
var collectProps = function(obj,prefix) {
prefix = prefix || "";
var props = {};
var props = {},
names = [];
$tw.utils.each(obj,function(value,name) {
if(["string","boolean","number"].indexOf(typeof value) !== -1) {
props[prefix + name] = value.toString();
names.push(name);
props[prefix + "-" + name] = value.toString();
}
});
props["list-" + prefix] = $tw.utils.stringifyList(names);
return props;
};
var variables = $tw.utils.extend(
{},
collectProps(event.paramObject,"event-paramObject-"),
collectProps(event,"event-"),
collectProps(event.paramObject,"event-paramObject"),
collectProps(event,"event"),
{
modifier: $tw.keyboardManager.getEventModifierKeyDescriptor(event)
});
isActionStringExecuting = true;
self.invokeActionString(actions,self,event,variables);
isActionStringExecuting = false;
return false;
}
);

View File

@@ -122,6 +122,7 @@ RadioWidget.prototype.refresh = function(changedTiddlers) {
return true;
} else if(changedTiddlers[this.radioTitle]) {
this.inputDomNode.checked = this.getValue() === this.radioValue;
$tw.utils.toggleClass(this.labelDomNode,"tc-radio-selected",this.inputDomNode.checked);
return this.refreshChildren(changedTiddlers);
} else {
return this.refreshChildren(changedTiddlers);

View File

@@ -226,7 +226,7 @@ RevealWidget.prototype.refresh = function(changedTiddlers) {
this.refreshSelf();
return true;
}
} else if(this.type === "popup" && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
} else if(this.type === "popup" && this.isOpen && this.updatePopupPosition && (changedTiddlers[this.state] || changedTiddlers[this.stateTitle])) {
this.positionPopup(this.domNode);
}
if(changedAttributes.style) {

View File

@@ -0,0 +1,81 @@
/*\
title: $:/core/modules/widgets/setmultiplevariables.js
type: application/javascript
module-type: widget
Widget to set multiple variables at once from a list of names and a list of values
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var SetMultipleVariablesWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
SetMultipleVariablesWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
SetMultipleVariablesWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
};
/*
Compute the internal state of the widget
*/
SetMultipleVariablesWidget.prototype.execute = function() {
// Setup our variables
this.setVariables();
// Construct the child widgets
this.makeChildWidgets();
};
SetMultipleVariablesWidget.prototype.setVariables = function() {
// Set the variables
var self = this,
filterNames = this.getAttribute("$names",""),
filterValues = this.getAttribute("$values","");
this.variableNames = [];
this.variableValues = [];
if(filterNames && filterValues) {
this.variableNames = this.wiki.filterTiddlers(filterNames,this);
this.variableValues = this.wiki.filterTiddlers(filterValues,this);
$tw.utils.each(this.variableNames,function(varname,index) {
self.setVariable(varname,self.variableValues[index]);
});
}
};
/*
Refresh the widget by ensuring our attributes are up to date
*/
SetMultipleVariablesWidget.prototype.refresh = function(changedTiddlers) {
var filterNames = this.getAttribute("$names",""),
filterValues = this.getAttribute("$values",""),
variableNames = this.wiki.filterTiddlers(filterNames,this),
variableValues = this.wiki.filterTiddlers(filterValues,this);
if(!$tw.utils.isArrayEqual(this.variableNames,variableNames) || !$tw.utils.isArrayEqual(this.variableValues,variableValues)) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
exports["setmultiplevariables"] = SetMultipleVariablesWidget;
})();

View File

@@ -29,14 +29,12 @@ var VarsWidget = function(parseTreeNode,options) {
/*
Inherit from the base widget class
*/
VarsWidget.prototype = Object.create(Widget.prototype);
VarsWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
VarsWidget.prototype.render = function(parent,nextSibling) {
// Call the constructor
Widget.call(this);
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
@@ -63,7 +61,7 @@ Refresh the widget by ensuring our attributes are up to date
*/
VarsWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(Object.keys(changedAttributes).length) {
if($tw.utils.count(changedAttributes) > 0) {
this.refreshSelf();
return true;
}

View File

@@ -263,19 +263,9 @@ Compute the current values of the attributes of the widget. Returns a hashmap of
*/
Widget.prototype.computeAttributes = function() {
var changedAttributes = {},
self = this,
value;
self = this;
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
if(attribute.type === "filtered") {
value = self.wiki.filterTiddlers(attribute.filter,self)[0] || "";
} else if(attribute.type === "indirect") {
value = self.wiki.getTextReference(attribute.textReference,"",self.getVariable("currentTiddler"));
} else if(attribute.type === "macro") {
value = self.getVariable(attribute.value.name,{params: attribute.value.params});
} else { // String attribute
value = attribute.value;
}
// Check whether the attribute has changed
var value = self.computeAttribute(attribute);
if(self.attributes[name] !== value) {
self.attributes[name] = value;
changedAttributes[name] = true;
@@ -284,6 +274,20 @@ Widget.prototype.computeAttributes = function() {
return changedAttributes;
};
Widget.prototype.computeAttribute = function(attribute) {
var value;
if(attribute.type === "filtered") {
value = this.wiki.filterTiddlers(attribute.filter,this)[0] || "";
} else if(attribute.type === "indirect") {
value = this.wiki.getTextReference(attribute.textReference,"",this.getVariable("currentTiddler"));
} else if(attribute.type === "macro") {
value = this.getVariable(attribute.value.name,{params: attribute.value.params});
} else { // String attribute
value = attribute.value;
}
return value;
};
/*
Check for the presence of an attribute
*/
@@ -570,7 +574,7 @@ Widget.prototype.invokeActions = function(triggeringWidget,event) {
for(var t=0; t<this.children.length; t++) {
var child = this.children[t],
childIsActionWidget = !!child.invokeAction,
actionRefreshPolicy = child.getVariable("tv-action-refresh-policy");
actionRefreshPolicy = child.getVariable("tv-action-refresh-policy"); // Default is "once"
// Refresh the child if required
if(childIsActionWidget || actionRefreshPolicy === "always") {
child.refreshSelf();

View File

@@ -81,7 +81,7 @@ exports.setText = function(title,field,index,value,options) {
} else {
delete data[index];
}
this.setTiddlerData(title,data,modificationFields);
this.setTiddlerData(title,data,{},{suppressTimestamp: options.suppressTimestamp});
} else {
var tiddler = this.getTiddler(title),
fields = {title: title};
@@ -365,47 +365,108 @@ Sort an array of tiddler titles by a specified field
*/
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric) {
var self = this;
titles.sort(function(a,b) {
var x,y,
compareNumbers = function(x,y) {
var result =
isNaN(x) && !isNaN(y) ? (isDescending ? -1 : 1) :
!isNaN(x) && isNaN(y) ? (isDescending ? 1 : -1) :
(isDescending ? y - x : x - y);
return result;
};
if(sortField !== "title") {
var tiddlerA = self.getTiddler(a),
tiddlerB = self.getTiddler(b);
if(tiddlerA) {
a = tiddlerA.getFieldString(sortField) || "";
if(sortField === "title") {
if(!isNumeric && !isAlphaNumeric) {
if(isCaseSensitive) {
if(isDescending) {
titles.sort(function(a,b) {
return b.localeCompare(a);
});
} else {
titles.sort(function(a,b) {
return a.localeCompare(b);
});
}
} else {
a = "";
if(isDescending) {
titles.sort(function(a,b) {
return b.toLowerCase().localeCompare(a.toLowerCase());
});
} else {
titles.sort(function(a,b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
}
}
if(tiddlerB) {
b = tiddlerB.getFieldString(sortField) || "";
} else {
b = "";
}
}
x = Number(a);
y = Number(b);
if(isNumeric && (!isNaN(x) || !isNaN(y))) {
return compareNumbers(x,y);
} else if($tw.utils.isDate(a) && $tw.utils.isDate(b)) {
return isDescending ? b - a : a - b;
} else if(isAlphaNumeric) {
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
} else {
titles.sort(function(a,b) {
var x,y;
if(isNumeric) {
x = Number(a);
y = Number(b);
if(isNaN(x)) {
if(isNaN(y)) {
// If neither value is a number then fall through to a textual comparison
} else {
return isDescending ? -1 : 1;
}
} else {
if(isNaN(y)) {
return isDescending ? 1 : -1;
} else {
return isDescending ? y - x : x - y;
}
}
}
if(isAlphaNumeric) {
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
}
if(!isCaseSensitive) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
});
}
} else {
titles.sort(function(a,b) {
var x,y;
if(sortField !== "title") {
var tiddlerA = self.getTiddler(a),
tiddlerB = self.getTiddler(b);
if(tiddlerA) {
a = tiddlerA.fields[sortField] || "";
} else {
a = "";
}
if(tiddlerB) {
b = tiddlerB.fields[sortField] || "";
} else {
b = "";
}
}
if(isNumeric) {
x = Number(a);
y = Number(b);
if(isNaN(x)) {
if(isNaN(y)) {
// If neither value is a number then fall through to a textual comparison
} else {
return isDescending ? -1 : 1;
}
} else {
if(isNaN(y)) {
return isDescending ? 1 : -1;
} else {
return isDescending ? y - x : x - y;
}
}
}
if(Object.prototype.toString.call(a) === "[object Date]" && Object.prototype.toString.call(b) === "[object Date]") {
return isDescending ? b - a : a - b;
}
a = String(a);
b = String(b);
if(isAlphaNumeric) {
return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
}
if(!isCaseSensitive) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
}
});
});
}
};
/*
@@ -795,19 +856,24 @@ Set a tiddlers content to a JavaScript object. Currently this is done by setting
title: title of tiddler
data: object that can be serialised to JSON
fields: optional hashmap of additional tiddler fields to be set
options: optional hashmap of options including:
suppressTimestamp: if true, don't set the creation/modification timestamps
*/
exports.setTiddlerData = function(title,data,fields) {
exports.setTiddlerData = function(title,data,fields,options) {
options = options || {};
var existingTiddler = this.getTiddler(title),
creationFields = options.suppressTimestamp ? {} : this.getCreationFields(),
modificationFields = options.suppressTimestamp ? {} : this.getModificationFields(),
newFields = {
title: title
};
};
if(existingTiddler && existingTiddler.fields.type === "application/x-tiddler-dictionary") {
newFields.text = $tw.utils.makeTiddlerDictionary(data);
} else {
newFields.type = "application/json";
newFields.text = JSON.stringify(data,null,$tw.config.preferences.jsonSpaces);
}
this.addTiddler(new $tw.Tiddler(this.getCreationFields(),existingTiddler,fields,newFields,this.getModificationFields()));
this.addTiddler(new $tw.Tiddler(creationFields,existingTiddler,fields,newFields,modificationFields));
};
/*
@@ -844,7 +910,7 @@ exports.clearGlobalCache = function() {
exports.getCacheForTiddler = function(title,cacheName,initializer) {
this.caches = this.caches || Object.create(null);
var caches = this.caches[title];
if(caches && caches[cacheName]) {
if(caches && caches[cacheName] !== undefined) {
return caches[cacheName];
} else {
if(!caches) {
@@ -1575,23 +1641,4 @@ exports.slugify = function(title,options) {
return slug;
};
/*
Return an array of the titles that would generate a specified slug, if any. Options include:
*/
exports.unslugify = function(slug) {
var self = this,
slugToTitle = this.getGlobalCache("slugs",function() {
var map = {};
$tw.utils.each($tw.wiki.allTitles(),function(title) {
var slug = self.slugify(title);
if(!(slug in map)) {
map[slug] = [];
}
map[slug].push(title);
});
return map;
});
return slugToTitle[slug];
};
})();

View File

@@ -19,71 +19,73 @@ $:/config/Plugins/Disabled/$(currentTiddler)$
\end
\define plugin-table-body(type,disabledMessage,default-popup-state)
\whitespace trim
<div class="tc-plugin-info-chunk tc-plugin-info-toggle">
<$reveal type="nomatch" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="yes">
{{$:/core/images/chevron-right}}
</$button>
</$reveal>
<$reveal type="match" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="no">
{{$:/core/images/chevron-down}}
</$button>
</$reveal>
<$reveal type="nomatch" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="yes">
{{$:/core/images/chevron-right}}
</$button>
</$reveal>
<$reveal type="match" state=<<popup-state>> text="yes" default="""$default-popup-state$""">
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<popup-state>> setTo="no">
{{$:/core/images/chevron-down}}
</$button>
</$reveal>
</div>
<div class="tc-plugin-info-chunk tc-plugin-info-icon">
<$transclude tiddler=<<currentTiddler>> subtiddler=<<plugin-icon-title>>>
<$transclude tiddler="$:/core/images/plugin-generic-$type$"/>
</$transclude>
<$transclude tiddler=<<currentTiddler>> subtiddler=<<plugin-icon-title>>>
<$transclude tiddler="$:/core/images/plugin-generic-$type$"/>
</$transclude>
</div>
<div class="tc-plugin-info-chunk tc-plugin-info-description">
<h1>
''<$text text={{{ [<currentTiddler>get[name]] ~[<currentTiddler>split[/]last[1]] }}}/>'': <$view field="description"><$view field="title"/></$view> $disabledMessage$
</h1>
<h2>
<$view field="title"/>
</h2>
<h2>
<div><em><$view field="version"/></em></div>
</h2>
<h1>
''<$text text={{{ [<currentTiddler>get[name]] ~[<currentTiddler>split[/]last[1]] }}}/>'':&nbsp;<$view field="description"><$view field="title"/></$view>&nbsp;$disabledMessage$
</h1>
<h2>
<$view field="title"/>
</h2>
<h2>
<div><em><$view field="version"/></em></div>
</h2>
</div>
\end
\define plugin-info(type,default-popup-state)
\whitespace trim
<$set name="popup-state" value=<<popup-state-macro>>>
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
<$link to={{!!title}} class="tc-plugin-info">
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""">>
</$link>
</$reveal>
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
<$link to={{!!title}} class="tc-plugin-info tc-plugin-info-disabled">
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""" disabledMessage:"<$macrocall $name='lingo' title='Disabled/Status'/>">>
</$link>
</$reveal>
<$reveal type="match" text="yes" state=<<popup-state>> default="""$default-popup-state$""">
<div class="tc-plugin-info-dropdown">
<div class="tc-plugin-info-dropdown-body">
<$list filter="[all[current]] -[[$:/core]]">
<div style="float:right;">
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
<$button set=<<plugin-disable-title>> setTo="yes" tooltip={{$:/language/ControlPanel/Plugins/Disable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Disable/Caption}}>
<<lingo Disable/Caption>>
</$button>
</$reveal>
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
<$button set=<<plugin-disable-title>> setTo="no" tooltip={{$:/language/ControlPanel/Plugins/Enable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Enable/Caption}}>
<<lingo Enable/Caption>>
</$button>
</$reveal>
</div>
</$list>
<$set name="tabsList" filter="[<currentTiddler>list[]] contents">
<$macrocall $name="tabs" state=<<tabs-state-macro>> tabsList=<<tabsList>> default={{{ [enlist<tabsList>] }}} template="$:/core/ui/PluginInfo"/>
</$set>
</div>
</div>
</$reveal>
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
<$link to={{!!title}} class="tc-plugin-info">
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""">>
</$link>
</$reveal>
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
<$link to={{!!title}} class="tc-plugin-info tc-plugin-info-disabled">
<<plugin-table-body type:"$type$" default-popup-state:"""$default-popup-state$""" disabledMessage:"<$macrocall $name='lingo' title='Disabled/Status'/>">>
</$link>
</$reveal>
<$reveal type="match" text="yes" state=<<popup-state>> default="""$default-popup-state$""">
<div class="tc-plugin-info-dropdown">
<div class="tc-plugin-info-dropdown-body">
<$list filter="[all[current]] -[[$:/core]]">
<div style="float:right;">
<$reveal type="nomatch" state=<<plugin-disable-title>> text="yes">
<$button set=<<plugin-disable-title>> setTo="yes" tooltip={{$:/language/ControlPanel/Plugins/Disable/Hint}} aria-label={{$:/language/ControlPanel/Plugins/Disable/Caption}}>
<<lingo Disable/Caption>>
</$button>
</$reveal>
<$reveal type="match" state=<<plugin-disable-title>> text="yes">
<$button set=<<plugin-disable-title>> setTo="no" tooltip={{$:/language/ControlPanel/Plugins/Enable Hint}} aria-label={{$:/language/ControlPanel/Plugins/Enable/Caption}}>
<<lingo Enable/Caption>>
</$button>
</$reveal>
</div>
</$list>
<$set name="tabsList" filter="[<currentTiddler>list[]] contents">
<$macrocall $name="tabs" state=<<tabs-state-macro>> tabsList=<<tabsList>> default={{{ [enlist<tabsList>] }}} template="$:/core/ui/PluginInfo"/>
</$set>
</div>
</div>
</$reveal>
</$set>
\end

View File

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

View File

@@ -0,0 +1,9 @@
title: $:/core/ui/ControlPanel/EditTemplateBody
tags: $:/tags/ControlPanel/Cascade
caption: {{$:/language/ControlPanel/EditTemplateBody/Caption}}
\define lingo-base() $:/language/ControlPanel/EditTemplateBody/
<<lingo Hint>>
{{$:/tags/EditTemplateBodyFilter||$:/snippets/ListTaggedCascade}}

View File

@@ -0,0 +1,9 @@
title: $:/core/ui/ControlPanel/StoryTiddler
tags: $:/tags/ControlPanel/Cascades
caption: {{$:/language/ControlPanel/StoryTiddler/Caption}}
\define lingo-base() $:/language/ControlPanel/StoryTiddler/
<<lingo Hint>>
{{$:/tags/StoryTiddlerTemplateFilter||$:/snippets/ListTaggedCascade}}

View File

@@ -0,0 +1,9 @@
title: $:/core/ui/ControlPanel/TiddlerIcon
tags: $:/tags/ControlPanel/Cascades
caption: {{$:/language/ControlPanel/TiddlerIcon/Caption}}
\define lingo-base() $:/language/ControlPanel/TiddlerIcon/
<<lingo Hint>>
{{$:/tags/TiddlerIconFilter||$:/snippets/ListTaggedCascade}}

View File

@@ -0,0 +1,9 @@
title: $:/core/ui/ControlPanel/ViewTemplateBody
tags: $:/tags/ControlPanel/Cascades
caption: {{$:/language/ControlPanel/ViewTemplateBody/Caption}}
\define lingo-base() $:/language/ControlPanel/ViewTemplateBody/
<<lingo Hint>>
{{$:/tags/ViewTemplateBodyFilter||$:/snippets/ListTaggedCascade}}

View File

@@ -0,0 +1,9 @@
title: $:/core/ui/ControlPanel/ViewTemplateTitle
tags: $:/tags/ControlPanel/Cascades
caption: {{$:/language/ControlPanel/ViewTemplateTitle/Caption}}
\define lingo-base() $:/language/ControlPanel/ViewTemplateTitle/
<<lingo Hint>>
{{$:/tags/ViewTemplateTitleFilter||$:/snippets/ListTaggedCascade}}

View File

@@ -16,4 +16,4 @@ caption: {{$:/language/ControlPanel/Plugins/Caption}}
<<lingo Installed/Hint>>
<$macrocall $name="tabs" tabsList="[[$:/core/ui/ControlPanel/Plugins/Installed/Plugins]] [[$:/core/ui/ControlPanel/Plugins/Installed/Themes]] [[$:/core/ui/ControlPanel/Plugins/Installed/Languages]]" default="$:/core/ui/ControlPanel/Plugins/Installed/Plugins" explicitState="$:/state/tab--86143343"/>
<$macrocall $name="tabs" tabsList="[all[tiddlers+shadows]tag[$:/tags/ControlPanel/Plugins]!has[draft.of]]" default="$:/core/ui/ControlPanel/Plugins/Installed/Plugins" explicitState="$:/state/tab--86143343"/>

View File

@@ -1,4 +1,5 @@
title: $:/core/ui/ControlPanel/Plugins/Installed/Languages
tags: $:/tags/ControlPanel/Plugins
caption: {{$:/language/ControlPanel/Plugins/Languages/Caption}} (<$count filter="[!has[draft.of]plugin-type[language]]"/>)
<<plugin-table language>>

View File

@@ -1,4 +1,5 @@
title: $:/core/ui/ControlPanel/Plugins/Installed/Plugins
tags: $:/tags/ControlPanel/Plugins
caption: {{$:/language/ControlPanel/Plugins/Plugins/Caption}} (<$count filter="[!has[draft.of]plugin-type[plugin]]"/>)
<<plugin-table plugin>>

View File

@@ -1,4 +1,5 @@
title: $:/core/ui/ControlPanel/Plugins/Installed/Themes
tags: $:/tags/ControlPanel/Plugins
caption: {{$:/language/ControlPanel/Plugins/Themes/Caption}} (<$count filter="[!has[draft.of]plugin-type[theme]]"/>)
<<plugin-table theme>>

View File

@@ -1,81 +0,0 @@
title: $:/core/ui/ControlPanel/Publishing
tags: $:/tags/ControlPanel
caption: {{$:/language/ControlPanel/Publishing/Caption}}
{{$:/language/ControlPanel/Publishing/Hint}}
<div class="tc-publishing-job-listing">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/PublishingJob]]" variable="job">
<div class="tc-publishing-job">
<h2>Job: <$link to=<<job>>><$transclude tiddler=<<job>> field="caption" mode="inline"/></$link></h2>
Publisher: <$select tiddler=<<job>> field="publisher">
<$list filter="[[publisher]modules[]moduleproperty[name]]">
<option value=<<currentTiddler>>><$text text=<<currentTiddler>>/></option>
</$list>
</$select>
Base URL: <$edit-text tiddler=<<job>> size="50" field="baseurl"/>
Logs: <$view tiddler=<<job>> field="list"/>
<$set name="publisher-name" value={{{ [<job>get[publisher]] }}}>
<$set name="publisher-module" value={{{ [[publisher]modules[name],<publisher-name>] }}}>
<div class="tc-publishing-job-publisher">
<h2>Publisher: <$text text=<<publisher-name>>/></h2>
<$set name="publisher-ui" value={{{ [<publisher-module>modulestring[ui],{$:/language}] }}}>
<$tiddler tiddler=<<job>>>
<<publisher-ui>>
</$tiddler>
</$set>
</div>
<$vars sitemap={{{ [<job>get[sitemap]] }}}>
<div class="tc-publishing-sitemap">
<h2>Sitemap: <$link to=<<sitemap>>><$view tiddler=<<sitemap>> field="caption"><$text text=<<sitemap>>/></$view></$link></h2>
<$list filter="[<sitemap>get[list]enlist-input[]]" variable="route">
<div class="tc-publishing-route">
<h2>Route: <$link to=<<route>>><$view tiddler=<<route>> field="caption"><$text text=<<route>>/></$view></$link></h2>
route type: <$view tiddler=<<route>> field="route-type"/>
path: <$edit-text tiddler=<<route>> size="50" field="route-path"/>
filter: <$edit-text tiddler=<<route>> size="50" field="route-tiddler-filter"/>
template: <$edit-text tiddler=<<route>> size="50" field="route-template"/>
</div>
</$list>
</div>
</$vars>
</$set>
</$set>
</div>
</$list>
</div>

View File

@@ -1,54 +1,4 @@
title: $:/core/ui/EditTemplate/body
tags: $:/tags/EditTemplate
\define lingo-base() $:/language/EditTemplate/Body/
\define config-visibility-title()
$:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
\end
\define importFileActions()
<$action-popup $state=<<importState>> $coords="(0,0,0,0)" $floating="yes"/>
\end
<$list filter="[all[current]has[_canonical_uri]]">
<div class="tc-message-box">
<<lingo External/Hint>>
<a href={{!!_canonical_uri}}><$text text={{!!_canonical_uri}}/></a>
<$edit-text field="_canonical_uri" class="tc-edit-fields" tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"></$edit-text>
</div>
</$list>
<$list filter="[all[current]!has[_canonical_uri]]">
<$vars importTitle=<<qualify $:/ImportImage>> importState=<<qualify $:/state/ImportImage>> >
<$dropzone importTitle=<<importTitle>> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<<importFileActions>> ><$reveal state="$:/state/showeditpreview" type="match" text="yes">
<div class="tc-tiddler-preview">
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
<div class="tc-tiddler-preview-preview">
<$transclude tiddler={{$:/state/editpreviewtype}} mode="inline">
<$transclude tiddler="$:/core/ui/EditTemplate/body/preview/output" mode="inline"/>
</$transclude>
</div>
</div>
</$reveal>
<$reveal state="$:/state/showeditpreview" type="nomatch" text="yes">
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
</$reveal>
</$dropzone>
</$vars>
</$list>
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/EditTemplateBodyFilter]get[text]] :and[!is[blank]else[$:/core/ui/EditTemplate/body/default]] }}} />

View File

@@ -0,0 +1,13 @@
title: $:/core/ui/EditTemplate/body/canonical-uri
\define lingo-base() $:/language/EditTemplate/Body/
<div class="tc-message-box">
<<lingo External/Hint>>
<a href={{!!_canonical_uri}}><$text text={{!!_canonical_uri}}/></a>
<$edit-text field="_canonical_uri" class="tc-edit-fields" tabindex={{$:/config/EditTabIndex}} cancelPopups="yes"></$edit-text>
</div>

View File

@@ -0,0 +1,38 @@
title: $:/core/ui/EditTemplate/body/default
\define config-visibility-title()
$:/config/EditorToolbarButtons/Visibility/$(currentTiddler)$
\end
\define importFileActions()
<$action-popup $state=<<importState>> $coords="(0,0,0,0)" $floating="yes"/>
\end
<$set name="edit-preview-state" value={{{ [{$:/config/ShowEditPreview/PerTiddler}!match[yes]then[$:/state/showeditpreview]] :else[<qualify "$:/state/showeditpreview">] }}}>
<$vars importTitle=<<qualify $:/ImportImage>> importState=<<qualify $:/state/ImportImage>> >
<$dropzone importTitle=<<importTitle>> autoOpenOnImport="no" contentTypesFilter={{$:/config/Editor/ImportContentTypesFilter}} class="tc-dropzone-editor" enable={{{ [{$:/config/DragAndDrop/Enable}match[no]] :else[subfilter{$:/config/Editor/EnableImportFilter}then[yes]else[no]] }}} filesOnly="yes" actions=<<importFileActions>> ><$reveal stateTitle=<<edit-preview-state>> type="match" text="yes">
<div class="tc-tiddler-preview">
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
<div class="tc-tiddler-preview-preview">
<$transclude tiddler={{$:/state/editpreviewtype}} mode="inline">
<$transclude tiddler="$:/core/ui/EditTemplate/body/preview/output" mode="inline"/>
</$transclude>
</div>
</div>
</$reveal>
<$reveal stateTitle=<<edit-preview-state>> type="nomatch" text="yes">
<$transclude tiddler="$:/core/ui/EditTemplate/body/editor" mode="inline"/>
</$reveal>
</$dropzone>
</$vars>
</$set>

View File

@@ -13,7 +13,7 @@ title: $:/core/ui/EditorToolbar/link-dropdown
<$set name="userInput" value={{{ [<storeTitle>get[text]] }}}><$list filter="[<searchTiddler>get[text]!match<userInput>]" emptyMessage="""<$action-deletetiddler $filter="[<searchTiddler>] [<linkTiddler>] [<storeTitle>] [<searchListState>]"/>"""><$action-setfield $tiddler=<<searchTiddler>> text=<<userInput>>/><$action-setfield $tiddler=<<refreshTitle>> text="yes"/></$list></$set>
\end
\define cancel-search-actions() <$list filter="[<storeTitle>!has[text]] +[<searchTiddler>!has[text]]" emptyMessage="""<<cancel-search-actions-inner>>"""><$action-sendmessage $message="tm-edit-text-operation" $param="wrap-selection" prefix="" suffix=""/></$list>
\define cancel-search-actions() <$list filter="[<storeTitle>!has[text]] +[<searchTiddler>!has[text]]" emptyMessage="""<<cancel-search-actions-inner>>"""><$action-sendmessage $message="tm-edit-text-operation" $param="focus-editor"/></$list>
\define external-link()
<$button class="tc-btn-invisible" style="width: auto; display: inline-block; background-colour: inherit;" actions=<<add-link-actions>>>

View File

@@ -8,11 +8,11 @@ condition: [<targetTiddler>]
button-classes: tc-text-editor-toolbar-item-start-group
shortcuts: ((preview))
<$reveal state="$:/state/showeditpreview" type="match" text="yes" tag="span">
<$reveal state=<<edit-preview-state>> type="match" text="yes" tag="span">
{{$:/core/images/preview-open}}
<$action-setfield $tiddler="$:/state/showeditpreview" $value="no"/>
<$action-setfield $tiddler=<<edit-preview-state>> $value="no"/>
</$reveal>
<$reveal state="$:/state/showeditpreview" type="nomatch" text="yes" tag="span">
<$reveal state=<<edit-preview-state>> type="nomatch" text="yes" tag="span">
{{$:/core/images/preview-closed}}
<$action-setfield $tiddler="$:/state/showeditpreview" $value="yes"/>
<$action-setfield $tiddler=<<edit-preview-state>> $value="yes"/>
</$reveal>

View File

@@ -0,0 +1,53 @@
title: $:/core/ui/EditorToolbar/StampDropdown/ItemTemplate
<$linkcatcher actions="""
<$list filter="[<modifier>!match[ctrl]]" variable="ignore">
<$list filter="[<currentTiddler>addsuffix[/prefix]!is[tiddler]!is[shadow]removesuffix[/prefix]addsuffix[/suffix]!is[tiddler]!is[shadow]]" variable="ignore">
<$action-sendmessage
$message="tm-edit-text-operation"
$param="replace-selection"
text={{{ [<currentTiddler>get[text]] }}}
/>
</$list>
<$list filter="[<currentTiddler>addsuffix[/prefix]] [<currentTiddler>addsuffix[/suffix]] +[is[shadow]] :else[is[tiddler]] +[limit[1]]" variable="ignore">
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-selection"
prefix={{{ [<currentTiddler>addsuffix[/prefix]get[text]] }}}
suffix={{{ [<currentTiddler>addsuffix[/suffix]get[text]] }}}
/>
</$list>
</$list>
<$list filter="[<modifier>match[ctrl]]" variable="ignore">
<$action-sendmessage $message="tm-edit-tiddler"/>
</$list>
<$action-deletetiddler
$tiddler=<<dropdown-state>>
/>
""">
<$link tooltip={{{ [<currentTiddler>get[description]] }}}>
<$transclude tiddler=<<currentTiddler>> field="caption" mode="inline">
<$view tiddler=<<currentTiddler>> field="title" />
</$transclude>
</$link>
</$linkcatcher>

View File

@@ -1,48 +1,6 @@
title: $:/core/ui/EditorToolbar/stamp-dropdown
\define toolbar-button-stamp-inner()
<$button tag="a">
<$list filter="[[$(snippetTitle)$]addsuffix[/prefix]is[missing]removesuffix[/prefix]addsuffix[/suffix]is[missing]]">
<$action-sendmessage
$message="tm-edit-text-operation"
$param="replace-selection"
text={{$(snippetTitle)$}}
/>
</$list>
<$list filter="[[$(snippetTitle)$]addsuffix[/prefix]is[missing]removesuffix[/prefix]addsuffix[/suffix]!is[missing]] [[$(snippetTitle)$]addsuffix[/prefix]!is[missing]removesuffix[/prefix]addsuffix[/suffix]is[missing]] [[$(snippetTitle)$]addsuffix[/prefix]!is[missing]removesuffix[/prefix]addsuffix[/suffix]!is[missing]]">
<$action-sendmessage
$message="tm-edit-text-operation"
$param="wrap-selection"
prefix={{{ [[$(snippetTitle)$]addsuffix[/prefix]get[text]] }}}
suffix={{{ [[$(snippetTitle)$]addsuffix[/suffix]get[text]] }}}
/>
</$list>
<$action-deletetiddler
$tiddler=<<dropdown-state>>
/>
<$transclude tiddler=<<snippetTitle>> field="caption" mode="inline">
<$view tiddler=<<snippetTitle>> field="title" />
</$transclude>
</$button>
\end
<$list filter="[all[shadows+tiddlers]tag[$:/tags/TextEditor/Snippet]!has[draft.of]sort[caption]]" variable="snippetTitle">
<<toolbar-button-stamp-inner>>
</$list>
<$macrocall $name="list-tagged-draggable" tag="$:/tags/TextEditor/Snippet" subFilter="!is[draft]" itemTemplate="$:/core/ui/EditorToolbar/StampDropdown/ItemTemplate"/>
----

View File

@@ -6,4 +6,5 @@ description: {{$:/language/Buttons/Stamp/Hint}}
condition: [<targetTiddler>type[]] [<targetTiddler>get[type]prefix[text/]] [<targetTiddler>get[type]match[application/javascript]] [<targetTiddler>get[type]match[application/json]] [<targetTiddler>get[type]match[application/x-tiddler-dictionary]] [<targetTiddler>get[type]match[image/svg+xml]] +[first[]]
shortcuts: ((stamp))
dropdown: $:/core/ui/EditorToolbar/stamp-dropdown
button-classes: tc-editortoolbar-stamp-button
text:

View File

@@ -0,0 +1,22 @@
title: $:/core/ui/ExportTiddlyWikiCore
\define jsFileName() tiddlywikicore-$(version)$.js
\define noExportMsg()
It appears that you have a wiki with an external ~TiddlyWiki core. The export action cannot be performed.
<p>You will need to view the page source in your browser. Then go to the very bottom the the source, find the last `<script>`
element, and right-click its `src` URI. Save the link as ''$(jsFileName)$''</p>
\end
''For advanced users''
Export the ~TiddlyWiki core ~JavaScript code for running with external ~JavaScript:
<$button tooltip="Export the ~TiddlyWiki core code for running with external ~JavaScript" aria-label="export TiddlyWiki core" class="tc-btn-big-green">
<$list filter="[[$:/boot/boot.js]is[missing]]" variable="ignore" emptyMessage="""<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/tiddlywiki5.js" filename=<<jsFileName>>/>""" >
<$action-setfield $tiddler=<<qualify "$:/temp/alert">> text=<<noExportMsg>> subtitle="Export ~TiddllyWiki Core"/>
<$action-sendmessage $message="tm-modal" $param=<<qualify "$:/temp/alert">>/>
</$list>
{{$:/core/images/download-button}} Download ~TiddlyWiki core
</$button>
[[Further information|https://tiddlywiki.com/#Using%20the%20external%20JavaScript%20template]]

View File

@@ -0,0 +1,14 @@
title: $:/snippets/ListTaggedCascade
{{||$:/language/ControlPanel/Cascades/TagPrompt}}
<ol>
<$list filter="[all[shadows+tiddlers]tag<currentTiddler>]">
<li>
<div>
<$link><$text text=<<currentTiddler>>/></$link>
</div>
<$codeblock code={{!!text}}/>
</li>
</$list>
</ol>

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