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

Compare commits

...

295 Commits

Author SHA1 Message Date
Jermolene
8756d25d78 Version number update for 5.0.10-beta 2014-04-19 14:07:48 +01:00
Jermolene
8a27c2759b Update 5.0.10 release date 2014-04-19 14:06:29 +01:00
Jermolene
beddcd7138 New ribbon colour for 5.0.10 2014-04-19 13:15:24 +01:00
Jermolene
2db90378a2 Release note updates for 5.0.10 2014-04-19 11:34:23 +01:00
Jermolene
7684891285 Move topbar out of the way of scrollbars
In the process getting rid of some extraneous `<p>` tags.

Fixes #566
2014-04-19 11:32:56 +01:00
Jermolene
821f1f1428 Fix hamburger and seamless behaviour
No longer remove the tiddler borders when hiding the sidebar; users can
select Seamless theme to get the same effect.

Fixes #566
2014-04-19 11:24:41 +01:00
Jermolene
4538f081ee Release note updates for 5.0.10 2014-04-19 11:22:59 +01:00
Jermolene
b4122be50c Update release note for 5.0.10 2014-04-19 11:18:08 +01:00
Jermolene
cd76514105 Update roadmap 2014-04-19 09:36:14 +01:00
Jermolene
ba576d9f1b Add support for safe mode 2014-04-19 09:36:08 +01:00
Jermolene
15d0c27e2a Add [is[tag]] filter operator 2014-04-18 17:57:55 +01:00
Jermolene
869cec1ccc Add docs for date format strings 2014-04-18 17:37:13 +01:00
Jermolene
d6054f1039 Fix problem with offline copy of server edition
We were accidentally including all the shadow tiddlers as well as
ordinary ones.
2014-04-18 15:23:00 +01:00
Jermolene
9fbe72a877 Rearrange system tag configuration
By rearranging the `[all[]]` operator we are able to ensure that shadow
tiddlers get processed before ordinary tiddlers. This makes it easier
to create custom stylesheets that override the core.
2014-04-18 09:28:14 +01:00
Jermolene
89165fc51d Fix problem with sorting date fields
Introduced a couple of commits ago when the localeCompare() stuff was
added.
2014-04-17 22:52:57 +01:00
Jermolene
4758874d13 Add path conversions from TiddlyWiki Classic
TiddlyWiki Classic converts local file URIs to various local native
formats. The same conversions are now performed by the TiddlyFox
adaptor for TW5.
2014-04-17 22:30:14 +01:00
Jermolene
0153fd2a30 Correct typos in 5.0.9 release note 2014-04-17 20:26:35 +01:00
Jermolene
bb42c0ab36 Use localCompare for sorting strings
So that accented characters get sorted correctly. Or at least as
correctly as browsers allow.
2014-04-17 20:15:52 +01:00
Jermolene
95d291daac Update print stylesheet to hide topbar 2014-04-17 19:50:12 +01:00
Jermolene
45b0966013 Support the image widget in markdown 2014-04-17 16:50:54 +01:00
Jermolene
de07da3797 Revise warning about backing up before upgrading 2014-04-17 16:26:57 +01:00
Jeremy Ruston
aebc1ea943 Merge pull request #562 from pmario/upgrade-backup-info
add a backup info for the Upgrade tiddler.
2014-04-17 16:24:57 +01:00
Jermolene
73cfd10218 Fix regression with untagged filter operator
Restored previous behaviour of considering a missing tiddler to be
untagged.
2014-04-17 16:10:50 +01:00
Jermolene
d336ffea02 Fix incorrect background colour for sidebar tag pills
Fixes #568.
2014-04-17 15:11:59 +01:00
Jermolene
6da28e7365 Docs update 2014-04-17 14:44:14 +01:00
Jermolene
d08a2d109f Fix html parser tests 2014-04-17 14:43:24 +01:00
Jermolene
f57e047877 Fix issues with tiddlers with null fields
Fixing #567
2014-04-17 14:43:12 +01:00
Jermolene
df5fe10a40 Start release note for 5.0.10 2014-04-17 12:52:52 +01:00
Jermolene
433ac8e96e Typo fix 2014-04-17 12:52:38 +01:00
Jermolene
ad4b03506a Added wikitext image support
We’ve added a parser to recognise the `[img[URL or tiddler title]]`
format, and an associated image widget.
2014-04-17 12:52:32 +01:00
Jermolene
ace57dd205 Refactor utilities out of HTML parser
Some of the functions are useful general purpose parser helpers.
2014-04-17 12:00:32 +01:00
Jermolene
bd4a031df8 Fix problem with version checking logic
Previously, importing a plugin with a semantically identical version
number was not rejected. This meant that attempts to import
5.0.9-prerelease wikis into 5.0.9-beta led to a corrupted wiki, with a
beta core and prerelease plugins.
2014-04-17 11:59:42 +01:00
Jermolene
6db94052c7 Prepare for 5.0.10 release 2014-04-17 11:58:16 +01:00
Mario Pietsch
dd8797223a add a backup info for the Upgrade tiddler. 2014-04-16 01:09:26 +02:00
Jermolene
e54b0d7129 Docs fixes 2014-04-15 21:50:36 +01:00
Jermolene
07ab8c75b8 Docs fixes 2014-04-15 21:48:19 +01:00
Jermolene
0a6077286f Version number update for 5.0.9-beta 2014-04-15 21:43:51 +01:00
Jermolene
634e76eb7f Update release date for 5.0.9 2014-04-15 21:39:46 +01:00
Jermolene
cd1463cbb0 Get rid of the home button
I’m not keen on it because it ends up being very visually prominent for
something that’s not particularly useful.
2014-04-15 20:33:58 +01:00
Jermolene
4b8be85b88 Docs updates 2014-04-15 13:24:43 +01:00
Jermolene
d01f1020d2 Release note updates 2014-04-15 09:07:25 +01:00
Jermolene
f77de37a2f Include Japanese translation in tiddlywiki.com
All of which is making index.html far too big, which we’ll address with
a plugin library.
2014-04-15 09:07:19 +01:00
Jeremy Ruston
f3c5ce7ca4 Merge pull request #558 from pekopeko1/japanese
Translation to Japanese.
2014-04-15 08:34:12 +01:00
Jermolene
6ed38389b0 Update test for previous commit
Test should have been updated with
dad60cda05
2014-04-15 08:28:47 +01:00
pekopeko1
5393fbee99 signed in CLA 2014-04-15 12:14:34 +09:00
pekopeko1
3b31c6fe3a some translation added 2014-04-15 12:00:04 +09:00
pekopeko1
9ba55c7e79 GettingStarted.tid plugin.info 2014-04-15 09:59:30 +09:00
pekopeko1
9323574efb add ja-JP directory 2014-04-15 09:58:21 +09:00
Jermolene
f5cf8cba5c Docs update 2014-04-14 21:33:16 +01:00
Jermolene
88be791e58 Fix full screen background 2014-04-14 21:30:42 +01:00
Jermolene
dad60cda05 Improve wiki.sortByList()
Previously list-before and list-after didn’t work if they referenced
entries that hadn’t yet been placed
2014-04-14 21:30:30 +01:00
Jermolene
fe0ed5e4ce Tweaks to themes
And shaking out some paragraph tags in the sidebar
2014-04-14 18:37:09 +01:00
Jermolene
aa243e4478 Add new seamless theme
Gets rid of the borders around tiddlers, and tightens up the use of
white space. Works particularly well with the sidebar hidden.
2014-04-14 13:12:44 +01:00
Jermolene
4c648e7cdc Exclude more illegal characters from external links 2014-04-14 11:17:28 +01:00
Jermolene
0aa559cd23 Improve responsiveness during editting
Simple optimisation whereby we defer the main refresh cycle when only
draft tiddlers have been modified.

We defer for 400ms, and keep extending the delay at each fresh draft
modification. The effect is that if the user is using the preview then
they’ll need to pause typing for 400ms before the preview is updated.

Fixes #470, #454, and maybe #206.
2014-04-14 10:20:32 +01:00
Jermolene
28db76ddb3 Refactor page rendering into a separate function
Refactoring page rendering so that we can fix the performance issues
with editing drafts. The plan is to defer the refresh cycle if all the
changes are to draft tiddlers.

We need to do a bit more of this to get startup.js into better shape
(and more extensible).
2014-04-14 09:53:13 +01:00
Jermolene
e366aa3746 Use Date.now() instead of new Date()
Just for when what we actually want is a millisecond counter.

Interesting video about this:

https://www.youtube.com/watch?v=Vo72W1HWeFI
2014-04-14 09:02:52 +01:00
Jermolene
22a529b28d New ribbon colour for 5.0.9 2014-04-14 08:57:50 +01:00
Jermolene
c2d6086bd9 Show fewer tiddlers in recent changes 2014-04-13 21:17:44 +01:00
Jermolene
f1578d3409 Turn off instrumentation
All those console.log()s make editing very slow
2014-04-13 21:17:44 +01:00
Jermolene
93b9d16d6c Don't include pipe characters in URLs 2014-04-13 21:17:44 +01:00
Jeremy Ruston
13bb20cad4 Merge pull request #553 from xcazin/fr-FR
fr-FR translation of the confirmation string before cancelling tiddler changes
2014-04-13 21:03:42 +01:00
Xavier Cazin
bba7e97f60 fr-FR translation of the confirmation string before cancelling tiddler changes 2014-04-13 16:55:13 +02:00
Xavier Cazin
cb32d187c5 Merge remote-tracking branch 'upstream/master' 2014-04-13 16:45:30 +02:00
Jeremy Ruston
8582e5ebe2 Merge pull request #552 from BramChen/master
Add chinese translations of confirmation for cancelling edits
2014-04-13 09:24:45 +01:00
Jermolene
46969fbd3e Adjust Cecily tiddler width 2014-04-13 09:24:06 +01:00
Jermolene
260d3ad8c0 Docs typo 2014-04-13 09:23:57 +01:00
Bram Chen
d9b87055bf Add chinese translations of confirmation for cancelling edits 2014-04-13 14:34:17 +08:00
Jermolene
4f4b743d9c Fix Cecily tiddler width for when sidebar hidden 2014-04-12 18:24:39 +01:00
Jermolene
ee2cd2056c Make tiddler width fluid when sidebar hidden 2014-04-12 17:14:27 +01:00
Jermolene
be5f6f6700 Allow spaces in property names in text references 2014-04-12 17:14:09 +01:00
Jermolene
be7822281a Release note updates 2014-04-12 16:32:58 +01:00
Jermolene
3afa26b9a3 Require confirmation before abandoning edits
Fixes #544
2014-04-12 14:15:49 +01:00
Xavier Cazin
2a2cc20601 Merge remote-tracking branch 'upstream/master' 2014-04-12 10:22:07 +02:00
Jeremy Ruston
400ab3b3c5 Merge pull request #550 from xcazin/fr-FR
3 new plugin-related strings in fr-FR Control Panel
2014-04-12 08:44:42 +01:00
Xavier Cazin
ebe7587aa0 Merge remote-tracking branch 'upstream/master' into fr-FR 2014-04-12 08:48:00 +02:00
Xavier Cazin
c954ac01fe Merge remote-tracking branch 'upstream/master' 2014-04-12 08:46:18 +02:00
Jermolene
a3cf925e56 Add classes for the current theme and language
Add the classes to the tw-page-container DIV
2014-04-11 21:37:58 +01:00
Xavier Cazin
be7c33dc48 Revert "Another missed update"
This reverts commit 7aaab03e03.
2014-04-11 16:23:23 +02:00
Xavier Cazin
634f914610 Another missed update 2014-04-11 16:15:56 +02:00
Xavier Cazin
7aaab03e03 Another missed update 2014-04-11 16:13:32 +02:00
Xavier Cazin
fd1399f6d9 3 new plugin-related strings in fr-FR Control Panel 2014-04-11 09:48:32 +02:00
Jermolene
442bc35bcb Remove dropdown from edit mode tags
Firefox didn’t like the nested buttons.

The better fix would be to switch the tag pills to being links instead
of buttons.

Fixes #515
2014-04-10 22:49:46 +01:00
Jermolene
1bc9bf541a Remove headings from Tiddler Info advanced tab
Fixes #518
2014-04-10 21:44:56 +01:00
Jermolene
ccf2cb36a1 Extend sameday operator to select field
Now the target field can be specified in the suffix:
`[sameday:created[20140808]]`
2014-04-10 20:19:12 +01:00
Jeremy Ruston
18d14031b7 Merge pull request #548 from xcazin/fr-FR
Four file updates on fr-FR translations
2014-04-10 20:08:26 +01:00
Jermolene
5fff6fc87f Docs update 2014-04-10 19:57:21 +01:00
Jermolene
5a65898dbe Update tiddler filter docs 2014-04-10 19:56:51 +01:00
Jermolene
cbf45a9982 Update release note 2014-04-10 19:56:43 +01:00
Jermolene
7a4a00f6ca Sort operator should default to title
Previously we were crashing if a sort field wasn’t specified
2014-04-10 19:56:21 +01:00
Xavier Cazin
dfb367c104 Last fr-FR updates to translatable content 2014-04-10 15:46:00 +02:00
Xavier Cazin
7853b7f7b3 Four file updates on fr-FR translations 2014-04-10 12:38:55 +02:00
Jermolene
ccefc1b17b Tolerate more whitespace in block elements
Previously the double newlines marking a block mode element couldn’t be
interspersed with whitespace.
2014-04-10 11:05:27 +01:00
Jeremy Ruston
6786a1fd14 Merge pull request #547 from BramChen/master
Fix typo in PaletteColours.multids for zh-Hant
2014-04-10 08:29:32 +01:00
Bram Chen
e73d2854f9 Fix typo in PaletteColours.multids for zh-Hant 2014-04-10 09:34:48 +08:00
Jeremy Ruston
127cd70769 Merge pull request #545 from xcazin/fr-FR
fr-FR translation of PaletteColours.multids + typo in core en-GB of the same
2014-04-09 22:20:40 +01:00
Jermolene
fc407d079c Pixel accuracy for restoring pre-refactor layout
Two problems:

* Extraneous whitespace shows up as whitespace in the HTML, making it
hard to style
* Fix some padding
2014-04-09 22:19:27 +01:00
Jermolene
df6fe8f852 Merge branch 'sidebar-remove-p' of https://github.com/pmario/TiddlyWiki5 into pmario-sidebar-remove-p 2014-04-09 21:56:20 +01:00
Jermolene
613f413942 Add docs on filter changes in 5.0.9 2014-04-09 21:53:34 +01:00
Mario Pietsch
70a2db34d1 these changes remove most of the <p> tags from the right sidebar, without changing the layout too much. The tab buttons are a little bit higher but this will be adjusted with the next CSS tweaks. 2014-04-09 21:12:10 +02:00
Mario Pietsch
5821165ec5 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 2014-04-09 19:59:39 +02:00
Xavier Cazin
4888417a35 fr-FR translation of PaletteColours.multids + typo in core en-GB version. 2014-04-09 19:11:41 +02:00
Jeremy Ruston
2aa1acb565 Merge pull request #526 from BramChen/master
Keep up-to-date changes for chinese translations.
2014-04-09 16:11:39 +01:00
Jermolene
e5fe3f76ac Fix linkcatcher message sending
We need to send messages to the parent so that we don’t set up an
infinite loop by sending `tw-navigate` messages. Also we need to pass
along the target of the navigation.
2014-04-09 16:09:12 +01:00
Jermolene
ef03e5ce63 Docs update 2014-04-09 14:33:55 +01:00
Jermolene
690c8fe9a0 Update macros docs
Include single line macros
2014-04-09 14:33:47 +01:00
Jermolene
6f1e8ee3a1 Missed adjustments of wikitext tests
The commit 4d91a7762e broke the test
2014-04-09 11:54:03 +01:00
Jeremy Ruston
9b52ca7cc0 Merge pull request #543 from welford/load-and-deserialize
Make deserializing a bit more robust
2014-04-09 11:51:16 +01:00
Jermolene
f9a274df85 Require confirmation for all tiddler deletions
Previously we only asked for confirmation when deleting a draft tiddler
2014-04-09 11:32:08 +01:00
Jermolene
776bf29afc Update LinkCatcherWidget docs 2014-04-09 11:31:36 +01:00
Jermolene
f08c4aa525 Arrange fields alphabetically in the edit template 2014-04-09 11:31:27 +01:00
James Welford Anderson
0f07977930 deserializertype -> deserializerType 2014-04-09 06:26:01 +09:00
James Welford Anderson
362df18a19 make deserializing a bit more robust
load.js references the encoding set in boot.js when loading a file.
boot.js can now register file type with different deserialization from
their actual type
2014-04-09 06:20:51 +09:00
Jermolene
426281539a Merge branch 'saner-filters' 2014-04-08 14:14:11 +01:00
Jermolene
dc5831a8a8 First pass at a release note for 5.0.9 2014-04-08 14:12:35 +01:00
Jermolene
6d43b4e8dc Update link widget docs 2014-04-08 14:12:27 +01:00
Jermolene
3282bd948f Fix problem with search filter operator 2014-04-08 09:36:30 +01:00
Jermolene
7ec356ac80 Add @welford's signature to CLA 2014-04-08 09:16:22 +01:00
Jeremy Ruston
688879e6fa Merge pull request #540 from mwfogleman/michael-cla
Add Michael Fogleman to cla-individual.md.
2014-04-08 08:55:39 +01:00
Michael Fogleman
9bdd7a4e19 Add Michael Fogleman to cla-individual.md. 2014-04-08 11:24:38 +05:30
Jermolene
78f81a6894 Move notifications a little to the left
So that they don’t overlap the menu hamburger
2014-04-07 19:01:08 +01:00
Jermolene
5ec0775d3e Link wikitext help text to tiddlywiki.com
Fixes #537
2014-04-07 18:08:11 +01:00
Jermolene
c4d0ee11d3 Update Emacs tip 2014-04-07 09:02:31 +01:00
Jermolene
597b8ca4b1 Ensure fieldnames are not wikified
`__proto__` was being wikified into underlined text
2014-04-06 22:49:59 +01:00
Jermolene
ea46f85a8a Fix problem with fields called "__proto__" 2014-04-06 22:49:20 +01:00
Jermolene
1e960ffcac Fix problems with tiddlers called __proto__
Background:

http://www.2ality.com/2012/01/objects-as-maps.html
2014-04-06 22:43:10 +01:00
Jermolene
8a7d0f53d3 Add a sourceURL to the end of eval'd code
This, miraculously, lets Chrome dev tools list tiddler modules in the
script tag by their proper titles. Which lets you set breakpoints
within them!!!!!

https://chromedevtools.googlecode.com/svn-history/r421/trunk/tutorials/b
reapoints/index.html#regular
2014-04-06 22:36:51 +01:00
Jermolene
b51d851f93 Fix extraneous comma
Thanks to Danielo Rodríguez
2014-04-06 22:09:42 +01:00
Jermolene
e21d558ff0 Add Michael Fogleman's Emacs macro 2014-04-06 22:08:29 +01:00
Jermolene
c7b4febae3 Optimise ordering of filter expressions
We get a significant speed improvement of >10% by rearranging filter
operators to bring to the front the operators likely to reduce the size
working list.
2014-04-06 11:50:16 +01:00
Jermolene
4d91a7762e Optimise link widget
Handle the classes better, and stop using a default tooltip (parsing
the tooltip was a performance hog)
2014-04-05 17:37:58 +01:00
Jermolene
272a4bbe61 Filtering optimisations 2014-04-05 17:31:36 +01:00
Jermolene
b7f674c51a First pass at refactoring filter execution
This is the beginning of addressing #523.
2014-04-03 20:49:16 +01:00
Jermolene
14f90b9519 Include direct tiddler link in template for community links 2014-04-03 20:30:31 +01:00
Jermolene
2f458e8573 Add link to Martin Kantor's MathJax plugin 2014-04-03 20:25:40 +01:00
Jermolene
3619eb1378 Fix missing newline
Fixes #529
2014-04-03 18:10:54 +01:00
Mario Pietsch
9bd626315e Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 2014-04-03 19:03:51 +02:00
Jeremy Ruston
d3c0296a87 Merge pull request #520 from pmario/decouple-sitetitle
right menue SiteTitle and SiteSubtitle decoupled
2014-04-03 17:02:22 +01:00
Jermolene
e397e4d159 Disable the tiddlyweb adaptor unless loaded over http(s) 2014-04-03 16:33:42 +01:00
Jermolene
93c29bd388 Fix missing require in filesystem adator 2014-04-03 15:40:30 +01:00
Bram Chen
7985a808bf Keep up-to-date changes for chinese translations. 2014-04-02 16:27:03 +08:00
Mario Pietsch
aced860d52 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 2014-04-01 23:20:59 +02:00
Jeremy Ruston
c1bb7b00c1 Merge pull request #522 from pmario/de-DE
german language update. Contains changes till Mar 31, 2014
2014-04-01 15:24:06 +01:00
Mario Pietsch
856b68a34d german language update. Contains changes till Mar 31, 2014 2014-04-01 15:43:08 +02:00
Mario Pietsch
1940bd4dce right menue SiteTitle and SiteSubtitle decoupled from tiddler title and tiddler subtitle. Otherwise it is not possible to modify the tiddler title styling, without affecting the site title. 2014-04-01 10:34:58 +02:00
Jermolene
d402d3c5a6 Add performance measurement features
This is an experimental module to help us measure the performance of
the refresh cycle and the filter mechanism. Not intended to replace the
performance measurement features in browser developer tools, just to
make it easier to automate performance checks cross-browser.

The immediate purpose is to help in refactoring the filter mechanism.
The recent change to encapsulate the wiki store “tiddlers” object has
hurt the performance of filters, and it’s going to be helpful to have
decent measurements while refactoring that code.

I’m still not convinced that this stuff should be in the core, and may
well end up removing it after the present refactoring cycle.
2014-04-01 08:33:36 +01:00
Jermolene
dcce487934 Add support for platform dependent high resolution performance timers
For profiling filter performance
2014-03-31 18:42:30 +01:00
Jermolene
53ca7f6a2f More defensive handling of pluginInfo 2014-03-31 18:30:45 +01:00
Jermolene
c3e24c1228 Trim spaces from new field and tag names
Fixes #517
2014-03-31 17:59:28 +01:00
Jermolene
6307293469 Fix some Node.js cross-platform compatibility issues
Thanks to http://shapeshed.com/writing-cross-platform-node/

Surprising that file path format is pretty much the only issue.
2014-03-31 17:17:36 +01:00
Jeremy Ruston
0d0679de1b Merge pull request #514 from Skeeve/patch-6
Show site title when logging in
2014-03-31 12:59:15 +01:00
Jermolene
09214d1c33 Fix problem with --load command overwriting $:/core
Now we use the `wiki.importTiddler()` method - it rejects attempts to
load older versions of loaded plugins
2014-03-31 12:46:10 +01:00
Jermolene
914a536d82 Correct relative date handling of t=1s
We were incorrectly displaying “1 seconds ago”
2014-03-31 12:41:54 +01:00
Jermolene
5a085f7927 Add basic CSV parser 2014-03-31 12:41:02 +01:00
Skeeve
0595619d39 Show site title when logging in
I have several TW5 servers running on the same host and think it would be good, would the password prompt display the $:/SiteTitle
2014-03-31 08:58:13 +02:00
Jermolene
776c9a2cad Add James Anderson's resource links 2014-03-27 09:56:33 +00:00
Jeremy Ruston
36dabd792e Merge pull request #509 from BramChen/master
Update chinese translations of types
2014-03-27 09:55:31 +00:00
Jermolene
ec90ac99cf Skinner dropdown arrow 2014-03-27 08:54:28 +00:00
Bram Chen
299007f08b Update chinese translations of types. 2014-03-27 10:06:40 +08:00
Bram Chen
49578bb144 Merge remote-tracking branch 'upstream/master' 2014-03-27 09:33:36 +08:00
Jeremy Ruston
ead5e607fa Merge pull request #502 from BramChen/master
Add chinese translations of translatable core strings in JavaScript modules
2014-03-26 22:15:01 +00:00
Jermolene
5c3c6cd7c0 Fix various typos 2014-03-26 21:57:13 +00:00
Jeremy Ruston
818b29386e Merge pull request #504 from buggyj/58texthtml
added missing text/html type
2014-03-26 21:49:45 +00:00
Bram Chen
c0f78df48d Merge remote-tracking branch 'upstream/master' 2014-03-27 00:53:15 +08:00
Jermolene
c58852a67b On narrow screens ensure there is a background behind the home and menu buttons 2014-03-26 14:11:26 +00:00
Jermolene
bca1d55280 Add validation of legal characters for fieldnames 2014-03-26 13:38:43 +00:00
Jermolene
45a362c285 Add a dropdown to tags in edit mode
As discussed in TW Hangout 40
2014-03-26 13:06:11 +00:00
Jermolene
355f467465 Update line colour for SVG curved text example 2014-03-26 10:16:15 +00:00
Jermolene
871630be88 Fix the menu hamburger 2014-03-26 10:16:00 +00:00
Jermolene
8b813ccb43 Correct typo 2014-03-25 22:17:31 +00:00
Jermolene
59ac38a3da Remove the scrollable from the story river
The problem was that the scrollable required that the mouse be over the
story river itself in order to scroll it with the wheel. If we fallback
to scrolling the story by scrolling the browser body then we are able
to scroll even if the mouse is over the sidebar.
2014-03-25 22:15:54 +00:00
Jermolene
80b65b1651 Add a top-left and top-right menu 2014-03-25 21:54:06 +00:00
Jermolene
7dede861e1 Fix styling for input boxes in sidebar 2014-03-25 21:53:18 +00:00
Jermolene
514b8e1776 Fix hover colour of the close buttons in the sidebar "open" tab 2014-03-25 14:37:55 +00:00
Jermolene
79d643775d Fix scrollable widget not to crash on the server 2014-03-25 14:37:33 +00:00
Jermolene
945ad6792f Add first pass at Cecily plugin 2014-03-25 14:29:32 +00:00
Jermolene
7c235566c4 Rejig the page layout to use the scrollable widget
This is the start of some refactoring of the main layout CSS intended
to give us more flexibility and control.
2014-03-25 14:29:16 +00:00
Jermolene
d3e178becc Add scrollable widget
A new widget to handle scrollable areas. We’ll use it both for the
story river and the sidebar.
2014-03-25 14:26:54 +00:00
Jermolene
bc432d5e52 Remove obsolete nighttime theme
Better to do change the background colour with a palette
2014-03-25 09:31:48 +00:00
Jermolene
fa10801d72 Fix tags for curved text howto 2014-03-24 22:53:11 +00:00
Jermolene
87c8478c80 Add curved text demo 2014-03-24 22:49:10 +00:00
Jermolene
535837e017 Use client bounding rect rather than offset positions for computing scroll positions 2014-03-24 22:31:03 +00:00
Jermolene
20f6383528 Add storyviews list filter and use it in view switcher 2014-03-24 22:17:45 +00:00
Jermolene
26fd460670 Move the version banner to the sidebar
By making it a page control we move it into the sidebar, making it easy
to control with the sidebar.
2014-03-24 21:37:42 +00:00
Jermolene
20d7264e4b Add protocol to YouTube URLs
Otherwise they don’t work when viewed from a file URI
2014-03-24 21:36:19 +00:00
Jermolene
3ce2159a95 Missing semicolon 2014-03-24 21:35:48 +00:00
buggyj
968d44e4be added missing text/html type 2014-03-24 11:31:28 +05:30
Bram Chen
f46d445ba2 Add chinese translations of PaletteColours 2014-03-24 10:34:36 +08:00
Bram Chen
1b0a39cd1a Add chinese translations of translatable core strings in JavaScript modules 2014-03-24 10:25:54 +08:00
Jeremy Ruston
cb2653aee0 Merge pull request #499 from mpollio/master
Italian translation available
2014-03-23 13:49:31 +00:00
Jermolene
34445dcc68 Break the links up into separate tiddlers 2014-03-22 17:32:28 +00:00
Maurizio
54abcdceeb Update cla-individual.md 2014-03-21 17:22:12 +01:00
Maurizio
cf7554a938 Delete favicon.ico 2014-03-21 11:03:24 +01:00
Maurizio
fb72b3b859 Delete index.html 2014-03-21 11:03:16 +01:00
Jeremy Ruston
03cfa61ae8 Merge pull request #494 from nameanyone/master
Stop using obsoleted "-moz-border-radius" and "-webkit-border-radius" pr...
2014-03-20 22:19:45 +00:00
Jeremy Ruston
4badabce4b Merge pull request #496 from buggyj/syncer
syncer freeze fix
2014-03-20 20:58:50 +00:00
Jeremy Ruston
3cb2b365c5 Merge pull request #498 from buggyj/plugindocumentation
Plugin development with github
2014-03-20 20:56:30 +00:00
Jermolene
178cfb1084 Make more core strings be translateable
Now we’re translating strings that occur in JavaScript modules.

Partially fixing #491
2014-03-20 20:55:59 +00:00
mpollio
920df5d2d4 Italian translation available
Add italian translation
2014-03-20 13:40:40 +01:00
buggyj
7b57561160 plugin development doc 2014-03-20 13:28:17 +05:30
buggyj
d2a41b8486 plugin development with github and node.js 2014-03-20 13:20:52 +05:30
buggyj
aa63151815 syncer freeze fix 2014-03-19 20:20:54 +05:30
Jermolene
ba6edd42c1 Explicitly blacklist unsafe elements, starting with <script>
Are there are any other elements that might be considered unsafe?
2014-03-19 10:05:44 +00:00
nameanyone
7616c4ce7d Stop using obsoleted "-moz-border-radius" and "-webkit-border-radius" properties
Fixes #480
2014-03-18 16:38:52 -07:00
Jermolene
925b3d2a5b Fix typo 2014-03-18 21:18:46 +00:00
Jermolene
b8d0fd059b Fix bug with plugintiddlers filter operator 2014-03-18 21:18:45 +00:00
Jermolene
a19432541e New architecture diagram and docs updates 2014-03-18 21:18:45 +00:00
Jeremy Ruston
b52299872a Merge pull request #493 from BramChen/master
Add chinese translations of ClassicWarning section for TWC tiddlers
2014-03-18 08:45:56 +00:00
Bram Chen
699b863588 Add chinese translations of ClassicWarning section for TWC tiddlers 2014-03-18 09:53:29 +08:00
Jermolene
bdbbf94326 Update transclusion wikitext syntax to allow a template without a target tiddler
This allows us to transclude a tiddler without changing the current
tiddler with `{{||MyTiddler}}`.
2014-03-17 21:44:10 +00:00
Jermolene
cdf3e101a8 Fix crash with headings
`this.match[1].length` can get overwritten when we parse the content of
the heading
2014-03-17 20:55:08 +00:00
Jermolene
06500e5f71 New error message text for recursive transclusion error 2014-03-17 11:54:41 +00:00
Jermolene
9de17aa206 Make shadowTiddlers, pluginTiddlers and pluginInfo be private to the Wiki object constructor 2014-03-17 10:50:18 +00:00
Jermolene
279626a3e3 Freeze array or object tiddler fields
Previously object fields like the tags array weren’t frozen.
2014-03-17 08:58:42 +00:00
Jermolene
721e333a20 Starting to make the members of $tw.Wiki be private
We want to avoid plugins from directly accessing the tiddlers hashmap.
Later we’ll do pluginTiddlers, pluginInfo and shadowTiddlers.
2014-03-16 21:23:10 +00:00
Jermolene
499730c458 Remove whitespace between toolbar icons 2014-03-15 17:04:12 +00:00
Jermolene
baa8cf3dd0 Add a warning segment to templates for TWC tiddlers
Now there’s a warning banner on all TWC tiddlers. It includes an
`upgrade` button that currently just flips the tiddler type to TW5
2014-03-15 17:03:50 +00:00
Jermolene
f649b5b037 Extend button widget to set text references
Previously the `set` attribute could only be used to identify a
tiddler, not a full text reference.
2014-03-15 17:02:13 +00:00
Jermolene
afa677b9a0 Add a class to tiddler frames in view mode
We’re already marking tiddlers in edit mode with tw-tiddler-edit-mode,
makes sense to make view mode tiddlers too.
2014-03-15 11:20:33 +00:00
Jeremy Ruston
6fe884bb8a Merge pull request #489 from BramChen/master
Keep up-to-date changes for zh-Hant and zh-Hans
2014-03-15 09:02:29 +00:00
Bram Chen
00af144085 Add Chinese translations for tiddler info 'advanced' panel 2014-03-15 09:57:50 +08:00
Bram Chen
5d893397c4 Merge remote-tracking branch 'upstream/master' 2014-03-15 08:39:54 +08:00
Jermolene
42c67cfeb7 Add tiddler info "advanced" panel 2014-03-14 15:23:28 +00:00
Jermolene
b714c67374 Refactor plugin loading to retain plugin info for all plugins
Previously we were not reading the plugin info for plugins that hadn’t
been loaded.
2014-03-14 15:23:12 +00:00
Jermolene
00cb2f4659 Add links to static representations for people with JS turned off 2014-03-14 15:21:52 +00:00
Jermolene
24b6603c42 Fix problem with checking versions of plugins carrying a badly formatted "version" field 2014-03-14 10:43:22 +00:00
Bram Chen
a82e50c07f Keep up-to-date changes for zh-Hant and zh-Hans 2014-03-14 13:02:49 +08:00
Jermolene
ebc77fbd09 Get ready for a new view template segment carrying information about plugins 2014-03-13 17:44:27 +00:00
Jermolene
96457d8011 Rejig plugins tab of control panel
Now we divide the plugins into categories and organise the displayed
information a bit better
2014-03-13 17:43:18 +00:00
Jermolene
3d9f61f041 More whitespace in core templates 2014-03-13 17:42:29 +00:00
Jermolene
f48701544e Enhance tiddler title for system tiddlers
Now the $:/ part of the name is rendered in grey, making the main part
of the title more prominent.

@tobibeer suggested this a long time ago; good idea!
2014-03-13 17:40:53 +00:00
Jermolene
50cf9678cb Add support for tw-home message 2014-03-12 22:32:13 +00:00
Jermolene
c4119f4f93 Default colour tweaks 2014-03-12 22:22:18 +00:00
Jermolene
cafe74fc89 Tweaks to list-before and list-after field descriptions 2014-03-12 22:22:02 +00:00
Jeremy Ruston
2466389397 Merge pull request #485 from TheDiveO/master
added descriptions for list-before, list-after
2014-03-12 21:57:41 +00:00
Jermolene
dd3ee2a603 Extend tag manager to edit icons assigned to tags
Add a dropdown for choosing available images for a tag.

As part of this change we need to tag tiddlers that contain images
typed as wikitext (these are inline SVG icons) so that we can display
them in the dropdown.
2014-03-12 21:56:46 +00:00
Jermolene
8e17c1dfd5 Fix setTextReference()
It wasn’t working for non-existent tiddlers. Also added support for
setting indexed properties of a data tiddler.
2014-03-12 21:54:43 +00:00
Jermolene
9bd0174205 Left off previous commit 2014-03-12 21:53:50 +00:00
TheDiveO
522dad95be added descriptions for list-before, list-after 2014-03-12 21:26:18 +01:00
Jeremy Ruston
87c4839fed Merge pull request #484 from TheDiveO/master
signed CLA
2014-03-12 20:06:01 +00:00
Jermolene
22b6425bac Update link to tags docs 2014-03-12 20:05:45 +00:00
Jermolene
5ba92fe274 Update to latest version of normalize.css and fix tab styling
Tab styling was inconsistent on Firefox due to some line-height issues.
2014-03-12 20:05:34 +00:00
TheDiveO
91939d67ed signed CLA 2014-03-12 20:45:04 +01:00
Jermolene
d0caf21b2d Exclude attributes starting "on" on HTML elements
Because:

* It doesn't work well with TW5's refresh mechanism, which relies on
being able to regenerate any portion of the DOM as required; this
frequently causes inline handlers to be re-executed at unexpected times
(see
http://tiddlywiki.com/static/TiddlyWiki%2520for%2520Developers.html)
* It mixes TW5 version-specific JavaScript with user content
* In multiuser environments there is a security risk to importing or
viewing tiddlers you didn't author if they can have JavaScript in them
2014-03-12 16:39:18 +00:00
Jermolene
0d18f3cc5d Add support for ordering tags by the 'list-before' and 'list-after' fields
See the discussion here:

https://groups.google.com/d/topic/tiddlywikidev/AXDJEjcAphs/discussion
2014-03-12 14:19:26 +00:00
Jermolene
a3507bf611 Freeze the fields of a tiddler
Thus enforcing the immutability of tiddler objects
2014-03-12 08:33:13 +00:00
Jermolene
62bc20a181 Restore visibility of system tags in view template
On discussion at Hangout #38 we felt that hiding them was confusing,
and that there were few situations where a user would see system tags
except on system tiddlers.
2014-03-11 18:25:41 +00:00
Jermolene
9ded88105b Update test of tagging filter to reflect 0d7c4ae6c7 2014-03-11 15:53:41 +00:00
Jermolene
aec618793f Fix problem with refreshing D3 plugin
Fixes #217
2014-03-11 11:12:56 +00:00
Jeremy Ruston
fe33906ef0 Merge pull request #481 from BramChen/master
Add chinese translation of canned filters
2014-03-11 08:30:33 +00:00
Jermolene
6a17bad96e Add margin on code blocks and tables 2014-03-11 08:29:11 +00:00
Bram Chen
4f9fa5d66e Add chinese translation of canned filters 2014-03-11 12:51:32 +08:00
Jermolene
0d7c4ae6c7 Include tags on shadow tiddlers in tagging filter
Ensures that for system tiddlers the info panel "Tagging" tab correctly
shows the tagged tiddlers.

Final fix for #478
2014-03-10 19:41:38 +00:00
Jermolene
2608a323eb Hide system tags from the sidebar tags list
Part of #478
2014-03-10 19:40:07 +00:00
Jermolene
8d612aefdd Fix problem with theme overrides triggering the syncer object
Fixes #479
2014-03-10 19:05:06 +00:00
Jermolene
ad96c48034 Docs updates 2014-03-10 18:41:30 +00:00
Jermolene
12e153ecff Update wikitext tests to reflect title attribute 2014-03-10 18:41:26 +00:00
Jermolene
db35bc36aa Disable storyviews when rendering to the fake dom 2014-03-10 18:41:11 +00:00
Jermolene
af34fbbca3 Only show command line help if no arguments are provided
Previously we were checking in a way that meant that `tiddlywiki
<wiki>` would trigger the help message.
2014-03-10 18:20:07 +00:00
Jermolene
8239275edb Add dropdown of canned filter searches
Now you can pick from a dropdown of predefined filtered searches in the
advanced search filter tab.
2014-03-10 18:16:10 +00:00
Jermolene
be6509a17f Remove system tags from sidebar tags listing 2014-03-10 18:15:12 +00:00
Jermolene
01e1133219 Fix bug where count widget wasn't being updated correctly 2014-03-10 18:15:00 +00:00
Jermolene
f04527ae32 Correct filter for count of overridden shadow tiddlers 2014-03-10 15:05:07 +00:00
Jermolene
98872bbe7c Allow pasting/dropping of HTML content
Fixes #477
2014-03-09 20:39:03 +00:00
Jermolene
bc8b72e6eb Use hasOwnProperty to text for tiddler existence 2014-03-09 19:20:58 +00:00
Jermolene
127d547632 Avoid confusion with the word "breaking"
I meant “broken” in the sense of “incompatible”, not “breaking” as in
“news”.
2014-03-09 09:19:47 +00:00
Jermolene
53755d87c8 Added tooltip examples to the link widget 2014-03-09 09:16:31 +00:00
Jermolene
289bec0fd5 Parse the wiki link tooltip as wiki text 2014-03-08 16:06:57 +00:00
Jermolene
8bd1fa50dc Fixed typo in dom maker 2014-03-08 10:43:01 +00:00
Jermolene
81af6bdd48 Fix typo in navigate handler for button widget 2014-03-08 10:22:09 +00:00
Jermolene
a5a2c718b1 Add support for a tooltip on the link widget 2014-03-06 12:38:47 +00:00
Jeremy Ruston
6b67a3f3c2 Merge pull request #471 from BramChen/master
Update doc and the chinese tranlastions of descriptive text for missing tiddlers
2014-03-06 08:31:54 +00:00
Jermolene
1cea80a3ab Docs update 2014-03-06 08:31:05 +00:00
Bram Chen
b6a202f525 Update doc 2014-03-06 11:47:20 +08:00
Bram Chen
7b109506c8 Update the chinese tranlastions of descriptive text for missing tiddlers 2014-03-06 11:31:17 +08:00
Jermolene
c277370e48 Display --help message if run without arguments
Fixes #389
2014-03-05 11:13:58 +00:00
Jermolene
f83443feac Fix location of stylesheet docs 2014-03-05 09:14:08 +00:00
Jermolene
8529ad13d6 Docs on using stylesheets 2014-03-05 09:13:14 +00:00
Jeremy Ruston
8deedf93a2 Merge pull request #467 from nameanyone/master
Fix a typo
2014-03-05 08:22:23 +00:00
nameanyone
bdcfa75220 Fixed a typo 2014-03-04 20:15:53 -08:00
nameanyone
20d39588b5 Signed CLA 2014-03-04 20:14:57 -08:00
Jermolene
67f3d58f71 Fix problem with "null" message when unloading under IE11
Fixes #457
2014-03-04 22:21:18 +00:00
Jeremy Ruston
bbfb855c2e Merge pull request #465 from BramChen/master
Add chinese translation of MissingTiddler stuff in Misc.multids.
2014-03-04 21:47:18 +00:00
Jermolene
6a63a45968 Improved tiddler filter documentation 2014-03-04 21:17:01 +00:00
Jermolene
70d2d4b7a1 Remove the "create" button from the missing tiddler template 2014-03-04 18:55:43 +00:00
Bram Chen
6aa21b3db6 Add chinese translation of MissingTiddler stuff in Misc.multids. 2014-03-04 17:38:26 +08:00
Jermolene
ff32317f5b Update grammar docs 2014-03-04 09:06:14 +00:00
Jermolene
df6436a12c Allow middle mouse button to trigger navigation suppression when clicking a tiddler link
Equivalent to holding control/command while clicking.
2014-03-03 09:09:13 +00:00
Jermolene
0200bc1b4e Force the highlight language to lower case 2014-03-02 19:42:40 +00:00
Jermolene
bd750a21e2 Add docs for keyboard widget 2014-03-02 19:30:13 +00:00
Jermolene
8c3782c1e2 Docs update 2014-03-02 18:43:59 +00:00
Jermolene
2f2a257745 Improve the descriptive text for missing tiddlers
Now we explain that it’s a missing tiddler, and add a “create” button
2014-03-02 18:43:22 +00:00
Jermolene
ab7d2d64e7 Add docs for tw-close-other-tiddlers message
Fixes #461
2014-03-02 18:36:46 +00:00
Jermolene
bc18501b59 Add @buggj's plugin site to the Community tiddler 2014-03-02 18:36:06 +00:00
Jermolene
0a5ce6d740 Prepare for 5.0.9-prerelease 2014-03-02 18:35:45 +00:00
439 changed files with 7565 additions and 1944 deletions

View File

@@ -19,8 +19,6 @@ Error message and password prompt
left: 50%;
margin-left: -144px; /* - width/2 - paddingHorz/2 - border */
padding: 16px 16px 16px 16px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}

View File

@@ -32,8 +32,8 @@ if(!$tw) {
$tw = require("./bootprefix.js").bootprefix();
}
$tw.utils = $tw.utils || {};
$tw.boot = $tw.boot || {};
$tw.utils = $tw.utils || Object.create(null);
$tw.boot = $tw.boot || Object.create(null);
/////////////////////////// Standard node.js libraries
@@ -73,13 +73,11 @@ Iterate through all the own properties of an object or array. Callback is invoke
$tw.utils.each = function(object,callback) {
var f;
if(object) {
if($tw.utils.isArray(object)) {
for(f=0; f<object.length; f++) {
callback(object[f],f,object);
}
if(Object.prototype.toString.call(object) == "[object Array]") {
object.forEach(callback);
} else {
for(f in object) {
if($tw.utils.hop(object,f)) {
if(Object.prototype.hasOwnProperty.call(object,f)) {
callback(object[f],f,object);
}
}
@@ -107,7 +105,7 @@ $tw.utils.domMaker = function(tag,options) {
element.className = options["class"];
}
if(options.text) {
element.appendChild(document.createTextNode(options.text));
element.appendChild(doc.createTextNode(options.text));
}
$tw.utils.each(options.children,function(child) {
element.appendChild(child);
@@ -282,7 +280,7 @@ $tw.utils.parseStringArray = function(value) {
// Parse a block of name:value fields. The `fields` object is used as the basis for the return value
$tw.utils.parseFields = function(text,fields) {
fields = fields || {};
fields = fields || Object.create(null);
text.split(/\r?\n/mg).forEach(function(line) {
if(line.charAt(0) !== "#") {
var p = line.indexOf(":");
@@ -354,11 +352,16 @@ $tw.utils.parseVersion = function(version) {
};
/*
Returns true if the version string A is greater than the version string B
Returns true if the version string A is greater than the version string B. Returns true if the versions are the same
*/
$tw.utils.checkVersions = function(versionStringA,versionStringB) {
var versionA = $tw.utils.parseVersion(versionStringA),
versionB = $tw.utils.parseVersion(versionStringB),
var defaultVersion = {
major: 0,
minor: 0,
patch: 0
},
versionA = $tw.utils.parseVersion(versionStringA) || defaultVersion,
versionB = $tw.utils.parseVersion(versionStringB) || defaultVersion,
diff = [
versionA.major - versionB.major,
versionA.minor - versionB.minor,
@@ -366,23 +369,38 @@ $tw.utils.checkVersions = function(versionStringA,versionStringB) {
];
return (diff[0] > 0) ||
(diff[0] === 0 && diff[1] > 0) ||
(diff[0] === 0 && diff[1] === 0 && diff[2] > 0);
(diff[0] === 0 && diff[1] === 0 && diff[2] > 0) ||
(diff[0] === 0 && diff[1] === 0 && diff[2] === 0);
};
/*
Register file type information
flags: "image" for image types
options: {flags: flags,deserializerType: deserializerType}
flags:"image" for image types
deserializerType: defaults to type if not specified
*/
$tw.utils.registerFileType = function(type,encoding,extension,flags) {
$tw.config.fileExtensionInfo[extension] = {type: type};
$tw.config.contentTypeInfo[type] = {encoding: encoding, extension: extension, flags: flags || []};
$tw.utils.registerFileType = function(type,encoding,extension,options) {
options = options || {};
$tw.config.fileExtensionInfo[extension] = {type: type};
$tw.config.contentTypeInfo[type] = {encoding: encoding, extension: extension, flags: options.flags || [], deserializerType: options.deserializerType || type};
};
/*
Given an extension, get the correct encoding for that file.
defaults to utf8
*/
$tw.utils.getTypeEncoding = function(ext) {
var extensionInfo = $tw.config.fileExtensionInfo[ext],
type = extensionInfo ? extensionInfo.type : null,
typeInfo = type ? $tw.config.contentTypeInfo[type] : null;
return typeInfo ? typeInfo.encoding : "utf8";
};
/*
Run code globally with specified context variables in scope
*/
$tw.utils.evalGlobal = function(code,context,filename) {
var contextCopy = $tw.utils.extend({},context);
var contextCopy = $tw.utils.extend(Object.create(null),context);
// Get the context variables as a pair of arrays of names and values
var contextNames = [], contextValues = [];
$tw.utils.each(contextCopy,function(value,name) {
@@ -394,7 +412,7 @@ $tw.utils.evalGlobal = function(code,context,filename) {
// Compile the code into a function
var fn;
if($tw.browser) {
fn = window["eval"](code);
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
} else {
fn = vm.runInThisContext(code,filename);
}
@@ -406,7 +424,7 @@ $tw.utils.evalGlobal = function(code,context,filename) {
Run code in a sandbox with only the specified context variables in scope
*/
$tw.utils.evalSandboxed = $tw.browser ? $tw.utils.evalGlobal : function(code,context,filename) {
var sandbox = $tw.utils.extend({},context);
var sandbox = $tw.utils.extend(Object.create(null),context);
vm.runInNewContext(code,sandbox,filename);
return sandbox.exports;
};
@@ -669,7 +687,7 @@ Apply a callback to each module of a particular type
*/
$tw.modules.forEachModuleOfType = function(moduleType,callback) {
var modules = $tw.modules.types[moduleType];
$tw.utils.each(modules,function(element,title,object) {
$tw.utils.each(modules,function(element,title) {
callback(title,$tw.modules.execute(title));
});
};
@@ -679,7 +697,7 @@ Get all the modules of a particular type in a hashmap by their `name` field
*/
$tw.modules.getModulesByTypeAsHashmap = function(moduleType,nameField) {
nameField = nameField || "name";
var results = {};
var results = Object.create(null);
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
results[module[nameField]] = module;
});
@@ -691,7 +709,7 @@ Apply the exports of the modules of a particular type to a target object
*/
$tw.modules.applyMethods = function(moduleType,targetObject) {
if(!targetObject) {
targetObject = {};
targetObject = Object.create(null);
}
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
$tw.utils.each(module,function(element,title,object) {
@@ -705,7 +723,7 @@ $tw.modules.applyMethods = function(moduleType,targetObject) {
Return an array of classes created from the modules of a specified type. Each module should export the properties to be added to those of the optional base class
*/
$tw.modules.createClassesFromModules = function(moduleType,subType,baseClass) {
var classes = {};
var classes = Object.create(null);
$tw.modules.forEachModuleOfType(moduleType,function(title,moduleExports) {
if(!subType || moduleExports.types[subType]) {
var newClass = function() {};
@@ -727,26 +745,34 @@ Construct a tiddler object from a hashmap of tiddler fields. If multiple hasmaps
taking precedence to the right
*/
$tw.Tiddler = function(/* [fields,] fields */) {
this.fields = {};
this.fields = Object.create(null);
for(var c=0; c<arguments.length; c++) {
var arg = arguments[c],
src = (arg instanceof $tw.Tiddler) ? arg.fields : arg;
for(var t in src) {
if(src[t] === undefined) {
if(src[t] === undefined || src[t] === null) {
if(t in this.fields) {
delete this.fields[t]; // If we get a field that's undefined, delete any previous field value
}
} else {
// Parse the field with the associated field module (if any)
var fieldModule = $tw.Tiddler.fieldModules[t];
var fieldModule = $tw.Tiddler.fieldModules[t],
value;
if(fieldModule && fieldModule.parse) {
this.fields[t] = fieldModule.parse.call(this,src[t]);
value = fieldModule.parse.call(this,src[t]);
} else {
this.fields[t] = src[t];
value = src[t];
}
// Freeze the field to keep it immutable
if(typeof value === "object") {
Object.freeze(value);
}
this.fields[t] = value;
}
}
}
// Freeze the tiddler against modification
Object.freeze(this.fields);
};
$tw.Tiddler.prototype.hasField = function(field) {
@@ -785,115 +811,206 @@ $tw.modules.define("$:/boot/tiddlerfields/list","tiddlerfield",{
/////////////////////////// Barebones wiki store
/*
Construct a wiki store object
Wiki constructor. State is stored in private members that only a small number of privileged accessor methods have direct access. Methods added via the prototype have to use these accessors and cannot access the state data directly.
options include:
shadowTiddlers: Array of shadow tiddlers to be added
*/
$tw.Wiki = function() {
this.tiddlers = {};
this.plugins = []; // Array of registered plugins, ordered by priority
this.shadowTiddlers = {}; // Hashmap by title of {source:, tiddler:}
$tw.Wiki = function(options) {
options = options || {};
var self = this,
tiddlers = Object.create(null), // Hashmap of tiddlers
pluginTiddlers = [], // Array of tiddlers containing registered plugins, ordered by priority
pluginInfo = Object.create(null), // Hashmap of parsed plugin content
shadowTiddlers = options.shadowTiddlers || Object.create(null); // Hashmap by title of {source:, tiddler:}
// Add a tiddler to the store
this.addTiddler = function(tiddler) {
if(!(tiddler instanceof $tw.Tiddler)) {
tiddler = new $tw.Tiddler(tiddler);
}
// Save the tiddler
if(tiddler) {
var title = tiddler.fields.title;
if(title) {
tiddlers[title] = tiddler;
this.clearCache(title);
this.clearGlobalCache();
this.enqueueTiddlerEvent(title);
}
}
};
// Delete a tiddler
this.deleteTiddler = function(title) {
delete tiddlers[title];
this.clearCache(title);
this.clearGlobalCache();
this.enqueueTiddlerEvent(title,true);
};
// Get a tiddler from the store
this.getTiddler = function(title) {
var t = tiddlers[title];
if(t instanceof $tw.Tiddler) {
return t;
} else if(title !== undefined && Object.prototype.hasOwnProperty.call(shadowTiddlers,title)) {
return shadowTiddlers[title].tiddler;
} else {
return undefined;
}
};
// Get an array of all tiddler titles
this.allTitles = function() {
return Object.keys(tiddlers);
};
// Iterate through all tiddler titles
this.each = function(callback) {
for(var title in tiddlers) {
callback(tiddlers[title],title);
}
};
// Get an array of all shadow tiddler titles
this.allShadowTitles = function() {
return Object.keys(shadowTiddlers);
};
// Iterate through all shadow tiddler titles
this.eachShadow = function(callback) {
for(var title in shadowTiddlers) {
var shadowInfo = shadowTiddlers[title];
callback(shadowInfo.tiddler,title);
}
};
// Test for the existence of a tiddler
this.tiddlerExists = function(title) {
return !!$tw.utils.hop(tiddlers,title);
};
// Determines if a tiddler is a shadow tiddler, regardless of whether it has been overridden by a real tiddler
this.isShadowTiddler = function(title) {
return $tw.utils.hop(shadowTiddlers,title);
};
this.getShadowSource = function(title) {
if($tw.utils.hop(shadowTiddlers,title)) {
return shadowTiddlers[title].source;
}
return null;
};
// Read plugin info for all plugins
this.readPluginInfo = function() {
for(var title in tiddlers) {
var tiddler = tiddlers[title];
if(tiddler.fields.type === "application/json" && tiddler.hasField("plugin-type")) {
pluginInfo[tiddler.fields.title] = JSON.parse(tiddler.fields.text);
}
}
};
// Get plugin info for a plugin
this.getPluginInfo = function(title) {
return pluginInfo[title];
};
// Register the plugin tiddlers of a particular type, optionally restricting registration to an array of tiddler titles. Return the array of titles affected
this.registerPluginTiddlers = function(pluginType,titles) {
var self = this,
registeredTitles = [],
checkTiddler = function(tiddler) {
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] === pluginType) {
pluginTiddlers.push(tiddler);
registeredTitles.push(tiddler.fields.title);
}
};
if(titles) {
$tw.utils.each(titles,function(title) {
checkTiddler(self.getTiddler(title));
});
} else {
this.each(function(tiddler,title) {
checkTiddler(tiddler);
});
}
return registeredTitles;
};
// Unregister the plugin tiddlers of a particular type, returning an array of the titles affected
this.unregisterPluginTiddlers = function(pluginType) {
var self = this,
titles = [];
// Remove any previous registered plugins of this type
for(var t=pluginTiddlers.length-1; t>=0; t--) {
var tiddler = pluginTiddlers[t];
if(tiddler.fields["plugin-type"] === pluginType) {
titles.push(tiddler.fields.title);
pluginTiddlers.splice(t,1);
}
}
return titles;
};
// Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
this.unpackPluginTiddlers = function() {
var self = this;
// Sort the plugin titles by the `plugin-priority` field
pluginTiddlers.sort(function(a,b) {
if("plugin-priority" in a.fields && "plugin-priority" in b.fields) {
return a.fields["plugin-priority"] - b.fields["plugin-priority"];
} else if("plugin-priority" in a.fields) {
return -1;
} else if("plugin-priority" in b.fields) {
return +1;
} else if(a.fields.title < b.fields.title) {
return -1;
} else if(a.fields.title === b.fields.title) {
return 0;
} else {
return +1;
}
});
// Now go through the plugins in ascending order and assign the shadows
shadowTiddlers = Object.create(null);
$tw.utils.each(pluginTiddlers,function(tiddler) {
// Extract the constituent tiddlers
if($tw.utils.hop(pluginInfo,tiddler.fields.title)) {
$tw.utils.each(pluginInfo[tiddler.fields.title].tiddlers,function(constituentTiddler,constituentTitle) {
// Save the tiddler object
if(constituentTitle) {
shadowTiddlers[constituentTitle] = {
source: tiddler.fields.title,
tiddler: new $tw.Tiddler(constituentTiddler,{title: constituentTitle})
};
}
});
}
});
};
};
$tw.Wiki.prototype.addTiddler = function(tiddler) {
if(!(tiddler instanceof $tw.Tiddler)) {
tiddler = new $tw.Tiddler(tiddler);
}
if(tiddler.fields.title) {
this.tiddlers[tiddler.fields.title] = tiddler;
}
};
// Dummy methods that will be filled in after boot
$tw.Wiki.prototype.clearCache =
$tw.Wiki.prototype.clearGlobalCache =
$tw.Wiki.prototype.enqueueTiddlerEvent = function() {};
// Add an array of tiddlers
$tw.Wiki.prototype.addTiddlers = function(tiddlers) {
for(var t=0; t<tiddlers.length; t++) {
this.addTiddler(tiddlers[t]);
}
};
/*
Register the plugin tiddlers of a particular type, optionally restricting registration to an array of tiddler titles. Return the array of titles affected
*/
$tw.Wiki.prototype.registerPluginTiddlers = function(pluginType,titles) {
var self = this,
registeredTitles = [];
// Go through the provided titles, or the entire tiddler list, looking for plugins of this type
var checkTiddler = function(tiddler) {
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] === pluginType) {
self.plugins.push(tiddler);
registeredTitles.push(tiddler.fields.title);
}
};
if(titles) {
$tw.utils.each(titles,function(title) {
checkTiddler(self.getTiddler(title));
});
} else {
$tw.utils.each(this.tiddlers,function(tiddler,title) {
checkTiddler(tiddler);
});
}
return registeredTitles;
};
/*
Unregister the plugin tiddlers of a particular type, returning an array of the titles affected
*/
$tw.Wiki.prototype.unregisterPluginTiddlers = function(pluginType) {
var self = this,
titles = [];
// Remove any previous registered plugins of this type
for(var t=this.plugins.length-1; t>=0; t--) {
var tiddler = this.plugins[t];
if(tiddler.fields["plugin-type"] === pluginType) {
titles.push(tiddler.fields.title);
this.plugins.splice(t,1);
}
}
return titles;
};
/*
Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
*/
$tw.Wiki.prototype.unpackPluginTiddlers = function() {
var self = this;
// Sort the plugin titles by the `plugin-priority` field
this.plugins.sort(function(a,b) {
if("plugin-priority" in a.fields && "plugin-priority" in b.fields) {
return a.fields["plugin-priority"] - b.fields["plugin-priority"];
} else if("plugin-priority" in a.fields) {
return -1;
} else if("plugin-priority" in b.fields) {
return +1;
} else if(a.fields.title < b.fields.title) {
return -1;
} else if(a.fields.title === b.fields.title) {
return 0;
} else {
return +1;
}
});
// Now go through the plugins in ascending order and assign the shadows
this.shadowTiddlers = {};
$tw.utils.each(this.plugins,function(tiddler) {
// Get the plugin information
var pluginInfo = JSON.parse(tiddler.fields.text);
// Extract the constituent tiddlers
$tw.utils.each(pluginInfo.tiddlers,function(constituentTiddler,constituentTitle) {
// Save the tiddler object
if(constituentTitle) {
self.shadowTiddlers[constituentTitle] = {
source: tiddler.fields.title,
tiddler: new $tw.Tiddler(constituentTiddler,{title: constituentTitle})
};
}
});
});
};
/*
Define all modules stored in ordinary tiddlers
*/
$tw.Wiki.prototype.defineTiddlerModules = function() {
$tw.utils.each(this.tiddlers,function(tiddler,title,object) {
this.each(function(tiddler,title) {
if(tiddler.hasField("module-type")) {
switch (tiddler.fields.type) {
case "application/javascript":
@@ -918,40 +1035,63 @@ Register all the module tiddlers that have a module type
*/
$tw.Wiki.prototype.defineShadowModules = function() {
var self = this;
$tw.utils.each(this.shadowTiddlers,function(element,title) {
var tiddler = self.getTiddler(title);
if(!$tw.utils.hop(self.tiddlers,title)) { // Don't define the module if it is overidden by an ordinary tiddler
if(tiddler.hasField("module-type")) {
// Define the module
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
}
this.eachShadow(function(tiddler,title) {
// Don't define the module if it is overidden by an ordinary tiddler
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
// Define the module
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
}
});
};
$tw.Wiki.prototype.getTiddler = function(title) {
var t = this.tiddlers[title];
if(t instanceof $tw.Tiddler) {
return t;
} else if(title !== undefined && $tw.utils.hop(this.shadowTiddlers,title)) {
return this.shadowTiddlers[title].tiddler;
} else {
return undefined;
}
/*
Enable safe mode by deleting any tiddlers that override a shadow tiddler
*/
$tw.Wiki.prototype.processSafeMode = function() {
var self = this,
overrides = [];
// Find the overriding tiddlers
this.each(function(tiddler,title) {
if(self.isShadowTiddler(title)) {
console.log(title);
overrides.push(title);
}
});
// Assemble a report tiddler
var titleReportTiddler = "TiddlyWiki Safe Mode",
report = [];
report.push("TiddlyWiki has been started in [[safe mode|http://tiddlywiki.com/static/SafeMode.html]]. Most customisations have been disabled by renaming the following tiddlers:")
// Delete the overrides
overrides.forEach(function(title) {
var tiddler = self.getTiddler(title),
newTitle = "SAFE: " + title;
self.deleteTiddler(title);
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
report.push("* [[" + title + "|" + newTitle + "]]");
});
report.push()
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
// Set $:/DefaultTiddlers to point to our report
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
};
/*
Extracts tiddlers from a typed block of text, specifying default field values
*/
$tw.Wiki.prototype.deserializeTiddlers = function(type,text,srcFields) {
srcFields = srcFields || {};
srcFields = srcFields || Object.create(null);
var deserializer = $tw.Wiki.tiddlerDeserializerModules[type],
fields = {};
fields = Object.create(null);
if(!deserializer && $tw.config.fileExtensionInfo[type]) {
// If we didn't find the serializer, try converting it from an extension to a content type
type = $tw.config.fileExtensionInfo[type].type;
deserializer = $tw.Wiki.tiddlerDeserializerModules[type];
}
if(!deserializer && $tw.config.contentTypeInfo[type]) {
// see if this type has a different deserializer registered with it
type = $tw.config.contentTypeInfo[type].deserializerType;
deserializer = $tw.Wiki.tiddlerDeserializerModules[type];
}
if(!deserializer) {
// If we still don't have a deserializer, treat it as plain text
deserializer = $tw.Wiki.tiddlerDeserializerModules["text/plain"];
@@ -1009,7 +1149,7 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/tids","tiddlerdeserializer",{
if(line.charAt(0) !== "#") {
var colonPos= line.indexOf(": ");
if(colonPos !== -1) {
var tiddler = $tw.utils.extend({},fields);
var tiddler = $tw.utils.extend(Object.create(null),fields);
tiddler.title = (tiddler.title || "") + line.substr(0,colonPos);
if(titles.indexOf(tiddler.title) !== -1) {
console.log("Warning: .multids file contains multiple definitions for " + tiddler.title);
@@ -1228,7 +1368,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
// Look for a tiddlywiki.files file
if(files.indexOf("tiddlywiki.files") !== -1) {
// If so, process the files it describes
var filesInfo = JSON.parse(fs.readFileSync(filepath + "/tiddlywiki.files","utf8"));
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
var typeInfo = $tw.config.contentTypeInfo[tidInfo.fields.type || "text/plain"],
pathname = path.resolve(filepath,tidInfo.file),
@@ -1246,7 +1386,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
// If not, read all the files in the directory
$tw.utils.each(files,function(file) {
if(!excludeRegExp.test(file)) {
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(filepath + "/" + file,excludeRegExp));
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(filepath + path.sep + file,excludeRegExp));
}
});
}
@@ -1267,20 +1407,20 @@ $tw.loadPluginFolder = function(filepath,excludeRegExp) {
stat = fs.statSync(filepath);
if(stat.isDirectory()) {
// Read the plugin information
pluginInfo = JSON.parse(fs.readFileSync(filepath + "/plugin.info","utf8"));
pluginInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "plugin.info","utf8"));
// Read the plugin files
files = fs.readdirSync(filepath);
for(f=0; f<files.length; f++) {
file = files[f];
if(!excludeRegExp.test(file) && file !== "plugin.info" && file !== "tiddlywiki.files") {
var tiddlerFiles = $tw.loadTiddlersFromPath(filepath + "/" + file,excludeRegExp);
var tiddlerFiles = $tw.loadTiddlersFromPath(filepath + path.sep + file,excludeRegExp);
$tw.utils.each(tiddlerFiles,function(tiddlerFile) {
pluginTiddlers.push.apply(pluginTiddlers,tiddlerFile.tiddlers);
});
}
}
// Save the plugin tiddlers into the plugin info
pluginInfo.tiddlers = pluginInfo.tiddlers || {};
pluginInfo.tiddlers = pluginInfo.tiddlers || Object.create(null);
for(t=0; t<pluginTiddlers.length; t++) {
if(pluginTiddlers[t].title) {
pluginInfo.tiddlers[pluginTiddlers[t].title] = pluginTiddlers[t];
@@ -1454,10 +1594,12 @@ readBrowserTiddlers: whether to read tiddlers from the HTML file we're executing
*/
$tw.boot.startup = function(options) {
options = options || {};
// Check for safe mode
$tw.safeMode = $tw.browser && location.hash === "#:safe";
// Initialise some more $tw properties
$tw.utils.deepDefaults($tw,{
modules: { // Information about each module
titles: {}, // hashmap by module title of {fn:, exports:, moduleType:}
titles: Object.create(null), // hashmap by module title of {fn:, exports:, moduleType:}
types: {} // hashmap by module type of hashmap of exports
},
config: { // Configuration overridables
@@ -1471,16 +1613,20 @@ $tw.boot.startup = function(options) {
wikiLanguagesSubDir: "./languages",
wikiTiddlersSubDir: "./tiddlers",
jsModuleHeaderRegExpString: "^\\/\\*\\\\(?:\\r?\\n)((?:^[^\\r\\n]*(?:\\r?\\n))+?)(^\\\\\\*\\/$(?:\\r?\\n)?)",
fileExtensionInfo: {}, // Map file extension to {type:}
contentTypeInfo: {} // Map type to {encoding:,extension:}
fileExtensionInfo: Object.create(null), // Map file extension to {type:}
contentTypeInfo: Object.create(null) // Map type to {encoding:,extension:}
}
});
if(!options.readBrowserTiddlers) {
// For writable tiddler files, a hashmap of title to {filepath:,type:,hasMetaFile:}
$tw.boot.files = {};
$tw.boot.files = Object.create(null);
// System paths and filenames
$tw.boot.bootPath = path.dirname(module.filename);
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
// If there's no arguments then default to `--help`
if($tw.boot.argv.length === 0) {
$tw.boot.argv = ["--help"];
}
// If the first command line argument doesn't start with `--` then we
// interpret it as the path to the wiki folder, which will otherwise default
// to the current folder
@@ -1506,21 +1652,22 @@ $tw.boot.startup = function(options) {
$tw.utils.registerFileType("text/plain","utf8",".txt");
$tw.utils.registerFileType("text/css","utf8",".css");
$tw.utils.registerFileType("text/html","utf8",".html");
$tw.utils.registerFileType("application/hta","utf16le",".hta",{deserializerType:"text/html"});
$tw.utils.registerFileType("application/javascript","utf8",".js");
$tw.utils.registerFileType("application/json","utf8",".json");
$tw.utils.registerFileType("application/pdf","base64",".pdf",["image"]);
$tw.utils.registerFileType("image/jpeg","base64",".jpg",["image"]);
$tw.utils.registerFileType("image/png","base64",".png",["image"]);
$tw.utils.registerFileType("image/gif","base64",".gif",["image"]);
$tw.utils.registerFileType("image/svg+xml","utf8",".svg",["image"]);
$tw.utils.registerFileType("image/x-icon","base64",".ico",["image"]);
$tw.utils.registerFileType("application/pdf","base64",".pdf",{flags:["image"]});
$tw.utils.registerFileType("image/jpeg","base64",".jpg",{flags:["image"]});
$tw.utils.registerFileType("image/png","base64",".png",{flags:["image"]});
$tw.utils.registerFileType("image/gif","base64",".gif",{flags:["image"]});
$tw.utils.registerFileType("image/svg+xml","utf8",".svg",{flags:["image"]});
$tw.utils.registerFileType("image/x-icon","base64",".ico",{flags:["image"]});
$tw.utils.registerFileType("application/font-woff","base64",".woff");
// Create the wiki store for the app
$tw.wiki = new $tw.Wiki();
// Install built in tiddler fields modules
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
// Install the tiddler deserializer modules
$tw.Wiki.tiddlerDeserializerModules = {};
$tw.Wiki.tiddlerDeserializerModules = Object.create(null);
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
// Load tiddlers
if(options.readBrowserTiddlers) {
@@ -1529,8 +1676,13 @@ $tw.boot.startup = function(options) {
$tw.loadTiddlersNode();
}
// Unpack plugin tiddlers
$tw.wiki.readPluginInfo();
$tw.wiki.registerPluginTiddlers("plugin");
$tw.wiki.unpackPluginTiddlers();
// Process "safe mode"
if($tw.safeMode) {
$tw.wiki.processSafeMode();
}
// Register typed modules from the tiddlers we've just loaded
$tw.wiki.defineTiddlerModules();
// And any modules within plugins

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,4 @@
title: $:/core/images/cancel-button
tags: $:/tags/Image
<svg class="tw-image-cancel-button tw-image-button" viewBox="366 150 58 58" width="22pt" height="22pt"><path d="M 414.76236 158.98764 C 403.77887 148.0041 385.97113 148.0041 374.98764 158.98764 C 364.0041 169.97113 364.0041 187.77887 374.98764 198.76236 C 385.97113 209.7459 403.77887 209.7459 414.76236 198.76236 C 425.7459 187.77887 425.7459 169.97113 414.76236 158.98764 M 385.3967 165.32954 L 385.3967 165.32954 L 394.77674 174.7096 L 404.3533 165.13303 C 405.53068 163.95566 407.4396 163.95566 408.61697 165.13303 C 409.79434 166.31041 409.79434 168.21932 408.61697 169.39669 L 399.0404 178.97325 L 408.42046 188.35331 C 409.59783 189.53068 409.59783 191.43959 408.42046 192.61697 L 408.42046 192.61697 C 407.24308 193.79434 405.33417 193.79434 404.1568 192.61697 L 394.77675 183.23692 L 385.5932 192.42046 C 384.41583 193.59783 382.50692 193.59783 381.32954 192.42046 L 381.32954 192.42046 C 380.15217 191.24308 380.15217 189.33417 381.32954 188.1568 C 381.32954 188.1568 381.32954 188.1568 381.32954 188.1568 L 381.32954 188.1568 L 381.32954 188.1568 L 390.51309 178.97326 L 381.13303 169.5932 C 379.95566 168.41583 379.95566 166.50692 381.13303 165.32954 L 381.13303 165.32954 C 382.3104 164.15217 384.21932 164.15217 385.3967 165.32954 C 385.3967 165.32954 385.3967 165.32954 385.3967 165.32954 Z"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/close-button
tags: $:/tags/Image
<svg class="tw-image-close-button tw-image-button" viewBox="222 150 56 56" width="22pt" height="22pt"><path d="M 249.56668 185.88827 L 267.06757 203.38916 C 269.26427 205.58586 272.82582 205.58586 275.02252 203.38916 L 275.02252 203.38916 C 277.21922 201.19246 277.21922 197.63091 275.02252 195.43421 L 257.52163 177.93332 L 275.38916 160.06579 C 277.58586 157.86909 277.58586 154.30754 275.38916 152.11084 C 273.19246 149.91414 269.63091 149.91414 267.43421 152.11084 L 249.56668 169.97837 L 232.06579 152.47748 L 232.06579 152.47748 C 232.06579 152.47748 232.06579 152.47748 232.06579 152.47748 C 229.86909 150.28078 226.30754 150.28078 224.11084 152.47748 L 224.11084 152.47748 C 221.91414 154.674175 221.91414 158.23573 224.11084 160.43243 L 241.61173 177.93332 L 224.47748 195.06757 L 224.47748 195.06757 L 224.47748 195.06757 C 224.47748 195.06757 224.47748 195.06757 224.47748 195.06757 C 222.28078 197.26427 222.28078 200.82583 224.47748 203.02252 L 224.47748 203.02252 C 226.67418 205.21922 230.23573 205.21922 232.43243 203.02252 Z"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/delete-button
tags: $:/tags/Image
<svg class="tw-image-delete-button tw-image-button" viewBox="303 155 39 50" width="17pt" height="22pt"><path d="M 333 164.25 L 333 157.25 C 333 156.14543 332.10457 155.25 331 155.25 L 314.75 155.25 C 314.75 155.25 314.75 155.25 314.75 155.25 C 313.64543 155.25 312.75 156.14543 312.75 157.25 L 312.75 164.25 L 303.75 164.25 L 303.75 168.75 L 306 168.75 L 306 201.75 L 306 201.75 L 306 201.75 C 306 203.40685 307.34315 204.75 309 204.75 L 336.75 204.75 C 338.40685 204.75 339.75 203.40685 339.75 201.75 L 339.75 168.75 L 342 168.75 L 342 164.25 Z M 317.25 160.75 L 317.25 160.75 C 317.25 160.19772 317.69772 159.75 318.25 159.75 C 318.25 159.75 318.25 159.75 318.25 159.75 L 327.5 159.75 C 328.05228 159.75 328.5 160.19772 328.5 160.75 L 328.5 164.25 L 317.25 164.25 L 317.25 160.75 Z M 310.5 168.75 L 312.75 168.75 L 312.75 200.25 L 310.5 200.25 Z M 317.25 168.75 L 319.5 168.75 L 319.5 200.25 L 317.25 200.25 Z M 324 168.75 L 326.25 168.75 L 326.25 200.25 L 324 200.25 Z M 330.75 168.75 L 333 168.75 L 333 200.25 L 330.75 200.25 Z"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/done-button
tags: $:/tags/Image
<svg class="tw-image-done-button tw-image-button" viewBox="434 150 68 55" width="22pt" height="18pt"><path d="M 438.49266 178.00797 L 439.00744 177.49319 C 441.35054 175.15008 445.14946 175.15004 447.49262 177.49309 L 452.50734 182.50757 C 454.8505 184.85063 458.6494 184.85058 460.99252 182.50748 L 488.50747 154.99255 C 490.85058 152.64944 494.6495 152.6494 496.99266 154.99246 L 497.50722 155.506995 C 499.8504 157.85009 499.8505 161.64908 497.5074 163.99228 C 497.50738 163.99229 497.50736 163.99231 497.50734 163.99233 L 460.9926 200.5077 C 458.64947 202.85087 454.85048 202.8509 452.50732 200.50778 C 452.5073 200.50777 452.5073 200.50777 452.5073 200.50776 L 438.49268 186.49327 C 436.14952 184.15013 436.1495 180.35114 438.49264 178.00799 C 438.49265 178.00798 438.49265 178.00797 438.49266 178.00797 Z"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/down-arrow
tags: $:/tags/Image
<svg class="tw-image-down-arrow tw-image-button" viewBox="441 306 59 45" width="24pt" height="22pt"><path d="M 441 306 L 470.25 351 L 499.5 306 Z"/></svg>
<svg class="tw-image-down-arrow tw-image-button" viewBox="63 152 64 64" width="22pt" height="22pt"><path d="M 98.001786 212.81802 L 123.45763 187.36218 C 125.21499 185.60482 125.21499 182.75557 123.45763 180.99821 C 121.70027 179.24086 118.85103 179.24086 117.09367 180.99821 L 94.819805 203.27208 L 72.54594 180.99821 C 70.788582 179.24086 67.93934 179.24086 66.18198 180.99821 C 64.42462 182.75557 64.42462 185.60482 66.18198 187.36218 L 91.637825 212.81802 C 93.395184 214.57538 96.244426 214.57538 98.001786 212.81802 Z"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/edit-button
tags: $:/tags/Image
<svg class="tw-image-edit-button tw-image-button" viewBox="244 193 20 22" width="20pt" height="22pt"><path d="M 257.33334 196.80951 L 245.90476 207.2857 L 244 212.0476 L 248.7619 210.14284 L 260.19048 199.66665 Z M 259.2381 194.90475 L 258.28566 195.85716 L 261.14284 198.71428 L 262.09522 197.76187 Z M 261.14286 193 L 260.19042 193.95241 L 263.04762 196.80953 L 264 195.85714 Z M 244 213.72882 C 244 213.72882 247.4281 215.43353 250.8572 213.7288 C 254.28599 212.02405 261.14284 214.86531 261.14284 214.86531 L 261.14284 213.72884 C 261.14284 213.72884 254.28577 210.88755 250.8572 212.5923 C 247.42858 214.29712 244 212.59228 244 212.59228 Z"/></svg>

View File

@@ -0,0 +1,4 @@
title: $:/core/images/home-button
tags: $:/tags/Image
<svg class="tw-image-home-button tw-image-button" viewBox="81 513 64 54" width="22pt" height="22pt"><g><path d="M 97.04536 522.62083 L 81.364685 531.49067 L 87.85863 531.49067 L 87.85863 566.9699 L 107.49902 566.9699 L 107.49902 552.99265 L 117.95268 552.99265 L 117.95268 566.9699 L 137.59307 566.9699 L 137.59307 531.49067 L 144.086885 531.49067 L 112.72591 513.751 L 107.49902 516.70758 L 107.49902 513.751 L 97.04536 513.751 Z M 94.669443 534.17844 L 103.222493 534.17844 L 103.222493 545.19854 L 94.669443 545.19854 Z M 108.449266 534.17844 L 117.002435 534.17844 L 117.002435 545.19854 L 108.449266 545.19854 Z M 122.387575 534.17844 L 130.9405 534.17844 L 130.9405 545.19854 L 122.387575 545.19854 Z"/></g></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/info-button
tags: $:/tags/Image
<svg class="tw-image-info-button tw-image-button" viewBox="294 150 58 58" width="22pt" height="22pt"><path d="M 342.76236 158.98764 C 331.77887 148.0041 313.97113 148.0041 302.98764 158.98764 C 292.0041 169.97113 292.0041 187.77887 302.98764 198.76236 C 313.97113 209.7459 331.77887 209.7459 342.76236 198.76236 C 353.7459 187.77887 353.7459 169.97113 342.76236 158.98764 M 326.5425 157.5 L 326.5425 157.5 C 327.72545 157.5 328.72201 157.91022 329.5337 158.73088 C 330.34465 159.55157 330.75 160.54402 330.75 161.7075 C 330.75 162.87172 330.33979 163.86316 329.51911 164.68385 C 328.69842 165.5045 327.70674 165.91501 326.5425 165.91501 C 325.39801 165.91501 324.4153 165.5045 323.5946 164.68385 C 322.77393 163.86316 322.36372 162.87172 322.36372 161.7075 C 322.36372 160.54402 322.76906 159.55157 323.58 158.73088 C 324.39171 157.91022 325.3793 157.5 326.5425 157.5 Z M 327.80211 190.47259 C 324.91945 195.49132 321.85778 198 318.61462 198 C 317.37452 198 316.38691 197.65158 315.65186 196.9555 C 314.9176 196.25866 314.54943 195.37617 314.54943 194.30782 C 314.54943 193.60202 314.71223 192.70572 315.03629 191.61813 L 319.0151 177.93651 C 319.39685 176.61922 319.58735 175.62754 319.58735 174.95991 C 319.58735 174.53996 319.40582 174.16692 319.04356 173.84286 C 318.68052 173.51905 318.18469 173.35701 317.55527 173.35701 C 317.26861 173.35701 316.92506 173.36677 316.5246 173.38548 L 316.89661 172.2407 L 326.59967 170.66627 L 328.31744 170.66627 L 322.44986 191.01638 C 322.12503 192.18064 321.963 192.94337 321.963 193.30666 C 321.963 193.51588 322.04862 193.71121 322.2204 193.89273 C 322.39218 194.07425 322.5737 194.16554 322.7642 194.16477 C 323.08903 194.16554 323.4131 194.02221 323.73792 193.73559 C 324.59605 193.02976 325.6267 191.75142 326.82838 189.90008 Z"/></svg>

View File

@@ -0,0 +1,4 @@
title: $:/core/images/menu-button
tags: $:/tags/Image
<svg class="tw-image-menu-button tw-image-button" viewBox="216 585 63 45" width="22pt" height="22pt"><g><path d="M 274.5 585 L 229.5 585 C 227.01472 585 225 587.01472 225 589.5 L 225 589.5 C 225 591.98528 227.01472 594 229.5 594 L 274.5 594 C 276.98528 594 279 591.98528 279 589.5 L 279 589.5 C 279 587.01472 276.98528 585 274.5 585 Z"/><path d="M 274.5 603 L 229.5 603 C 227.01472 603 225 605.01472 225 607.5 L 225 607.5 C 225 609.98528 227.01472 612 229.5 612 L 274.5 612 C 276.98528 612 279 609.98528 279 607.5 L 279 607.5 C 279 605.01472 276.98528 603 274.5 603 Z"/><path d="M 274.5 621 L 229.5 621 C 227.01472 621 225 623.01472 225 625.5 L 225 625.5 C 225 627.9853 227.01472 630 229.5 630 L 274.5 630 C 276.98528 630 279 627.9853 279 625.5 L 279 625.5 C 279 623.01472 276.98528 621 274.5 621 Z"/></g></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/new-button
tags: $:/tags/Image
<svg class="tw-image-new-button tw-image-button" viewBox="83 81 50 50" width="22pt" height="22pt"><path d="M 101.25 112.5 L 101.25 127.5 C 101.25 127.5 101.25 127.5 101.25 127.5 L 101.25 127.5 C 101.25 129.156855 102.593146 130.5 104.25 130.5 L 111.75 130.5 C 113.406854 130.5 114.75 129.156854 114.75 127.5 L 114.75 112.5 L 129.75 112.5 C 131.406854 112.5 132.75 111.156854 132.75 109.5 L 132.75 102 C 132.75 100.343146 131.406854 99 129.75 99 L 114.75 99 L 114.75 84 C 114.75 82.343146 113.406854 81 111.75 81 L 104.25 81 C 104.25 81 104.25 81 104.25 81 C 102.593146 81 101.25 82.343146 101.25 84 L 101.25 99 L 86.25 99 C 86.25 99 86.25 99 86.25 99 C 84.593146 99 83.25 100.343146 83.25 102 L 83.25 109.5 C 83.25 109.5 83.25 109.5 83.25 109.5 L 83.25 109.5 C 83.25 111.156855 84.593146 112.5 86.25 112.5 Z"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/options-button
tags: $:/tags/Image
<svg class="tw-image-options-button tw-image-button" viewBox="434 218 68 68" width="22pt" height="22pt"><path d="M 478.39696 232.53705 L 478.39696 232.53705 C 477.11453 231.85132 475.77877 231.30146 474.4106 230.88735 L 474.4106 218.24993 L 461.58944 218.24993 L 461.58944 230.88735 C 460.22126 231.30146 458.8855 231.85132 457.60308 232.53705 L 448.66825 223.60214 L 439.6022 232.66814 L 448.53716 241.60304 C 447.8515 242.88541 447.30158 244.22116 446.88747 245.58935 L 434.25 245.58935 L 434.25 258.41052 L 446.88747 258.41052 C 447.30158 259.7787 447.8515 261.11446 448.53716 262.39689 L 439.6022 271.33173 L 448.66825 280.39779 L 457.60308 271.46281 C 458.8855 272.14862 460.22126 272.69847 461.58944 273.11251 L 461.58944 285.74986 L 474.4106 285.74986 L 474.4106 273.11251 C 475.77877 272.69847 477.11453 272.14862 478.39696 271.46281 L 487.3318 280.39779 L 496.3977 271.33173 L 487.46287 262.39689 C 488.14854 261.11446 488.6984 259.7787 489.11257 258.41052 L 501.7499 258.41052 L 501.7499 245.58935 L 489.11257 245.58935 C 488.6984 244.22116 488.14854 242.88541 487.46287 241.60304 L 496.3977 232.66814 L 487.3318 223.60214 Z M 475.3328 244.66714 C 479.38253 248.71698 479.38253 255.2829 475.3328 259.33273 C 471.28297 263.3826 464.71706 263.3826 460.66723 259.33273 C 456.61737 255.2829 456.61737 248.71698 460.66723 244.66714 C 464.71706 240.61734 471.28297 240.61734 475.3328 244.66714"/></svg>

View File

@@ -1,3 +1,4 @@
title: $:/core/images/save-button
tags: $:/tags/Image
<svg class="tw-image-save-button tw-image-button" viewBox="4 512 64 60" width="22pt" height="21pt"><path d="M 13.5 537.75 L 11.5 537.75 C 11.5 537.75 11.5 537.75 11.5 537.75 C 7.6340064 537.75 4.4999994 540.884 4.5 544.75 L 4.5 564.5 L 4.5 564.5 C 4.5 564.5 4.5 564.5 4.5 564.5 L 4.5 564.5 C 4.5000006 568.366 7.634007 571.5 11.5 571.5 L 60.5 571.5 C 64.365993 571.5 67.5 568.366 67.5 564.5 L 67.5 544.75 C 67.5 540.884 64.365993 537.75 60.5 537.75 L 58.5 537.75 L 49.5 546.75 L 50 546.75 C 52.20914 546.75 54 548.54086 54 550.75 L 54 556.25 C 54 558.45914 52.20914 560.25 50 560.25 L 36 560.25 L 22 560.25 C 19.790861 560.25 18 558.45914 18 556.25 L 18 556.25 C 18 556.25 18 556.25 18 556.25 L 18 550.75 C 18 548.54086 19.790861 546.75 22 546.75 C 22 546.75 22 546.75 22 546.75 L 22.5 546.75 Z"/><path d="M 16.37132 533.87132 L 33.87868 551.37868 C 35.050253 552.55025 36.949747 552.55025 38.12132 551.37868 L 55.62868 533.87132 C 56.800252 532.69975 56.800252 530.80025 55.62868 529.62868 C 55.06607 529.06607 54.30301 528.75 53.50736 528.75 L 48 528.75 C 46.343146 528.75 45 527.40685 45 525.75 L 45 516 C 45 514.34315 43.656854 513 42 513 L 30 513 C 28.343146 513 27 514.34315 27 516 L 27 525.75 C 27 527.40685 25.656854 528.75 24 528.75 L 18.492641 528.75 C 16.835786 528.75 15.492641 530.09315 15.492641 531.75 C 15.492641 532.54565 15.808711 533.3087 16.37132 533.87132 Z"/></svg>

View File

@@ -14,9 +14,9 @@ Appearance/Palette/Editor/Clone/Prompt: It is recommended that you clone this sh
Appearance/Palette/Editor/Prompt/Modified: This shadow palette has been modified
Appearance/Palette/Editor/Prompt: Editing
Appearance/Palette/Editor/Reset/Caption: reset
Appearance/Palette/ShowEditor/Caption: show editor
Appearance/Palette/HideEditor/Caption: hide editor
Appearance/Palette/Prompt: Current palette:
Appearance/Palette/ShowEditor/Caption: show editor
Appearance/StoryView/Caption: Story View
Appearance/StoryView/Prompt: Current view:
Appearance/Theme/Caption: Theme
@@ -40,6 +40,9 @@ Plugins/Caption: Plugins
Plugins/Fields/Description: Description
Plugins/Fields/Title: Title
Plugins/Fields/Version: Version
Plugins/Language/Prompt: Languages
Plugins/Plugin/Prompt: Plugins
Plugins/Theme/Prompt: Themes
Saving/AutoSave/Disabled/Button: enable
Saving/AutoSave/Disabled/Prompt: Autosave is currently disabled
Saving/AutoSave/Enabled/Button: disable

View File

@@ -0,0 +1,100 @@
title: $:/language/Docs/PaletteColours/
alert-background: Alert background
alert-border: Alert border
alert-highlight: Alert highlight
alert-muted-foreground: Alert muted foreground
background: General background
blockquote-bar: Blockquote bar
code-background: Code background
code-border: Code border
code-foreground: Code foreground
download-background: Download button background
download-foreground: Download button foreground
dragger-background: Dragger background
dragger-foreground: Dragger foreground
dropdown-background: Dropdown background
dropdown-border: Dropdown border
dropdown-tab-background-selected: Dropdown tab background for selected tabs
dropdown-tab-background: Dropdown tab background
dropzone-background: Dropzone background
external-link-background-hover: External link background hover
external-link-background-visited: External link background visited
external-link-background: External link background
external-link-foreground-hover: External link foreground hover
external-link-foreground-visited: External link foreground visited
external-link-foreground: External link foreground
foreground: General foreground
message-background: Message box background
message-border: Message box border
message-foreground: Message box foreground
modal-backdrop: Modal backdrop
modal-background: Modal background
modal-border: Modal border
modal-footer-background: Modal footer background
modal-footer-border: Modal footer border
modal-header-border: Modal header border
muted-foreground: General muted foreground
notification-background: Notification background
notification-border: Notification border
page-background: Page background
pre-background: Preformatted code background
pre-border: Preformatted code border
primary: General primary
sidebar-button-foreground: Sidebar button foreground
sidebar-controls-foreground-hover: Sidebar controls foreground hover
sidebar-controls-foreground: Sidebar controls foreground
sidebar-foreground-shadow: Sidebar foreground shadow
sidebar-foreground: Sidebar foreground
sidebar-muted-foreground-hover: Sidebar muted foreground hover
sidebar-muted-foreground: Sidebar muted foreground
sidebar-tab-background-selected: Sidebar tab background for selected tabs
sidebar-tab-background: Sidebar tab background
sidebar-tab-border-selected: Sidebar tab border for selected tabs
sidebar-tab-border: Sidebar tab border
sidebar-tab-divider: Sidebar tab divider
sidebar-tab-foreground-selected: Sidebar tab foreground for selected tabs
sidebar-tab-foreground: Sidebar tab foreground
sidebar-tiddler-link-foreground-hover: Sidebar tiddler link foreground hover
sidebar-tiddler-link-foreground: Sidebar tiddler link foreground
static-alert-foreground: Static alert foreground
tab-background-selected: Tab background for selected tabs
tab-background: Tab background
tab-border-selected: Tab border for selected tabs
tab-border: Tab border
tab-divider: Tab divider
tab-foreground-selected: Tab foreground for selected tabs
tab-foreground: Tab foreground
table-border: Table border
table-footer-background: Table footer background
table-header-background: Table header background
tag-background: Tag background
tag-foreground: Tag foreground
tiddler-background: Tiddler background
tiddler-border: Tiddler border
tiddler-controls-foreground-hover: Tiddler controls foreground hover
tiddler-controls-foreground-selected: Tiddler controls foreground for selected controls
tiddler-controls-foreground: Tiddler controls foreground
tiddler-editor-background: Tiddler editor background
tiddler-editor-border-image: Tiddler editor border image
tiddler-editor-border: Tiddler editor border
tiddler-editor-fields-even: Tiddler editor background for even fields
tiddler-editor-fields-odd: Tiddler editor background for odd fields
tiddler-info-background: Tiddler info panel background
tiddler-info-border: Tiddler info panel border
tiddler-info-tab-background: Tiddler info panel tab background
tiddler-link-background: Tiddler link background
tiddler-link-foreground: Tiddler link foreground
tiddler-subtitle-foreground: Tiddler subtitle foreground
tiddler-title-foreground: Tiddler title foreground
toolbar-new-button: Toolbar 'new tiddler' button foreground
toolbar-options-button: Toolbar 'options' button foreground
toolbar-save-button: Toolbar 'save' button foreground
toolbar-info-button: Toolbar 'info' button foreground
toolbar-edit-button: Toolbar 'edit' button foreground
toolbar-close-button: Toolbar 'close' button foreground
toolbar-delete-button: Toolbar 'delete' button foreground
toolbar-cancel-button: Toolbar 'cancel' button foreground
toolbar-done-button: Toolbar 'done' button foreground
untagged-background: Untagged pill background
very-muted-foreground: Very muted foreground

View File

@@ -1,6 +1,6 @@
title: $:/language/EditTemplate/
Body/Hint: Use WikiText to add formatting, images, and dynamic features
Body/Hint: Use [[wiki text|http://tiddlywiki.com/static/WikiText.html]] to add formatting, images, and dynamic features
Body/Placeholder: Type the text for this tiddler
Body/Preview/Button/Hide: hide preview
Body/Preview/Button/Show: show preview

View File

@@ -16,6 +16,8 @@ hack-to-give-us-something-to-compare-against: A temporary storage field used in
icon: The title of the tiddler containing the icon associated with a tiddler
library: If set to "yes" indicates that a tiddler should be saved as a JavaScript library
list: An ordered list of tiddler titles associated with a tiddler
list-before: If set, the title of a tiddler before which this tiddler should be added to the ordered list of tiddler titles, or at the start of the list if this field is present but empty
list-after: If set, the title of the tiddler after which this tiddler should be added to the ordered list of tiddler titles
modified: The date and time at which a tiddler was last modified
modifier: The tiddler title associated with the person who last modified a tiddler
name: The human readable name associated with a plugin tiddler
@@ -29,4 +31,4 @@ tags: A list of tags associated with a tiddler
text: The body text of a tiddler
title: The unique name of a tiddler
type: The content type of a tiddler
version: Version information for a plugin
version: Version information for a plugin

View File

@@ -0,0 +1,12 @@
title: $:/language/Filters/
AllTiddlers: All tiddlers except system tiddlers
RecentTiddlers: Recently modified tiddlers
AllTags: All tags except system tags
Missing: Missing tiddlers
Drafts: Draft tiddlers
Orphans: Orphan tiddlers
SystemTiddlers: System tiddlers
ShadowTiddlers: Shadow tiddlers
OverriddenShadowTiddlers: Overridden shadow tiddlers
SystemTags: System tags

View File

@@ -12,3 +12,5 @@ To load tiddlers from an encrypted TiddlyWiki file you should first specify the
```
tiddlywiki ./MyWiki --password pa55w0rd --load my_encrypted_wiki.html
```
Note that TiddlyWiki will not load an older version of an already loaded plugin.

View File

@@ -1,4 +1,30 @@
title: $:/language/
RecentChanges/DateFormat: DDth MMM YYYY
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See http://tiddlywiki.com/static/Upgrading.html for more details.
ClassicWarning/Upgrade/Caption: upgrade
CloseAll/Button: close all
ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<<title>>/>"?
ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"?
ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"?
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters and the characters underscore (`_`), hyphen (`-`) and period (`.`)
MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" - click {{$:/core/images/edit-button}} to create
RecentChanges/DateFormat: DDth MMM YYYY
RelativeDate/Future/Days: <<period>> days from now
RelativeDate/Future/Hours: <<period>> hours from now
RelativeDate/Future/Minutes: <<period>> minutes from now
RelativeDate/Future/Months: <<period>> months from now
RelativeDate/Future/Second: 1 second from now
RelativeDate/Future/Seconds: <<period>> seconds from now
RelativeDate/Future/Years: <<period>> years from now
RelativeDate/Past/Days: <<period>> days ago
RelativeDate/Past/Hours: <<period>> hours ago
RelativeDate/Past/Minutes: <<period>> minutes ago
RelativeDate/Past/Months: <<period>> months ago
RelativeDate/Past/Second: 1 second ago
RelativeDate/Past/Seconds: <<period>> seconds ago
RelativeDate/Past/Years: <<period>> years ago
SystemTiddler/Tooltip: This is a system tiddler
TagManager/Colour/Heading: Colour
TagManager/Count/Heading: Count
TagManager/Icon/Heading: Icon
TagManager/Tag/Heading: Tag

View File

@@ -1,5 +1,14 @@
title: $:/language/TiddlerInfo/
Advanced/Caption: Advanced
Advanced/PluginInfo/Empty/Hint: none
Advanced/PluginInfo/Heading: Plugin Details
Advanced/PluginInfo/Hint: This plugin contains the following shadow tiddlers:
Advanced/ShadowInfo/Heading: Shadow Status
Advanced/ShadowInfo/NotShadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is not a shadow tiddler
Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is a shadow tiddler
Advanced/ShadowInfo/Shadow/Source: It is defined in the plugin <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>
Advanced/ShadowInfo/OverriddenShadow/Hint: It is overridden by an ordinary tiddler
Fields/Caption: Fields
List/Caption: List
List/Empty: This tiddler does not have a list

View File

@@ -0,0 +1,3 @@
title: $:/language/Docs/Types/text/html
description: HTML markup
name: text/html

View File

@@ -34,7 +34,7 @@ Command.prototype.execute = function() {
for(var editionIndex=0; editionIndex<editions.length; editionIndex++) {
var editionName = editions[editionIndex];
// Check the edition exists
var editionPath = path.resolve($tw.boot.corePath,$tw.config.editionsPath) + "/" + editionName;
var editionPath = path.resolve($tw.boot.corePath,$tw.config.editionsPath) + path.sep + editionName;
if(!$tw.utils.isDirectory(editionPath)) {
return "Edition '" + editionName + "' not found";
}

View File

@@ -30,8 +30,9 @@ Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename";
}
fs.readFile(this.params[0],"utf8",function(err,data) {
if(err) {
var ext = path.extname(self.params[0]);
fs.readFile(this.params[0],$tw.utils.getTypeEncoding(ext),function(err,data) {
if (err) {
self.callback(err);
} else {
var fields = {title: self.params[0]},
@@ -41,7 +42,7 @@ Command.prototype.execute = function() {
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
} else {
for(var t=0; t<tiddlers.length; t++) {
self.commander.wiki.addTiddler(new $tw.Tiddler(tiddlers[t]));
self.commander.wiki.importTiddler(new $tw.Tiddler(tiddlers[t]));
}
self.callback(null);
}

View File

@@ -95,8 +95,9 @@ SimpleServer.prototype.listen = function(port,host) {
if(username && password) {
// Check they match
if(self.checkCredentials(request,username,password) !== "ALLOWED") {
var servername = state.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5";
response.writeHead(401,"Authentication required",{
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to TiddlyWiki5"'
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to ' + servername + '"'
});
response.end();
return;

View File

@@ -37,4 +37,6 @@ exports.htmlVoidElements = "area,base,br,col,command,embed,hr,img,input,keygen,l
exports.htmlBlockElements = "address,article,aside,audio,blockquote,canvas,dd,div,dl,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,li,noscript,ol,output,p,pre,section,table,tfoot,ul,video".split(",");
exports.htmlUnsafeElements = "script".split(",");
})();

View File

@@ -3,7 +3,7 @@ title: $:/core/modules/filters.js
type: application/javascript
module-type: wikimethod
Adds tiddler filtering to the $tw.Wiki object.
Adds tiddler filtering methods to the $tw.Wiki object.
\*/
(function(){
@@ -149,11 +149,16 @@ exports.getFilterOperators = function() {
return this.filterOperators;
};
exports.filterTiddlers = function(filterString,currTiddlerTitle,tiddlerList) {
exports.filterTiddlers = function(filterString,currTiddlerTitle,source) {
var fn = this.compileFilter(filterString);
return fn.call(this,tiddlerList || this.tiddlers,currTiddlerTitle);
return fn.call(this,source,currTiddlerTitle);
};
/*
Compile a filter into a function with the signature fn(source,currTiddlerTitle) where:
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
currTiddlerTitle: the optional name of the current tiddler
*/
exports.compileFilter = function(filterString) {
var filterParseTree;
try {
@@ -175,10 +180,15 @@ exports.compileFilter = function(filterString) {
var accumulator = source,
results = [];
$tw.utils.each(operation.operators,function(operator) {
var operatorFunction = filterOperators[operator.operator] || filterOperators.field || function(source,operator,operations) {
return ["Filter Error: unknown operator '" + operator.operator + "'"];
},
operand = operator.operand;
var operand = operator.operand,
operatorFunction;
if(!operator.operator) {
operatorFunction = filterOperators.title;
} else if(!filterOperators[operator.operator]) {
operatorFunction = filterOperators.field;
} else {
operatorFunction = filterOperators[operator.operator];
}
if(operator.indirect) {
operand = self.getTextReference(operator.operand,"",currTiddlerTitle);
}
@@ -192,7 +202,7 @@ exports.compileFilter = function(filterString) {
wiki: self,
currTiddlerTitle: currTiddlerTitle
});
accumulator = results;
accumulator = self.makeTiddlerIterator(results);
});
return results;
};
@@ -210,22 +220,26 @@ exports.compileFilter = function(filterString) {
case "+": // This operation is applied to the main results so far
return function(results,source,currTiddlerTitle) {
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
source = results.slice(0);
source = self.makeTiddlerIterator(results);
results.splice(0,results.length);
$tw.utils.pushTop(results,operationSubFunction(source,currTiddlerTitle));
};
}
})());
});
// Return a function that applies the operations to a source array/hashmap of tiddler titles
return function(source,currTiddlerTitle) {
source = source || self.tiddlers;
// Return a function that applies the operations to a source iterator of tiddler titles
return $tw.perf.measure("filter",function filterFunction(source,currTiddlerTitle) {
if(!source) {
source = self.each;
} else if(typeof source === "object") { // Array or hashmap
source = self.makeTiddlerIterator(source);
}
var results = [];
$tw.utils.each(operationFunctions,function(operationFunction) {
operationFunction(results,source,currTiddlerTitle);
});
return results;
};
});
};
})();

View File

@@ -0,0 +1,45 @@
/*\
title: $:/core/modules/filters/all.js
type: application/javascript
module-type: filteroperator
Filter operator for selecting tiddlers
[all[shadows+tiddlers]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var allFilterOperators;
function getAllFilterOperators() {
if(!allFilterOperators) {
allFilterOperators = {};
$tw.modules.applyMethods("allfilteroperator",allFilterOperators);
}
return allFilterOperators;
}
/*
Export our filter function
*/
exports.all = function(source,operator,options) {
// Get our suboperators
var allFilterOperators = getAllFilterOperators();
// Cycle through the suboperators accumulating their results
var results = [],
subops = operator.operand.split("+");
for(var t=0; t<subops.length; t++) {
var subop = allFilterOperators[subops[t]];
if(subop) {
$tw.utils.pushTop(results,subop(source,operator.prefix,options));
}
}
return results;
};
})();

View File

@@ -0,0 +1,26 @@
/*\
title: $:/core/modules/filters/all/current.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[current]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.current = function(source,prefix,options) {
if(options.currTiddlerTitle) {
return [options.currTiddlerTitle];
} else {
return [];
}
};
})();

View File

@@ -0,0 +1,22 @@
/*\
title: $:/core/modules/filters/all/missing.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[missing]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.missing = function(source,prefix,options) {
return options.wiki.getMissingTitles();
};
})();

View File

@@ -0,0 +1,22 @@
/*\
title: $:/core/modules/filters/all/orphans.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[orphans]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.orphans = function(source,prefix,options) {
return options.wiki.getOrphanTitles();
};
})();

View File

@@ -0,0 +1,22 @@
/*\
title: $:/core/modules/filters/all/shadows.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[shadows]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.shadows = function(source,prefix,options) {
return options.wiki.allShadowTitles();
};
})();

View File

@@ -0,0 +1,22 @@
/*\
title: $:/core/modules/filters/all/tiddlers.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[tiddlers]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.tiddlers = function(source,prefix,options) {
return options.wiki.allTitles();
};
})();

View File

@@ -17,20 +17,9 @@ Export our filter function
*/
exports.backlinks = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
source(function(tiddler,title) {
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -16,18 +16,9 @@ Filter operator that selects one tiddler for each unique value of the specified
Export our filter function
*/
exports.each = function(source,operator,options) {
// Convert the source to an array if necessary
if(!$tw.utils.isArray(source)) {
var copy = [];
$tw.utils.each(source,function(element,title) {
copy.push(title);
});
source = copy;
}
// Collect up the first tiddler with each unique value of the specified field
var results = [],values = {};
$tw.utils.each(source,function(title) {
var tiddler = options.wiki.getTiddler(title);
var results = [],
values = {};
source(function(tiddler,title) {
if(tiddler) {
var value = tiddler.getFieldString(operator.operand);
if(!$tw.utils.hop(values,value)) {

View File

@@ -16,23 +16,14 @@ Filter operator that selects one tiddler for each unique day covered by the spec
Export our filter function
*/
exports.eachday = function(source,operator,options) {
var results = [],
values = [];
// Function to convert a date/time to a date integer
var toDate = function(value) {
value = (new Date(value)).setHours(0,0,0,0);
return value+0;
};
// Convert the source to an array if necessary
if(!$tw.utils.isArray(source)) {
var copy = [];
$tw.utils.each(source,function(element,title) {
copy.push(title);
});
source = copy;
}
// Collect up the first tiddler with each unique day value of the specified field
var results = [],values = [];
$tw.utils.each(source,function(title) {
var tiddler = options.wiki.getTiddler(title);
source(function(tiddler,title) {
if(tiddler && tiddler.fields[operator.operand]) {
var value = toDate(tiddler.fields[operator.operand]);
if(values.indexOf(value) === -1) {

View File

@@ -17,36 +17,47 @@ Export our filter function
*/
exports.field = function(source,operator,options) {
var results = [],
fieldname = (operator.suffix || operator.operator).toLowerCase(),
isTitle = fieldname === "title";
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title),
text = tiddler ? tiddler.getFieldString(fieldname) : (isTitle ? title : null),
match;
if(text !== null) {
if(operator.regexp) {
match = !!operator.regexp.exec(text);
} else {
match = text === operator.operand;
}
if(operator.prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
if(operator.prefix === "!") {
if(operator.regexp) {
source(function(tiddler,title) {
if(tiddler) {
var text = tiddler.getFieldString(fieldname);
if(text !== null && !operator.regexp.exec(text)) {
results.push(title);
}
}
});
} else {
source(function(tiddler,title) {
if(tiddler) {
var text = tiddler.getFieldString(fieldname);
if(text !== null && text !== operator.operand) {
results.push(title);
}
}
});
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
if(operator.regexp) {
source(function(tiddler,title) {
if(tiddler) {
var text = tiddler.getFieldString(fieldname);
if(text !== null && !!operator.regexp.exec(text)) {
results.push(title);
}
}
});
} else {
source(function(tiddler,title) {
if(tiddler) {
var text = tiddler.getFieldString(fieldname);
if(text !== null && text === operator.operand) {
results.push(title);
}
}
});
}
}
return results;
};

View File

@@ -16,28 +16,14 @@ Filter operator for returning the names of the fields on the selected tiddlers
Export our filter function
*/
exports.fields = function(source,operator,options) {
var self = this,
results = [];
// Function to check an individual title
function checkTiddler(title) {
// Return the fields on the specified tiddler
var tiddler = options.wiki.getTiddler(title);
var results = [];
source(function(tiddler,title) {
if(tiddler) {
for(var fieldName in tiddler.fields) {
$tw.utils.pushTop(results,fieldName);
}
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -17,27 +17,17 @@ Export our filter function
*/
exports.has = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title);
if(tiddler) {
var match = $tw.utils.hop(tiddler.fields,operator.operand) && tiddler.fields[operator.operand] !== "";
if(operator.prefix === "!") {
match = !match;
}
if(match) {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(tiddler && (!$tw.utils.hop(tiddler.fields,operator.operand) || tiddler.fields[operator.operand] === "")) {
results.push(title);
}
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
source(function(tiddler,title) {
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && tiddler.fields[operator.operand] !== "") {
results.push(title);
}
});
}
return results;

View File

@@ -16,26 +16,13 @@ Filter operator for returning the indexes of a data tiddler
Export our filter function
*/
exports.indexes = function(source,operator,options) {
var self = this,
results = [];
// Function to check an individual title
function checkTiddler(title) {
// Return the fields on the specified tiddler
var data = options.wiki.getTiddlerData(title,{});
var results = [];
source(function(tiddler,title) {
var data = options.wiki.getTiddlerData(title);
if(data) {
$tw.utils.pushTop(results,Object.keys(data));
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
results.sort();
return results;
};

View File

@@ -17,31 +17,18 @@ Export our filter function
*/
exports.current = function(source,prefix,options) {
var results = [];
// Function to check a tiddler
function checkTiddler(title) {
if(title !== options.currTiddlerTitle) {
results.push(title);
}
};
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
if(prefix === "!") {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
if(source.indexOf(options.currTiddlerTitle) !== -1) {
results.push(options.currTiddlerTitle);
if(prefix === "!") {
source(function(tiddler,title) {
if(title !== options.currTiddlerTitle) {
results.push(title);
}
}
});
} else {
if(prefix === "!") {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
} else {
results.push(options.currTiddlerTitle);
}
source(function(tiddler,title) {
if(title === options.currTiddlerTitle) {
results.push(title);
}
});
}
return results;
};

View File

@@ -17,24 +17,17 @@ Export our filter function
*/
exports.image = function(source,prefix,options) {
var results = [];
// Function to check a tiddler
function checkTiddler(title) {
var match = options.wiki.isImageTiddler(title);
if(prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
};
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
if(prefix === "!") {
source(function(tiddler,title) {
if(!options.wiki.isImageTiddler(title)) {
results.push(title);
}
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
source(function(tiddler,title) {
if(options.wiki.isImageTiddler(title)) {
results.push(title);
}
});
}
return results;

View File

@@ -16,31 +16,19 @@ Filter function for [is[missing]]
Export our filter function
*/
exports.missing = function(source,prefix,options) {
var results = [],
missingTitles;
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
missingTitles = options.wiki.getMissingTitles();
$tw.utils.each(source,function(title) {
var match = missingTitles.indexOf(title) !== -1;
if(prefix === "!") {
match = !match;
}
if(match) {
var results = [];
if(prefix === "!") {
source(function(tiddler,title) {
if(options.wiki.tiddlerExists(title)) {
results.push(title);
}
});
} else {
if(prefix !== "!") {
missingTitles = options.wiki.getMissingTitles();
$tw.utils.each(missingTitles,function(title) {
source(function(tiddler,title) {
if(!options.wiki.tiddlerExists(title)) {
results.push(title);
});
} else {
$tw.utils.each(source,function(element,title) {
results.push(title);
});
}
}
});
}
return results;
};

View File

@@ -18,24 +18,15 @@ Export our filter function
exports.orphan = function(source,prefix,options) {
var results = [],
orphanTitles = options.wiki.getOrphanTitles();
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
var match = orphanTitles.indexOf(title) !== -1;
if(prefix === "!") {
match = !match;
}
if(match) {
if(prefix === "!") {
source(function(tiddler,title) {
if(orphanTitles.indexOf(title) === -1) {
results.push(title);
}
});
} else {
$tw.utils.each(source,function(element,title) {
var match = orphanTitles.indexOf(title) !== -1;
if(prefix === "!") {
match = !match;
}
if(match) {
source(function(tiddler,title) {
if(orphanTitles.indexOf(title) !== -1) {
results.push(title);
}
});

View File

@@ -17,31 +17,18 @@ Export our filter function
*/
exports.shadow = function(source,prefix,options) {
var results = [];
// Function to check a tiddler
function checkTiddler(title) {
var match = options.wiki.isShadowTiddler(title);
if(prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
};
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
if(prefix === "!") {
source(function(tiddler,title) {
if(!options.wiki.isShadowTiddler(title)) {
results.push(title);
}
});
} else {
if(prefix !== "!") {
$tw.utils.each(options.wiki.shadowTiddlers,function(tiddler,title) {
source(function(tiddler,title) {
if(options.wiki.isShadowTiddler(title)) {
results.push(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
}
});
}
return results;
};

View File

@@ -17,24 +17,17 @@ Export our filter function
*/
exports.system = function(source,prefix,options) {
var results = [];
// Function to check a tiddler
function checkTiddler(title) {
var match = options.wiki.isSystemTiddler(title);
if(prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
};
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
if(prefix === "!") {
source(function(tiddler,title) {
if(!options.wiki.isSystemTiddler(title)) {
results.push(title);
}
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
source(function(tiddler,title) {
if(options.wiki.isSystemTiddler(title)) {
results.push(title);
}
});
}
return results;

View File

@@ -0,0 +1,37 @@
/*\
title: $:/core/modules/filters/is/tag.js
type: application/javascript
module-type: isfilteroperator
Filter function for [is[tag]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.tag = function(source,prefix,options) {
var results = [],
tagMap = options.wiki.getTagMap();
if(prefix === "!") {
source(function(tiddler,title) {
if(!$tw.utils.hop(tagMap,title)) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if($tw.utils.hop(tagMap,title)) {
results.push(title);
}
});
}
return results;
};
})();

View File

@@ -17,24 +17,17 @@ Export our filter function
*/
exports.tiddler = function(source,prefix,options) {
var results = [];
// Function to check a tiddler
function checkTiddler(title) {
var match = options.wiki.tiddlerExists(title);
if(prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
};
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
if(prefix === "!") {
source(function(tiddler,title) {
if(!options.wiki.tiddlerExists(title)) {
results.push(title);
}
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
source(function(tiddler,title) {
if(options.wiki.tiddlerExists(title)) {
results.push(title);
}
});
}
return results;

View File

@@ -17,20 +17,16 @@ Export our filter function
*/
exports.limit = function(source,operator,options) {
var results = [];
// Convert to an array if necessary
if(!$tw.utils.isArray(source)) {
var copy = [];
$tw.utils.each(source,function(element,title) {
copy.push(title);
});
source = copy;
}
// Convert to an array
source(function(tiddler,title) {
results.push(title);
});
// Slice the array if necessary
var limit = Math.min(source.length,parseInt(operator.operand,10));
var limit = Math.min(results.length,parseInt(operator.operand,10));
if(operator.prefix === "!") {
results = source.slice(source.length - limit);
results = results.slice(-limit);
} else {
results = source.slice(0,limit);
results = results.slice(0,limit);
}
return results;
};

View File

@@ -17,20 +17,9 @@ Export our filter function
*/
exports.links = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
source(function(tiddler,title) {
$tw.utils.pushTop(results,options.wiki.getTiddlerLinks(title));
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -19,28 +19,14 @@ exports.list = function(source,operator,options) {
var results = [],
tr = $tw.utils.parseTextReference(operator.operand),
list = options.wiki.getTiddlerList(tr.title || options.currTiddlerTitle,tr.field,tr.index);
function checkTiddler(title) {
var match = list.indexOf(title) !== -1;
if(operator.prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(list.indexOf(title) === -1) {
results.push(title);
}
});
} else {
if(operator.prefix !== "!") {
results = list;
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
results = list;
}
return results;
};

View File

@@ -17,20 +17,9 @@ Export our filter function
*/
exports.listed = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
source(function(tiddler,title) {
$tw.utils.pushTop(results,options.wiki.findListingsOfTiddler(title));
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -17,10 +17,7 @@ Reverse list
*/
exports.reverse = function(source,operator,options) {
var results = [];
if(!$tw.utils.isArray(source)) {
source = Object.keys(source).sort();
}
$tw.utils.each(source,function(title) {
source(function(tiddler,title) {
results.unshift(title);
});
return results;
@@ -30,33 +27,36 @@ exports.reverse = function(source,operator,options) {
First entry/entries in list
*/
exports.first = function(source,operator,options) {
var count = parseInt(operator.operand) || 1;
if(!$tw.utils.isArray(source)) {
source = Object.keys(source).sort();
}
return source.slice(0,Math.min(count,source.length));
var count = parseInt(operator.operand) || 1,
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(0,count);
};
/*
Last entry/entries in list
*/
exports.last = function(source,operator,options) {
var count = parseInt(operator.operand) || 1;
if(!$tw.utils.isArray(source)) {
source = Object.keys(source).sort();
}
return source.slice(-count);
var count = parseInt(operator.operand) || 1,
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(-count);
};
/*
All but the first entry/entries of the list
*/
exports.rest = function(source,operator,options) {
var count = parseInt(operator.operand) || 1;
if(!$tw.utils.isArray(source)) {
source = Object.keys(source).sort();
}
return source.slice(count);
var count = parseInt(operator.operand) || 1,
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(count);
};
exports.butfirst = exports.rest;
exports.bf = exports.rest;
@@ -65,11 +65,12 @@ exports.bf = exports.rest;
All but the last entry/entries of the list
*/
exports.butlast = function(source,operator,options) {
var count = parseInt(operator.operand) || 1;
if(!$tw.utils.isArray(source)) {
source = Object.keys(source).sort();
}
return source.slice(0,-count);
var count = parseInt(operator.operand) || 1,
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(0,-count);
};
exports.bl = exports.butlast;
@@ -77,11 +78,12 @@ exports.bl = exports.butlast;
The nth member of the list
*/
exports.nth = function(source,operator,options) {
var count = parseInt(operator.operand) || 1;
if(!$tw.utils.isArray(source)) {
source = Object.keys(source).sort();
}
return source.slice(count-1,count);
var count = parseInt(operator.operand) || 1,
results = [];
source(function(tiddler,title) {
results.push(title);
});
return results.slice(count - 1,count);
};
})();

View File

@@ -16,22 +16,12 @@ Filter operator for returning the titles of the modules of a given type in this
Export our filter function
*/
exports.modules = function(source,operator,options) {
var results = [],
pushModules = function(type) {
$tw.utils.each($tw.modules.types[type],function(moduleInfo,moduleName) {
results.push(moduleName);
});
};
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
pushModules(title);
var results = [];
source(function(tiddler,title) {
$tw.utils.each($tw.modules.types[title],function(moduleInfo,moduleName) {
results.push(moduleName);
});
} else {
$tw.utils.each(source,function(element,title) {
pushModules(title);
});
}
});
results.sort();
return results;
};

View File

@@ -18,25 +18,14 @@ Export our filter function
exports.next = function(source,operator,options) {
var results = [],
list = options.wiki.getTiddlerList(operator.operand);
function checkTiddler(title) {
source(function(tiddler,title) {
var match = list.indexOf(title);
// increment match and then test if result is in range
match++;
if(match > 0 && match < list.length) {
results.push(list[match]);
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -0,0 +1,32 @@
/*\
title: $:/core/modules/filters/plugintiddlers.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the titles of the shadow tiddlers within a plugin
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.plugintiddlers = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
var pluginInfo = options.wiki.getPluginInfo(title);
if(pluginInfo) {
$tw.utils.each(pluginInfo.tiddlers,function(fields,title) {
results.push(title);
});
}
});
results.sort();
return results;
};
})();

View File

@@ -17,24 +17,17 @@ Export our filter function
*/
exports.prefix = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
var match = title.substr(0,operator.operand.length).toLowerCase() === operator.operand.toLowerCase();
if(operator.prefix === "!") {
match = !match;
}
if(match) {
results.push(title);
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title.substr(0,operator.operand.length).toLowerCase() !== operator.operand.toLowerCase()) {
results.push(title);
}
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
source(function(tiddler,title) {
if(title.substr(0,operator.operand.length).toLowerCase() === operator.operand.toLowerCase()) {
results.push(title);
}
});
}
return results;

View File

@@ -18,25 +18,14 @@ Export our filter function
exports.previous = function(source,operator,options) {
var results = [],
list = options.wiki.getTiddlerList(operator.operand);
function checkTiddler(title) {
source(function(tiddler,title) {
var match = list.indexOf(title);
// decrement match and then test if result is in range
// increment match and then test if result is in range
match--;
if( match >= 0 ) {
if(match >= 0) {
results.push(list[match]);
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -0,0 +1,28 @@
/*\
title: $:/core/modules/filters/removeprefix.js
type: application/javascript
module-type: filteroperator
Filter operator for removing a prefix from each title in the list. Titles that do not start with the prefix are removed.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.removeprefix = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
if(title.substr(0,operator.operand.length).toLowerCase() === operator.operand.toLowerCase()) {
results.push(title.substr(operator.operand.length));
}
});
return results;
};
})();

View File

@@ -17,34 +17,19 @@ Export our filter function
*/
exports.sameday = function(source,operator,options) {
var results = [],
isSameDay = function(dateField,dateString) {
var date1 = (new Date(dateField)).setHours(0,0,0,0),
date2 = (new Date($tw.utils.parseDate(dateString))).setHours(0,0,0,0);
return date1 === date2;
fieldName = operator.suffix || "modified",
targetDate = (new Date($tw.utils.parseDate(operator.operand))).setHours(0,0,0,0);
// Function to convert a date/time to a date integer
var isSameDay = function(dateField) {
return (new Date(dateField)).setHours(0,0,0,0) === targetDate;
};
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title);
if(tiddler) {
var match = isSameDay(tiddler.fields.modified,operator.operand);
if(operator.prefix === "!") {
match = !match;
}
if(match) {
source(function(tiddler,title) {
if(tiddler && tiddler.fields[fieldName]) {
if(isSameDay(tiddler.fields[fieldName])) {
results.push(title);
}
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -18,7 +18,7 @@ Export our filter function
exports.search = function(source,operator,options) {
var invert = operator.prefix === "!";
return options.wiki.search(operator.operand,{
titles: source,
source: source,
invert: invert
});
};

View File

@@ -0,0 +1,30 @@
/*\
title: $:/core/modules/filters/shadowsource.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the source plugins for shadow tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.shadowsource = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
var source = options.wiki.getShadowSource(title);
if(source) {
$tw.utils.pushTop(results,source);
}
});
results.sort();
return results;
};
})();

View File

@@ -17,38 +17,33 @@ Export our filter function
*/
exports.sort = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",false,false);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
return results;
};
exports.nsort = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",false,true);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
return results;
};
exports.sortcs = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",true,false);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
return results;
};
exports.nsortcs = function(source,operator,options) {
var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",true,true);
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
return results;
};
var prepare_results = function (source) {
var results;
if($tw.utils.isArray(source)) {
results = source;
} else {
results = [];
$tw.utils.each(source,function(element,title) {
results.push(title);
});
}
var results = [];
source(function(tiddler,title) {
results.push(title);
});
return results;
}

View File

@@ -17,31 +17,18 @@ Export our filter function
*/
exports.tag = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title);
if(tiddler) {
var match = tiddler.hasTag(operator.operand);
if(operator.prefix === "!") {
match = !match;
}
if(match) {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(tiddler && !tiddler.hasTag(operator.operand)) {
results.push(title);
}
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
source(function(tiddler,title) {
if(tiddler && tiddler.hasTag(operator.operand)) {
results.push(title);
}
});
}
// Sort the results if we are matching a tag
if(operator.prefix !== "!") {
results = options.wiki.sortByList(results,operator.operand);
}
return results;

View File

@@ -17,20 +17,9 @@ Export our filter function
*/
exports.tagging = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
source(function(tiddler,title) {
$tw.utils.pushTop(results,options.wiki.getTiddlersWithTag(title));
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -17,23 +17,11 @@ Export our filter function
*/
exports.tags = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title);
source(function(tiddler,title) {
if(tiddler && tiddler.fields.tags) {
$tw.utils.pushTop(results,tiddler.fields.tags);
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
});
}
});
return results;
};

View File

@@ -17,35 +17,14 @@ Export our filter function
*/
exports.title = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title);
if(tiddler) {
var match = tiddler.fields[operator.operator] === operator.operand;
if(operator.prefix === "!") {
match = !match;
}
if(match) {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(tiddler && tiddler.fields.title !== operator.operand) {
results.push(title);
}
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
});
} else {
// If we're filtering a hashmap we change the behaviour to pass through missing tiddlers
if(operator.prefix !== "!") {
results.push(operator.operand);
} else {
$tw.utils.each(source,function(element,title) {
if(title !== operator.operand) {
checkTiddler(title);
}
});
}
results.push(operator.operand);
}
return results;
};

View File

@@ -17,25 +17,17 @@ Export our filter function
*/
exports.untagged = function(source,operator,options) {
var results = [];
// Function to check an individual title
function checkTiddler(title) {
var tiddler = options.wiki.getTiddler(title),
match = tiddler && $tw.utils.isArray(tiddler.fields.tags) && tiddler.fields.tags.length > 0;
if(operator.prefix !== "!") {
match = !match;
}
if(match) {
$tw.utils.pushTop(results,title);
}
}
// Iterate through the source tiddlers
if($tw.utils.isArray(source)) {
$tw.utils.each(source,function(title) {
checkTiddler(title);
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 {
$tw.utils.each(source,function(element,title) {
checkTiddler(title);
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);
}
});
}
return results;

37
core/modules/language.js Normal file
View File

@@ -0,0 +1,37 @@
/*\
title: $:/core/modules/language.js
type: application/javascript
module-type: global
The $tw.Language() manages translateable strings
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Create an instance of the language manager. Options include:
wiki: wiki from which to retrieve translation tiddlers
*/
function Language(options) {
options = options || "";
this.wiki = options.wiki || $tw.wiki;
}
/*
Return a single translateable string. The title is automatically prefixed with "$:/language/"
Options include:
variables: optional hashmap of variables to supply to the language wikification
*/
Language.prototype.getString = function(title,options) {
options = options || {};
title = "$:/language/" + title;
return this.wiki.renderTiddler("text/plain",title,{variables: options.variables});
};
exports.Language = Language;
})();

View File

@@ -0,0 +1,53 @@
/*\
title: $:/core/modules/parsers/csvparser.js
type: application/javascript
module-type: parser
The CSV text parser processes CSV files into a table wrapped in a scrollable widget
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var CsvParser = function(type,text,options) {
// Table framework
this.tree = [{
"type": "element", "tag": "$scrollable", "children": [{
"type": "element", "tag": "table", "children": [{
"type": "element", "tag": "tbody", "children": []
}], "attributes": {
"class": {"type": "string", "value": "tw-csv-table"}
}
}]
}];
// Split the text into lines
var lines = text.split(/\r?\n/mg),
tag = "th";
for(var line=0; line<lines.length; line++) {
var lineText = lines[line];
if(lineText) {
var row = {
"type": "element", "tag": "tr", "children": []
};
var columns = lineText.split(",");
for(var column=0; column<columns.length; column++) {
row.children.push({
"type": "element", "tag": tag, "children": [{
"type": "text",
"text": columns[column]
}]
});
}
tag = "td";
this.tree[0].children[0].children[0].children.push(row);
}
}
};
exports["text/csv"] = CsvParser;
})();

View File

@@ -0,0 +1,268 @@
/*\
title: $:/core/modules/utils/parseutils.js
type: application/javascript
module-type: utils
Utility functions concerned with parsing text into tokens.
Most functions have the following pattern:
* The parameters are:
** `source`: the source string being parsed
** `pos`: the current parse position within the string
** Any further parameters are used to identify the token that is being parsed
* The return value is:
** null if the token was not found at the specified position
** an object representing the token with the following standard fields:
*** `type`: string indicating the type of the token
*** `start`: start position of the token in the source string
*** `end`: end position of the token in the source string
*** Any further fields required to describe the token
The exception is `skipWhiteSpace`, which just returns the position after the whitespace.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Look for a whitespace token. Returns null if not found, otherwise returns {type: "whitespace", start:, end:,}
*/
exports.parseWhiteSpace = function(source,pos) {
var node = {
type: "whitespace",
start: pos
};
var re = /(\s)+/g;
re.lastIndex = pos;
var match = re.exec(source);
if(match && match.index === pos) {
node.end = pos + match[0].length;
return node;
}
return null;
};
/*
Convenience wrapper for parseWhiteSpace. Returns the position after the whitespace
*/
exports.skipWhiteSpace = function(source,pos) {
var whitespace = $tw.utils.parseWhiteSpace(source,pos);
if(whitespace) {
return whitespace.end;
}
return pos;
};
/*
Look for a given string token. Returns null if not found, otherwise returns {type: "token", value:, start:, end:,}
*/
exports.parseTokenString = function(source,pos,token) {
var match = source.indexOf(token,pos) === pos;
if(match) {
return {
type: "token",
value: token,
start: pos,
end: pos + token.length
};
}
return null;
};
/*
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
*/
exports.parseTokenRegExp = function(source,pos,reToken) {
var node = {
type: "regexp",
start: pos
};
reToken.lastIndex = pos;
node.match = reToken.exec(source);
if(node.match && node.match.index === pos) {
node.end = pos + node.match[0].length;
return node;
} else {
return null;
}
};
/*
Look for a string literal. Returns null if not found, otherwise returns {type: "string", value:, start:, end:,}
*/
exports.parseStringLiteral = function(source,pos) {
var node = {
type: "string",
start: pos
};
var reString = /(?:"([^"]*)")|(?:'([^']*)')/g;
reString.lastIndex = pos;
var match = reString.exec(source);
if(match && match.index === pos) {
node.value = match[1] === undefined ? match[2] : match[1];
node.end = pos + match[0].length;
return node;
} else {
return null;
}
};
/*
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
*/
exports.parseMacroParameter = function(source,pos) {
var node = {
type: "macro-parameter",
start: pos
};
// Define our regexp
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^\s>"'=]+)))/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the parameter
var token = $tw.utils.parseTokenRegExp(source,pos,reMacroParameter);
if(!token) {
return null;
}
pos = token.end;
// Get the parameter details
node.value = token.match[2] !== undefined ? token.match[2] : (
token.match[3] !== undefined ? token.match[3] : (
token.match[4] !== undefined ? token.match[4] : (
token.match[5] !== undefined ? token.match[5] : (
""
)
)
)
);
if(token.match[1]) {
node.name = token.match[1];
}
// Update the end position
node.end = pos;
return node;
};
/*
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
*/
exports.parseMacroInvocation = function(source,pos) {
var node = {
type: "macrocall",
start: pos,
params: []
};
// Define our regexps
var reMacroName = /([^\s>"'=]+)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double less than sign
var token = $tw.utils.parseTokenString(source,pos,"<<");
if(!token) {
return null;
}
pos = token.end;
// Get the macro name
var name = $tw.utils.parseTokenRegExp(source,pos,reMacroName);
if(!name) {
return null;
}
node.name = name.match[1];
pos = name.end;
// Process parameters
var parameter = $tw.utils.parseMacroParameter(source,pos);
while(parameter) {
node.params.push(parameter);
pos = parameter.end;
// Get the next parameter
parameter = $tw.utils.parseMacroParameter(source,pos);
}
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double greater than sign
token = $tw.utils.parseTokenString(source,pos,">>");
if(!token) {
return null;
}
pos = token.end;
// Update the end position
node.end = pos;
return node;
};
/*
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
*/
exports.parseAttribute = function(source,pos) {
var node = {
start: pos
};
// Define our regexps
var reAttributeName = /([^\/\s>"'=]+)/g,
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the attribute name
var name = $tw.utils.parseTokenRegExp(source,pos,reAttributeName);
if(!name) {
return null;
}
node.name = name.match[1];
pos = name.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for an equals sign
var token = $tw.utils.parseTokenString(source,pos,"=");
if(token) {
pos = token.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
} else {
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
node.type = "string";
node.value = "true";
}
}
}
}
} else {
node.type = "string";
node.value = "true";
}
// Update the end position
node.end = pos;
return node;
};
})();

View File

@@ -26,7 +26,7 @@ exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /~?(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s'"<>]+(?:\/|\b)/mg;
this.matchRegExp = /~?(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|'"\\^~]+(?:\/|\b)/mg;
};
exports.parse = function() {

View File

@@ -36,7 +36,7 @@ exports.parse = function() {
// Return the heading
return [{
type: "element",
tag: "h" + this.match[1].length,
tag: "h" + headingLevel,
attributes: {
"class": {type: "string", value: classes.join(" ")}
},

View File

@@ -48,7 +48,7 @@ exports.parse = function() {
// Advance the parser position to past the tag
this.parser.pos = tag.end;
// Check for an immediately following double linebreak
var hasLineBreak = !tag.isSelfClosing && !!this.parseTokenRegExp(this.parser.source,this.parser.pos,/(\r?\n(?:\r?\n|$))/g);
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
// Set whether we're in block mode
tag.isBlock = this.is.block || hasLineBreak;
// Parse the body if we need to
@@ -71,244 +71,7 @@ exports.parse = function() {
};
/*
Look for a whitespace token. Returns null if not found, otherwise returns {type: "whitespace", start:, end:,}
*/
exports.parseWhiteSpace = function(source,pos) {
var node = {
type: "whitespace",
start: pos
};
var re = /(\s)+/g;
re.lastIndex = pos;
var match = re.exec(source);
if(match && match.index === pos) {
node.end = pos + match[0].length;
return node;
}
return null;
};
/*
Convenience wrapper for parseWhiteSpace
*/
exports.skipWhiteSpace = function(source,pos) {
var whitespace = this.parseWhiteSpace(source,pos);
if(whitespace) {
return whitespace.end;
}
return pos;
};
/*
Look for a given string token. Returns null if not found, otherwise returns {type: "token", value:, start:, end:,}
*/
exports.parseTokenString = function(source,pos,token) {
var match = source.indexOf(token,pos) === pos;
if(match) {
return {
type: "token",
value: token,
start: pos,
end: pos + token.length
};
}
return null;
};
/*
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
*/
exports.parseTokenRegExp = function(source,pos,reToken) {
var node = {
type: "regexp",
start: pos
};
reToken.lastIndex = pos;
node.match = reToken.exec(source);
if(node.match && node.match.index === pos) {
node.end = pos + node.match[0].length;
return node;
} else {
return null;
}
};
/*
Look for a string literal. Returns null if not found, otherwise returns {type: "string", value:, start:, end:,}
*/
exports.parseStringLiteral = function(source,pos) {
var node = {
type: "string",
start: pos
};
var reString = /(?:"([^"]*)")|(?:'([^']*)')/g;
reString.lastIndex = pos;
var match = reString.exec(source);
if(match && match.index === pos) {
node.value = match[1] === undefined ? match[2] : match[1];
node.end = pos + match[0].length;
return node;
} else {
return null;
}
};
/*
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
*/
exports.parseMacroParameter = function(source,pos) {
var node = {
type: "macro-parameter",
start: pos
};
// Define our regexp
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^\s>"'=]+)))/g;
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
// Look for the parameter
var token = this.parseTokenRegExp(source,pos,reMacroParameter);
if(!token) {
return null;
}
pos = token.end;
// Get the parameter details
node.value = token.match[2] !== undefined ? token.match[2] : (
token.match[3] !== undefined ? token.match[3] : (
token.match[4] !== undefined ? token.match[4] : (
token.match[5] !== undefined ? token.match[5] : (
""
)
)
)
);
if(token.match[1]) {
node.name = token.match[1];
}
// Update the end position
node.end = pos;
return node;
};
/*
Look for a macro invocation. Returns null if not found, or {type: "macrocall", name:, parameters:, start:, end:}
*/
exports.parseMacroInvocation = function(source,pos) {
var node = {
type: "macrocall",
start: pos,
params: []
};
// Define our regexps
var reMacroName = /([^\s>"'=]+)/g;
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
// Look for a double less than sign
var token = this.parseTokenString(source,pos,"<<");
if(!token) {
return null;
}
pos = token.end;
// Get the macro name
var name = this.parseTokenRegExp(source,pos,reMacroName);
if(!name) {
return null;
}
node.name = name.match[1];
pos = name.end;
// Process parameters
var parameter = this.parseMacroParameter(source,pos);
while(parameter) {
node.params.push(parameter);
pos = parameter.end;
// Get the next parameter
parameter = this.parseMacroParameter(source,pos);
}
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
// Look for a double greater than sign
token = this.parseTokenString(source,pos,">>");
if(!token) {
return null;
}
pos = token.end;
// Update the end position
node.end = pos;
return node;
};
/*
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, valueType: "string|indirect|macro", value:, start:, end:,}
*/
exports.parseAttribute = function(source,pos) {
var node = {
start: pos
};
// Define our regexps
var reAttributeName = /([^\/\s>"'=]+)/g,
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g;
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
// Get the attribute name
var name = this.parseTokenRegExp(source,pos,reAttributeName);
if(!name) {
return null;
}
node.name = name.match[1];
pos = name.end;
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
// Look for an equals sign
var token = this.parseTokenString(source,pos,"=");
if(token) {
pos = token.end;
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
// Look for a string literal
var stringLiteral = this.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
} else {
// Look for an indirect value
var indirectValue = this.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a unquoted value
var unquotedValue = this.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = this.parseMacroInvocation(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
node.type = "string";
node.value = "true";
}
}
}
}
} else {
node.type = "string";
node.value = "true";
}
// Update the end position
node.end = pos;
return node;
};
/*
Look for an HTML tag. Returns null if not found, otherwise returns {type: "tag", name:, attributes: [], isSelfClosing:, start:, end:,}
Look for an HTML tag. Returns null if not found, otherwise returns {type: "element", name:, attributes: [], isSelfClosing:, start:, end:,}
*/
exports.parseTag = function(source,pos,options) {
options = options || {};
@@ -321,45 +84,45 @@ exports.parseTag = function(source,pos,options) {
// Define our regexps
var reTagName = /([a-zA-Z0-9\-\$]+)/g;
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a less than sign
token = this.parseTokenString(source,pos,"<");
token = $tw.utils.parseTokenString(source,pos,"<");
if(!token) {
return null;
}
pos = token.end;
// Get the tag name
token = this.parseTokenRegExp(source,pos,reTagName);
token = $tw.utils.parseTokenRegExp(source,pos,reTagName);
if(!token) {
return null;
}
node.tag = token.match[1];
pos = token.end;
// Process attributes
var attribute = this.parseAttribute(source,pos);
var attribute = $tw.utils.parseAttribute(source,pos);
while(attribute) {
node.attributes[attribute.name] = attribute;
pos = attribute.end;
// Get the next attribute
attribute = this.parseAttribute(source,pos);
attribute = $tw.utils.parseAttribute(source,pos);
}
// Skip whitespace
pos = this.skipWhiteSpace(source,pos);
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a closing slash
token = this.parseTokenString(source,pos,"/");
token = $tw.utils.parseTokenString(source,pos,"/");
if(token) {
pos = token.end;
node.isSelfClosing = true;
}
// Look for a greater than sign
token = this.parseTokenString(source,pos,">");
token = $tw.utils.parseTokenString(source,pos,">");
if(!token) {
return null;
}
pos = token.end;
// Check for a required line break
if(options.requireLineBreak) {
token = this.parseTokenRegExp(source,pos,/(\r?\n(?:\r?\n|$))/g);
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n]*\r?\n(?:[^\S\n]*\r?\n|$))/g);
if(!token) {
return null;
}

View File

@@ -0,0 +1,137 @@
/*\
title: $:/core/modules/parsers/wikiparser/rules/image.js
type: application/javascript
module-type: wikirule
Wiki text inline rule for embedding images. For example:
```
[img[http://tiddlywiki.com/fractalveg.jpg]]
[img width=23 height=24 [http://tiddlywiki.com/fractalveg.jpg]]
[img 23x24 [http://tiddlywiki.com/fractalveg.jpg]]
[img width={{!!width}} height={{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
[img {{!!width}}x{{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
[img[Description of image|http://tiddlywiki.com/fractalveg.jpg]]
[img[TiddlerTitle]]
[img[Description of image|TiddlerTitle]]
```
Generates the `<$image>` widget.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.name = "image";
exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
};
exports.findNextMatch = function(startPos) {
// Find the next tag
this.nextImage = this.findNextImage(this.parser.source,startPos);
return this.nextImage ? this.nextImage.start : undefined;
};
exports.parse = function() {
// Move past the match
this.parser.pos = this.nextImage.end;
var node = {
type: "element",
tag: "$image",
attributes: this.nextImage.attributes
};
return [node];
};
/*
Find the next image from the current position
*/
exports.findNextImage = function(source,pos) {
// A regexp for finding candidate HTML tags
var reLookahead = /(\[img)/g;
// Find the next candidate
reLookahead.lastIndex = pos;
var match = reLookahead.exec(source);
while(match) {
// Try to parse the candidate as a tag
var tag = this.parseImage(source,match.index);
// Return success
if(tag) {
return tag;
}
// Look for the next match
reLookahead.lastIndex = match.index + 1;
match = reLookahead.exec(source);
}
// Failed
return null;
};
/*
Look for an image at the specified position. Returns null if not found, otherwise returns {type: "element", name: "$image", attributes: [], isSelfClosing:, start:, end:,}
*/
exports.parseImage = function(source,pos) {
var token,
node = {
type: "element",
name: "$image",
start: pos,
attributes: {}
};
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the `[img`
token = $tw.utils.parseTokenString(source,pos,"[img");
if(!token) {
return null;
}
pos = token.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Process attributes
if(source.charAt(pos) !== "[") {
var attribute = $tw.utils.parseAttribute(source,pos);
while(attribute) {
node.attributes[attribute.name] = attribute;
pos = attribute.end;
pos = $tw.utils.skipWhiteSpace(source,pos);
if(source.charAt(pos) !== "[") {
// Get the next attribute
attribute = $tw.utils.parseAttribute(source,pos);
} else {
attribute = null;
}
}
}
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the `[` after the attributes
token = $tw.utils.parseTokenString(source,pos,"[");
if(!token) {
return null;
}
pos = token.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the source up to the terminating `]]`
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
if(!token) {
return null;
}
pos = token.end;
if(token.match[1]) {
node.attributes.tooltip = {type: "string", value: token.match[1].trim()};
}
node.attributes.source = {type: "string", value: (token.match[2] || "").trim()};
// Update the end position
node.end = pos;
return node;
};
})();

View File

@@ -28,7 +28,7 @@ exports.init = function(parser) {
};
var isLinkExternal = function(to) {
var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s'"]+(?:\/|\b)/i;
var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|'"\\^~]+(?:\/|\b)/i;
return externalRegExp.test(to);
};

View File

@@ -23,19 +23,17 @@ exports.types = {block: true};
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /\{\{([^\{\}\|]+)(?:\|\|([^\|\{\}]+))?\}\}(?:\r?\n|$)/mg;
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}(?:\r?\n|$)/mg;
};
exports.parse = function() {
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details
var textRef = $tw.utils.trim(this.match[1]),
tr = $tw.utils.parseTextReference(textRef),
targetTitle = tr.title,
targetField = tr.field,
targetIndex = tr.index,
template = $tw.utils.trim(this.match[2]);
var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]);
// Prepare the transclude widget
var transcludeNode = {
type: "element",
@@ -43,27 +41,43 @@ exports.parse = function() {
attributes: {},
isBlock: true
};
var tiddlerNode = {
type: "element",
tag: "$tiddler",
attributes: {
tiddler: {type: "string", value: targetTitle}
},
isBlock: true,
children: [transcludeNode]
};
// Prepare the tiddler widget
if(textRef) {
var tr = $tw.utils.parseTextReference(textRef),
targetTitle = tr.title,
targetField = tr.field,
targetIndex = tr.index,
tiddlerNode = {
type: "element",
tag: "$tiddler",
attributes: {
tiddler: {type: "string", value: targetTitle}
},
isBlock: true,
children: [transcludeNode]
};
}
if(template) {
transcludeNode.attributes.tiddler = {type: "string", value: template};
} else {
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
if(targetField) {
transcludeNode.attributes.field = {type: "string", value: targetField};
if(textRef) {
return [tiddlerNode];
} else {
return [transcludeNode];
}
if(targetIndex) {
transcludeNode.attributes.index = {type: "string", value: targetIndex};
} else {
if(textRef) {
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
if(targetField) {
transcludeNode.attributes.field = {type: "string", value: targetField};
}
if(targetIndex) {
transcludeNode.attributes.index = {type: "string", value: targetIndex};
}
return [tiddlerNode];
} else {
return [transcludeNode];
}
}
return [tiddlerNode];
};
})();

View File

@@ -23,45 +23,57 @@ exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /\{\{([^\{\}\|]+)(?:\|\|([^\|\{\}]+))?\}\}/mg;
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?\}\}/mg;
};
exports.parse = function() {
// Move past the match
this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details
var textRef = $tw.utils.trim(this.match[1]),
tr = $tw.utils.parseTextReference(textRef),
targetTitle = tr.title,
targetField = tr.field,
targetIndex = tr.index,
template = $tw.utils.trim(this.match[2]);
var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]);
// Prepare the transclude widget
var transcludeNode = {
type: "element",
tag: "$transclude",
attributes: {}
};
var tiddlerNode = {
type: "element",
tag: "$tiddler",
attributes: {
tiddler: {type: "string", value: targetTitle}
},
children: [transcludeNode]
};
// Prepare the tiddler widget
if(textRef) {
var tr = $tw.utils.parseTextReference(textRef),
targetTitle = tr.title,
targetField = tr.field,
targetIndex = tr.index,
tiddlerNode = {
type: "element",
tag: "$tiddler",
attributes: {
tiddler: {type: "string", value: targetTitle}
},
children: [transcludeNode]
};
}
if(template) {
transcludeNode.attributes.tiddler = {type: "string", value: template};
} else {
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
if(targetField) {
transcludeNode.attributes.field = {type: "string", value: targetField};
if(textRef) {
return [tiddlerNode];
} else {
return [transcludeNode];
}
if(targetIndex) {
transcludeNode.attributes.index = {type: "string", value: targetIndex};
} else {
if(textRef) {
transcludeNode.attributes.tiddler = {type: "string", value: targetTitle};
if(targetField) {
transcludeNode.attributes.field = {type: "string", value: targetField};
}
if(targetIndex) {
transcludeNode.attributes.index = {type: "string", value: targetIndex};
}
return [tiddlerNode];
} else {
return [transcludeNode];
}
}
return [tiddlerNode];
};
})();

View File

@@ -62,8 +62,9 @@ PluginSwitcher.prototype.switchPlugins = function() {
var unregisteredTiddlers = $tw.wiki.unregisterPluginTiddlers(this.pluginType);
// Accumulate the titles of shadow tiddlers that have changed as a result of this switch
var changedTiddlers = {};
$tw.utils.each(this.wiki.shadowTiddlers,function(shadowInfo,title) {
if(unregisteredTiddlers.indexOf(shadowInfo.source) !== -1) {
this.wiki.eachShadow(function(tiddler,title) {
var source = self.wiki.getShadowSource(title);
if(unregisteredTiddlers.indexOf(source) !== -1) {
changedTiddlers[title] = true; // isDeleted?
}
});
@@ -72,8 +73,9 @@ PluginSwitcher.prototype.switchPlugins = function() {
// Unpack the current theme tiddlers
$tw.wiki.unpackPluginTiddlers();
// Accumulate the affected shadow tiddlers
$tw.utils.each(this.wiki.shadowTiddlers,function(shadowInfo,title) {
if(registeredTiddlers.indexOf(shadowInfo.source) !== -1) {
this.wiki.eachShadow(function(tiddler,title) {
var source = self.wiki.getShadowSource(title);
if(registeredTiddlers.indexOf(source) !== -1) {
changedTiddlers[title] = false; // isDeleted?
}
});

View File

@@ -19,13 +19,27 @@ TiddlyFoxSaver.prototype.save = function(text,method,callback) {
var messageBox = document.getElementById("tiddlyfox-message-box");
if(messageBox) {
// Get the pathname of this document
var pathname = document.location.pathname;
// Test for a Windows path of the form /x:/blah/blah
if(/^\/[A-Z]\:\//i.test(pathname)) {
// Remove the leading slash
pathname = pathname.substr(1);
// Convert slashes to backslashes
pathname = pathname.replace(/\//g,"\\");
var pathname = document.location.toString();
// Replace file://localhost/ with file:///
if(pathname.indexOf("file://localhost/") == 0) {
pathname = "file://" + pathname.substr(16);
}
// Windows path file:///x:/blah/blah --> x:\blah\blah
if(/^file\:\/\/\/[A-Z]\:\//i.test(pathname)) {
// Remove the leading slash and convert slashes to backslashes
pathname = pathname.substr(8).replace(/\//g,"\\");
// Firefox Windows network path file://///server/share/blah/blah --> //server/share/blah/blah
} else if(pathname.indexOf("file://///") === 0) {
pathname = "\\\\" + unescape(pathname.substr(10)).replace(/\//g,"\\");
// Mac/Unix local path file:///path/path --> /path/path
} else if(pathname.indexOf("file:///") == 0) {
pathname = unescape(pathname.substr(7));
// Mac/Unix local path file:/path/path --> /path/path
} else if(pathname.indexOf("file:/") == 0) {
pathname = unescape(pathname.substr(5));
// Otherwise Windows networth path file://server/share/path/path --> \\server\share\path\path
} else {
pathname = "\\\\" + unescape(pathname.substr(7)).replace(new RegExp("/","g"),"\\");
}
// Create the message element and put it in the message box
var message = document.createElement("div");

View File

@@ -12,6 +12,12 @@ This is the main application logic for both the client and server
/*global $tw: false */
"use strict";
// Set to `true` to enable performance instrumentation
var PERFORMANCE_INSTRUMENTATION = false;
// Time (in ms) that we defer refreshing changes to draft tiddlers
var DRAFT_TIDDLER_TIMEOUT = 400;
var widget = require("$:/core/modules/widgets/widget.js");
exports.startup = function() {
@@ -32,14 +38,15 @@ exports.startup = function() {
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
// Set up the performance framework
$tw.perf = new $tw.Performance(PERFORMANCE_INSTRUMENTATION);
// Set up the parsers
$tw.wiki.initParsers();
// Set up the syncer object
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki});
// Set up the command modules
$tw.Commander.initCommands();
// Kick off the language manager
$tw.languageManager = new $tw.PluginSwitcher({
// Kick off the language manager and switcher
$tw.language = new $tw.Language();
$tw.languageSwitcher = new $tw.PluginSwitcher({
wiki: $tw.wiki,
pluginType: "language",
controllerTitle: "$:/language",
@@ -57,25 +64,31 @@ exports.startup = function() {
"$:/themes/tiddlywiki/vanilla"
]
});
// Get the default tiddlers
var defaultTiddlersTitle = "$:/DefaultTiddlers",
defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle),
defaultTiddlers = [];
if(defaultTiddlersTiddler) {
defaultTiddlers = $tw.wiki.filterTiddlers(defaultTiddlersTiddler.fields.text);
}
// Initialise the story and history
var storyTitle = "$:/StoryList",
story = [];
for(var t=0; t<defaultTiddlers.length; t++) {
story[t] = defaultTiddlers[t];
}
$tw.wiki.addTiddler({title: storyTitle, text: "", list: story},$tw.wiki.getModificationFields());
// Display the default tiddlers
var displayDefaultTiddlers = function() {
// Get the default tiddlers
var defaultTiddlersTitle = "$:/DefaultTiddlers",
defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle),
defaultTiddlers = [];
if(defaultTiddlersTiddler) {
defaultTiddlers = $tw.wiki.filterTiddlers(defaultTiddlersTiddler.fields.text);
}
// Initialise the story
var storyTitle = "$:/StoryList",
story = [];
for(var t=0; t<defaultTiddlers.length; t++) {
story[t] = defaultTiddlers[t];
}
$tw.wiki.addTiddler({title: storyTitle, text: "", list: story},$tw.wiki.getModificationFields());
};
displayDefaultTiddlers();
// Set up the syncer object
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki});
// Host-specific startup
if($tw.browser) {
// Set up our beforeunload handler
window.addEventListener("beforeunload",function(event) {
var confirmationMessage = null;
var confirmationMessage = undefined;
if($tw.syncer.isDirty()) {
confirmationMessage = "You have unsaved changes in TiddlyWiki";
event.returnValue = confirmationMessage; // Gecko
@@ -111,6 +124,10 @@ exports.startup = function() {
$tw.rootWidget.addEventListener("tw-scroll",function(event) {
$tw.pageScroller.handleEvent(event);
});
// Listen for the tw-home message
$tw.rootWidget.addEventListener("tw-home",function(event) {
displayDefaultTiddlers();
});
// Install the save action handlers
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
$tw.syncer.saveWiki({
@@ -190,22 +207,13 @@ exports.startup = function() {
$tw.styleElement = document.createElement("style");
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
document.head.insertBefore($tw.styleElement,document.head.firstChild);
$tw.wiki.addEventListener("change",function(changes) {
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) {
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
}
});
// Display the PageMacros, which includes the PageTemplate
var templateTitle = "$:/core/ui/PageMacros",
parser = $tw.wiki.parseTiddler(templateTitle);
$tw.pageWidgetNode = $tw.wiki.makeWidget(parser,{document: document, parentWidget: $tw.rootWidget});
$tw.pageContainer = document.createElement("div");
$tw.utils.addClass($tw.pageContainer,"tw-page-container");
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
$tw.pageWidgetNode.render($tw.pageContainer,null);
$tw.wiki.addEventListener("change",function(changes) {
$tw.pageWidgetNode.refresh(changes,$tw.pageContainer,null);
});
}));
// Display the $:/PageMacros tiddler to kick off the display
renderPage();
// Fix up the link between the root widget and the page container
$tw.rootWidget.domNodes = [$tw.pageContainer];
$tw.rootWidget.children = [$tw.pageWidgetNode];
@@ -235,7 +243,54 @@ exports.startup = function() {
);
commander.execute();
}
};
/*
Main render function for PageMacros, which includes the PageTemplate
*/
function renderPage() {
// Parse and render the template
var templateTitle = "$:/core/ui/PageMacros",
parser = $tw.wiki.parseTiddler(templateTitle);
$tw.perf.report("mainRender",function() {
$tw.pageWidgetNode = $tw.wiki.makeWidget(parser,{document: document, parentWidget: $tw.rootWidget});
$tw.pageContainer = document.createElement("div");
$tw.utils.addClass($tw.pageContainer,"tw-page-container-wrapper");
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
$tw.pageWidgetNode.render($tw.pageContainer,null);
})();
// Prepare refresh mechanism
var deferredChanges = Object.create(null),
timerId;
function refresh() {
// Process the refresh
$tw.pageWidgetNode.refresh(deferredChanges,$tw.pageContainer,null);
deferredChanges = Object.create(null);
}
// Add the change event handler
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
// Check if only drafts have changed
var onlyDraftsHaveChanged = true;
for(var title in changes) {
var tiddler = $tw.wiki.getTiddler(title);
if(!tiddler || !tiddler.hasField("draft.of")) {
onlyDraftsHaveChanged = false;
}
}
// Defer the change if only drafts have changed
if(timerId) {
clearTimeout(timerId);
}
timerId = null;
if(onlyDraftsHaveChanged) {
timerId = setTimeout(refresh,DRAFT_TIDDLER_TIMEOUT);
$tw.utils.extend(deferredChanges,changes);
} else {
$tw.utils.extend(deferredChanges,changes);
refresh();
}
}));
}
})();

View File

@@ -25,7 +25,7 @@ var ZoominListView = function(listWidget) {
}
domNode.style.position = "absolute";
});
}
};
ZoominListView.prototype.navigateTo = function(historyInfo) {
var duration = $tw.utils.getAnimationDuration(),

View File

@@ -267,8 +267,13 @@ Synchronise a set of changes to the server
*/
Syncer.prototype.syncToServer = function(changes) {
var self = this,
now = new Date(),
filteredChanges = this.filterFn.call(this.wiki,changes);
now = Date.now(),
filteredChanges = this.filterFn.call(this.wiki,function(callback) {
$tw.utils.each(changes,function(change,title) {
var tiddler = self.wiki.getTiddler(title);
callback(tiddler,title);
});
});
$tw.utils.each(changes,function(change,title,object) {
// Process the change if it is a deletion of a tiddler we're already syncing, or is on the filtered change list
if((change.deleted && $tw.utils.hop(self.tiddlerInfo,title)) || filteredChanges.indexOf(title) !== -1) {
@@ -366,7 +371,7 @@ Queue up a sync task. If there is already a pending task for the tiddler, just u
*/
Syncer.prototype.enqueueSyncTask = function(task) {
var self = this,
now = new Date();
now = Date.now();
// Set the timestamps on this task
task.queueTime = now;
task.lastModificationTime = now;
@@ -469,7 +474,7 @@ Choose the next applicable task
Syncer.prototype.chooseNextTask = function() {
var self = this,
candidateTask = null,
now = new Date();
now = Date.now();
// Select the best candidate task
$tw.utils.each(this.taskQueue,function(task,title) {
// Exclude the task if there's one of the same name in progress
@@ -514,6 +519,9 @@ Syncer.prototype.dispatchTask = function(task,callback) {
// Invoke the callback
callback(null);
});
} else {
this.logger.log(" Not Dispatching 'save' task:",task.title,"tiddler does not exist");
return callback(null);
}
} else if(task.type === "load") {
// Load the tiddler

View File

@@ -55,25 +55,20 @@ Handle a scroll event hitting the page document
*/
PageScroller.prototype.scrollIntoView = function(element) {
var duration = $tw.utils.getAnimationDuration();
// Get the offset bounds of the element
var bounds = {
left: element.offsetLeft,
top: element.offsetTop,
width: element.offsetWidth,
height: element.offsetHeight
};
// Walk up the tree adjusting the offset bounds by each offsetParent
while(element.offsetParent) {
element = element.offsetParent;
bounds.left += element.offsetLeft;
bounds.top += element.offsetTop;
}
// Now get ready to scroll the body
this.cancelScroll();
this.startTime = new Date();
var scrollPosition = $tw.utils.getScrollPosition(),
// We'll consider the horizontal and vertical scroll directions separately via this function
getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
this.startTime = Date.now();
var scrollPosition = $tw.utils.getScrollPosition();
// Get the client bounds of the element and adjust by the scroll position
var clientBounds = element.getBoundingClientRect(),
bounds = {
left: clientBounds.left + scrollPosition.x,
top: clientBounds.top + scrollPosition.y,
width: clientBounds.width,
height: clientBounds.height
};
// We'll consider the horizontal and vertical scroll directions separately via this function
var getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
// If the target is above/left of the current view, then scroll to it's top/left
if(targetPos <= currentPos) {
return targetPos;
@@ -99,7 +94,7 @@ PageScroller.prototype.scrollIntoView = function(element) {
if(duration <= 0) {
t = 1;
} else {
t = ((new Date()) - self.startTime) / duration;
t = ((Date.now()) - self.startTime) / duration;
}
if(t >= 1) {
self.cancelScroll();

View File

@@ -219,6 +219,7 @@ var document = {
createTextNode: function(text) {
return new TW_TextNode(text);
},
isTiddlyWikiFakeDom: true
};
exports.fakeDocument = document;

View File

@@ -0,0 +1,62 @@
/*\
title: $:/core/modules/utils/performance.js
type: application/javascript
module-type: global
Performance measurement.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
function Performance(enabled) {
this.enabled = !!enabled;
this.measures = {}; // Hashmap of current values of measurements
this.logger = new $tw.utils.Logger("performance");
}
/*
Wrap performance reporting around a top level function
*/
Performance.prototype.report = function(name,fn) {
var self = this;
if(this.enabled) {
return function() {
self.measures = {};
var startTime = $tw.utils.timer(),
result = fn.apply(this,arguments);
self.logger.log(name + ": " + $tw.utils.timer(startTime) + "ms");
for(var m in self.measures) {
self.logger.log("+" + m + ": " + self.measures[m] + "ms");
}
return result;
};
} else {
return fn;
}
};
/*
Wrap performance measurements around a subfunction
*/
Performance.prototype.measure = function(name,fn) {
var self = this;
if(this.enabled) {
return function() {
var startTime = $tw.utils.timer(),
result = fn.apply(this,arguments),
value = self.measures[name] || 0;
self.measures[name] = value + $tw.utils.timer(startTime);
return result;
};
} else {
return fn;
}
};
exports.Performance = Performance;
})();

View File

@@ -35,21 +35,34 @@ exports.count = function(object) {
/*
Push entries onto an array, removing them first if they already exist in the array
array: array to modify
array: array to modify (assumed to be free of duplicates)
value: a single value to push or an array of values to push
*/
exports.pushTop = function(array,value) {
var t,p;
if($tw.utils.isArray(value)) {
// Remove any array entries that are duplicated in the new values
for(t=0; t<value.length; t++) {
p = array.indexOf(value[t]);
if(p !== -1) {
array.splice(p,1);
if(value.length !== 0) {
if(array.length !== 0) {
if(value.length < array.length) {
for(t=0; t<value.length; t++) {
p = array.indexOf(value[t]);
if(p !== -1) {
array.splice(p,1);
}
}
} else {
for(t=array.length-1; t>=0; t--) {
p = value.indexOf(array[t]);
if(p !== -1) {
array.splice(t,1);
}
}
}
}
// Push the values on top of the main array
array.push.apply(array,value);
}
// Push the values on top of the main array
array.push.apply(array,value);
} else {
p = array.indexOf(value);
if(p !== -1) {
@@ -214,32 +227,36 @@ exports.getRelativeDate = function(delta) {
futurep = true;
}
var units = [
{name: "years", duration: 365 * 24 * 60 * 60 * 1000},
{name: "months", duration: (365/12) * 24 * 60 * 60 * 1000},
{name: "days", duration: 24 * 60 * 60 * 1000},
{name: "hours", duration: 60 * 60 * 1000},
{name: "minutes", duration: 60 * 1000},
{name: "seconds", duration: 1000}
{name: "Years", duration: 365 * 24 * 60 * 60 * 1000},
{name: "Months", duration: (365/12) * 24 * 60 * 60 * 1000},
{name: "Days", duration: 24 * 60 * 60 * 1000},
{name: "Hours", duration: 60 * 60 * 1000},
{name: "Minutes", duration: 60 * 1000},
{name: "Seconds", duration: 1000}
];
for(var t=0; t<units.length; t++) {
var result = Math.floor(delta / units[t].duration);
if(result >= 2) {
var desc = result + " " + units[t].name;
if(futurep) {
desc = desc + " from now";
} else {
desc = desc + " ago";
}
return {
delta: delta,
description: desc,
description: $tw.language.getString(
"RelativeDate/" + (futurep ? "Future" : "Past") + "/" + units[t].name,
{variables:
{period: result.toString()}
}
),
updatePeriod: units[t].duration
};
}
}
return {
delta: delta,
description: "1 second ago",
description: $tw.language.getString(
"RelativeDate/" + (futurep ? "Future" : "Past") + "/Second",
{variables:
{period: "1"}
}
),
updatePeriod: 1000
};
};
@@ -362,7 +379,7 @@ Returns an object with the following fields, all optional:
*/
exports.parseTextReference = function(textRef) {
// Separate out the title, field name and/or JSON indices
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##([^\s]+)))?\s*/mg,
var reTextRef = /^\s*([^!#]+)?(?:(?:!!([^\s]+))|(?:##(.+)))?\s*/mg,
match = reTextRef.exec(textRef);
if(match && reTextRef.lastIndex === textRef.length) {
// Return the parts
@@ -447,4 +464,23 @@ exports.makeTiddlerDictionary = function(data) {
return output.join("\n");
};
/*
High resolution microsecond timer for profiling
*/
exports.timer = function(base) {
var m;
if($tw.node) {
var r = process.hrtime();
m = r[0] * 1e3 + (r[1] / 1e6);
} else if(window.performance) {
m = performance.now();
} else {
m = Date.now();
}
if(typeof base !== "undefined") {
m = m - base;
}
return m;
}
})();

View File

@@ -54,7 +54,7 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
domNode.addEventListener("click",function (event) {
var handled = false;
if(self.to) {
self.dispatchEvent({type: "tw-navigate", navigateTo: self.to, tiddlerTitle: self.getVariable("currentTiddler")});
self.navigateTo(event);
handled = true;
}
if(self.message) {
@@ -92,6 +92,19 @@ ButtonWidget.prototype.isPoppedUp = function() {
return result;
};
ButtonWidget.prototype.navigateTo = function(event) {
var bounds = this.domNodes[0].getBoundingClientRect();
this.dispatchEvent({
type: "tw-navigate",
navigateTo: this.to,
navigateFromTitle: this.getVariable("storyTiddler"),
navigateFromNode: this,
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
},
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1)
});
};
ButtonWidget.prototype.dispatchMessage = function(event) {
this.dispatchEvent({type: this.message, param: this.param, tiddlerTitle: this.getVariable("currentTiddler")});
};
@@ -105,8 +118,7 @@ ButtonWidget.prototype.triggerPopup = function(event) {
};
ButtonWidget.prototype.setTiddler = function() {
var tiddler = this.wiki.getTiddler(this.set);
this.wiki.addTiddler(new $tw.Tiddler(tiddler,{title: this.set, text: this.setTo}));
this.wiki.setTextReference(this.set,this.setTo,this.getVariable("currentTiddler"));
};
/*

View File

@@ -54,6 +54,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
CountWidget.prototype.refresh = function(changedTiddlers) {
// Re-execute the filter to get the count
this.computeAttributes();
var oldCount = this.currentCount;
this.execute();
if(this.currentCount !== oldCount) {

View File

@@ -147,6 +147,11 @@ DropZoneWidget.prototype.importDataTypes = [
};
}
}},
{type: "text/html", IECompatible: false, convertToFields: function(data) {
return {
text: data
};
}},
{type: "text/plain", IECompatible: false, convertToFields: function(data) {
return {
text: data

View File

@@ -30,8 +30,13 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
var domNode = this.document.createElementNS(this.namespace,this.parseTreeNode.tag);
this.assignAttributes(domNode);
// Neuter blacklisted elements
var tag = this.parseTreeNode.tag;
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
tag = "safe-" + tag;
}
var domNode = this.document.createElementNS(this.namespace,tag);
this.assignAttributes(domNode,{excludeEventAttributes: true});
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
@@ -65,7 +70,7 @@ ElementWidget.prototype.refresh = function(changedTiddlers) {
hasChangedAttributes = $tw.utils.count(changedAttributes) > 0;
if(hasChangedAttributes) {
// Update our attributes
this.assignAttributes(this.domNodes[0]);
this.assignAttributes(this.domNodes[0],{excludeEventAttributes: true});
}
return this.refreshChildren(changedTiddlers) || hasChangedAttributes;
};

View File

@@ -71,10 +71,20 @@ FieldManglerWidget.prototype.handleRemoveFieldEvent = function(event) {
};
FieldManglerWidget.prototype.handleAddFieldEvent = function(event) {
var tiddler = this.wiki.getTiddler(this.mangleTitle);
var tiddler = this.wiki.getTiddler(this.mangleTitle),
fieldValidatorRegEx = /^[a-z\-\._]+$/mg;
if(tiddler && typeof event.param === "string") {
var name = event.param.toLowerCase();
var name = event.param.toLowerCase().trim();
if(name !== "" && !$tw.utils.hop(tiddler.fields,name)) {
if(!fieldValidatorRegEx.test(name)) {
alert($tw.language.getString(
"InvalidFieldName",
{variables:
{fieldName: name}
}
));
return true;
}
var addition = this.wiki.getModificationFields();
addition[name] = "";
this.wiki.addTiddler(new $tw.Tiddler(tiddler,addition));
@@ -102,11 +112,14 @@ FieldManglerWidget.prototype.handleRemoveTagEvent = function(event) {
FieldManglerWidget.prototype.handleAddTagEvent = function(event) {
var tiddler = this.wiki.getTiddler(this.mangleTitle);
if(tiddler && typeof event.param === "string" && event.param !== "") {
var modification = this.wiki.getModificationFields();
modification.tags = (tiddler.fields.tags || []).slice(0);
$tw.utils.pushTop(modification.tags,event.param);
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
if(tiddler && typeof event.param === "string") {
var tag = event.param.trim();
if(tag !== "") {
var modification = this.wiki.getModificationFields();
modification.tags = (tiddler.fields.tags || []).slice(0);
$tw.utils.pushTop(modification.tags,tag);
this.wiki.addTiddler(new $tw.Tiddler(tiddler,modification));
}
}
return true;
};

View File

@@ -0,0 +1,123 @@
/*\
title: $:/core/modules/widgets/image.js
type: application/javascript
module-type: widget
The image widget displays an image referenced with an external URI or with a local tiddler title.
```
<$image src="TiddlerTitle" width="320" height="400" class="classnames">
```
The image source can be the title of an existing tiddler or the URL of an external image.
External images always generate an HTML `<img>` tag.
Tiddlers that have a _canonical_uri field generate an HTML `<img>` tag with the src attribute containing the URI.
Tiddlers that contain image data generate an HTML `<img>` tag with the src attribute containing a base64 representation of the image.
Tiddlers that contain wikitext could be rendered to a DIV of the usual size of a tiddler, and then transformed to the size requested.
The width and height attributes are interpreted as a number of pixels, and do not need to include the "px" suffix.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var ImageWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
ImageWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
ImageWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create element
// Determine what type of image it is
var tag = "img", src = "",
tiddler = this.wiki.getTiddler(this.imageSource);
if(!tiddler) {
// The source isn't the title of a tiddler, so we'll assume it's a URL
src = this.imageSource;
} else {
// Check if it is an image tiddler
if(this.wiki.isImageTiddler(this.imageSource)) {
// Render the appropriate element for the image type
var type = tiddler.fields.type,
text = tiddler.fields.text;
switch(type) {
case "application/pdf":
tag = "embed";
src = "data:application/pdf;base64," + text;
break;
case "image/svg+xml":
src = "data:image/svg+xml," + encodeURIComponent(text);
break;
default:
src = "data:" + type + ";base64," + text;
break;
}
}
}
// Create the element and assign the attributes
var domNode = this.document.createElement(tag);
domNode.setAttribute("src",src);
if(this.imageClass) {
domNode.setAttribute("class",this.imageClass);
}
if(this.imageWidth) {
domNode.setAttribute("width",parseInt(this.imageWidth,10) + "px");
}
if(this.imageHeight) {
domNode.setAttribute("height",parseInt(this.imageHeight,10) + "px");
}
if(this.imageTooltip) {
domNode.setAttribute("title",this.imageTooltip);
}
// Insert element
parent.insertBefore(domNode,nextSibling);
this.domNodes.push(domNode);
};
/*
Compute the internal state of the widget
*/
ImageWidget.prototype.execute = function() {
// Get our parameters
this.imageSource = this.getAttribute("source");
this.imageWidth = this.getAttribute("width");
this.imageHeight = this.getAttribute("height");
this.imageClass = this.getAttribute("class");
this.imageTooltip = this.getAttribute("tooltip");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ImageWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.source || changedAttributes.width || changedAttributes.height || changedAttributes["class"] || changedAttributes.tooltip || changedTiddlers[this.imageSource]) {
this.refreshSelf();
return true;
} else {
return false;
}
};
exports.image = ImageWidget;
})();

View File

@@ -56,23 +56,37 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
// Create our element
var domNode = this.document.createElement("a");
// Assign classes
$tw.utils.addClass(domNode,"tw-tiddlylink");
var classes = ["tw-tiddlylink"];
if(this.isShadow) {
$tw.utils.addClass(domNode,"tw-tiddlylink-shadow");
classes.push("tw-tiddlylink-shadow");
}
if(this.isMissing && !this.isShadow) {
$tw.utils.addClass(domNode,"tw-tiddlylink-missing");
classes.push("tw-tiddlylink-missing");
} else {
if(!this.isMissing) {
$tw.utils.addClass(domNode,"tw-tiddlylink-resolves");
classes.push("tw-tiddlylink-resolves");
}
}
domNode.setAttribute("class",classes.join(" "));
// Set an href
var wikiLinkTemplateMacro = this.getVariable("tw-wikilink-template"),
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$",
wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to));
wikiLinkText = wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
domNode.setAttribute("href",wikiLinkText);
// Set the tooltip
// HACK: Performance issues with re-parsing the tooltip prevent us defaulting the tooltip to "<$transclude field='tooltip'><$transclude field='title'/></$transclude>"
var tooltipWikiText = this.tooltip || this.getVariable("tw-wikilink-tooltip");
if(tooltipWikiText) {
var tooltipText = this.wiki.renderText("text/plain","text/vnd.tiddlywiki",tooltipWikiText,{
parseAsInline: true,
variables: {
currentTiddler: this.to
},
parentWidget: this
});
domNode.setAttribute("title",tooltipText);
}
// Add a click event handler
$tw.utils.addEventListeners(domNode,[
{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"},
@@ -95,7 +109,7 @@ LinkWidget.prototype.handleClickEvent = function (event) {
navigateFromNode: this,
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
},
navigateSuppressNavigation: event.metaKey || event.ctrlKey
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1)
});
event.preventDefault();
event.stopPropagation();
@@ -162,6 +176,8 @@ Compute the internal state of the widget
LinkWidget.prototype.execute = function() {
// Get the target tiddler title
this.to = this.getAttribute("to",this.getVariable("currentTiddler"));
// Get the link title
this.tooltip = this.getAttribute("tooltip");
// Determine the link characteristics
this.isMissing = !this.wiki.tiddlerExists(this.to);
this.isShadow = this.wiki.isShadowTiddler(this.to);
@@ -174,7 +190,7 @@ 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]) {
if(changedAttributes.to || changedTiddlers[this.to] || changedAttributes.tooltip) {
this.refreshSelf();
return true;
}

View File

@@ -69,10 +69,11 @@ LinkCatcherWidget.prototype.handleNavigateEvent = function(event) {
if(this.catchTo) {
this.wiki.setTextReference(this.catchTo,event.navigateTo,this.getVariable("currentTiddler"));
}
if(this.catchMessage) {
this.dispatchEvent({
if(this.catchMessage && this.parentWidget) {
this.parentWidget.dispatchEvent({
type: this.catchMessage,
param: event.navigateTo
param: event.navigateTo,
navigateTo: event.navigateTo
});
}
if(this.catchSet) {

View File

@@ -43,7 +43,11 @@ ListWidget.prototype.render = function(parent,nextSibling) {
this.renderChildren(parent,nextSibling);
// Construct the storyview
var StoryView = this.storyViews[this.storyViewName];
this.storyview = StoryView ? new StoryView(this) : null;
if(StoryView && !this.document.isTiddlyWikiFakeDom) {
this.storyview = new StoryView(this)
} else {
this.storyview = null;
}
};
/*

View File

@@ -26,7 +26,7 @@ var NavigatorWidget = function(parseTreeNode,options) {
{type: "tw-close-all-tiddlers", handler: "handleCloseAllTiddlersEvent"},
{type: "tw-close-other-tiddlers", handler: "handleCloseOtherTiddlersEvent"},
{type: "tw-new-tiddler", handler: "handleNewTiddlerEvent"},
{type: "tw-import-tiddlers", handler: "handleImportTiddlersEvent"},
{type: "tw-import-tiddlers", handler: "handleImportTiddlersEvent"}
]);
};
@@ -198,15 +198,29 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
// Get the tiddler we're deleting
var title = event.param || event.tiddlerTitle,
tiddler = this.wiki.getTiddler(title),
storyList = this.getStoryList();
storyList = this.getStoryList(),
originalTitle, confirmationTitle;
// Check if the tiddler we're deleting is in draft mode
if(tiddler.hasField("draft.title")) {
// Delete the original tiddler
var originalTitle = tiddler.fields["draft.of"];
// Ask for confirmation if the tiddler has changed
if(!confirm("Do you wish to delete the tiddler '" + originalTitle + "'")) {
return false;
}
// If so, we'll prompt for confirmation referencing the original tiddler
originalTitle = tiddler.fields["draft.of"];
confirmationTitle = originalTitle;
} else {
// If not a draft, then prompt for confirmation referencing the specified tiddler
originalTitle = null;
confirmationTitle = title;
}
// Seek confirmation
if(!confirm($tw.language.getString(
"ConfirmDeleteTiddler",
{variables:
{title: confirmationTitle}
}
))) {
return false;
}
// Delete the original tiddler
if(originalTitle) {
this.wiki.deleteTiddler(originalTitle);
this.removeTitleFromStory(storyList,originalTitle);
}
@@ -277,7 +291,12 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
var isRename = draftOf !== draftTitle,
isConfirmed = true;
if(isRename && this.wiki.tiddlerExists(draftTitle)) {
isConfirmed = confirm("Do you wish to overwrite the tiddler '" + draftTitle + "'?");
isConfirmed = confirm($tw.language.getString(
"ConfirmOverwriteTiddler",
{variables:
{title: draftTitle}
}
));
}
if(isConfirmed) {
// Save the draft tiddler as the real tiddler
@@ -314,11 +333,23 @@ NavigatorWidget.prototype.handleCancelTiddlerEvent = function(event) {
originalTitle = draftTiddler.fields["draft.of"],
storyList = this.getStoryList();
if(draftTiddler && originalTitle) {
// Ask for confirmation if the tiddler text has changed
var isConfirmed = true;
if(this.wiki.getTiddlerText(draftTitle) !== this.wiki.getTiddlerText(originalTitle)) {
isConfirmed = confirm($tw.language.getString(
"ConfirmCancelTiddler",
{variables:
{title: draftTitle}
}
));
}
// Remove the draft tiddler
this.wiki.deleteTiddler(draftTitle);
this.replaceFirstTitleInStory(storyList,draftTitle,originalTitle);
this.addToHistory(originalTitle,event.navigateFromClientRect);
this.saveStoryList(storyList);
if(isConfirmed) {
this.wiki.deleteTiddler(draftTitle);
this.replaceFirstTitleInStory(storyList,draftTitle,originalTitle);
this.addToHistory(originalTitle,event.navigateFromClientRect);
this.saveStoryList(storyList);
}
}
return false;
};

View File

@@ -0,0 +1,184 @@
/*\
title: $:/core/modules/widgets/scrollable.js
type: application/javascript
module-type: widget
Scrollable widget
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var ScrollableWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
this.scaleFactor = 1;
this.addEventListeners([
{type: "tw-scroll", handler: "handleScrollEvent"}
]);
if($tw.browser) {
this.requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, 1000/60);
};
this.cancelAnimationFrame = window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
function(id) {
window.clearTimeout(id);
};
}
};
/*
Inherit from the base widget class
*/
ScrollableWidget.prototype = new Widget();
ScrollableWidget.prototype.cancelScroll = function() {
if(this.idRequestFrame) {
this.cancelAnimationFrame.call(window,this.idRequestFrame);
this.idRequestFrame = null;
}
};
/*
Handle a scroll event
*/
ScrollableWidget.prototype.handleScrollEvent = function(event) {
// Pass the scroll event through if our offsetsize is larger than our scrollsize
if(this.outerDomNode.scrollWidth <= this.outerDomNode.offsetWidth && this.outerDomNode.scrollHeight <= this.outerDomNode.offsetHeight && this.fallthrough === "yes") {
return true;
}
this.scrollIntoView(event.target);
return false; // Handled event
};
/*
Scroll an element into view
*/
ScrollableWidget.prototype.scrollIntoView = function(element) {
var duration = $tw.utils.getAnimationDuration();
this.cancelScroll();
this.startTime = Date.now();
var scrollPosition = {
x: this.outerDomNode.scrollLeft,
y: this.outerDomNode.scrollTop
};
// Get the client bounds of the element and adjust by the scroll position
var scrollableBounds = this.outerDomNode.getBoundingClientRect(),
clientTargetBounds = element.getBoundingClientRect(),
bounds = {
left: clientTargetBounds.left + scrollPosition.x - scrollableBounds.left,
top: clientTargetBounds.top + scrollPosition.y - scrollableBounds.top,
width: clientTargetBounds.width,
height: clientTargetBounds.height
};
// We'll consider the horizontal and vertical scroll directions separately via this function
var getEndPos = function(targetPos,targetSize,currentPos,currentSize) {
// If the target is already visible then stay where we are
if(targetPos >= currentPos && (targetPos + targetSize) <= (currentPos + currentSize)) {
return currentPos;
// If the target is above/left of the current view, then scroll to its top/left
} else if(targetPos <= currentPos) {
return targetPos;
// If the target is smaller than the window and the scroll position is too far up, then scroll till the target is at the bottom of the window
} else if(targetSize < currentSize && currentPos < (targetPos + targetSize - currentSize)) {
return targetPos + targetSize - currentSize;
// If the target is big, then just scroll to the top
} else if(currentPos < targetPos) {
return targetPos;
// Otherwise, stay where we are
} else {
return currentPos;
}
},
endX = getEndPos(bounds.left,bounds.width,scrollPosition.x,this.outerDomNode.offsetWidth),
endY = getEndPos(bounds.top,bounds.height,scrollPosition.y,this.outerDomNode.offsetHeight);
// Only scroll if necessary
if(endX !== scrollPosition.x || endY !== scrollPosition.y) {
var self = this,
drawFrame;
drawFrame = function () {
var t;
if(duration <= 0) {
t = 1;
} else {
t = ((Date.now()) - self.startTime) / duration;
}
if(t >= 1) {
self.cancelScroll();
t = 1;
}
t = $tw.utils.slowInSlowOut(t);
self.outerDomNode.scrollLeft = scrollPosition.x + (endX - scrollPosition.x) * t;
self.outerDomNode.scrollTop = scrollPosition.y + (endY - scrollPosition.y) * t;
if(t < 1) {
self.idRequestFrame = self.requestAnimationFrame.call(window,drawFrame);
}
};
drawFrame();
}
};
/*
Render this widget into the DOM
*/
ScrollableWidget.prototype.render = function(parent,nextSibling) {
var self = this;
// Remember parent
this.parentDomNode = parent;
// Compute attributes and execute state
this.computeAttributes();
this.execute();
// Create elements
this.outerDomNode = this.document.createElement("div");
$tw.utils.setStyle(this.outerDomNode,[
{overflowY: "auto"},
{overflowX: "auto"},
{webkitOverflowScrolling: "touch"}
]);
this.innerDomNode = this.document.createElement("div");
this.outerDomNode.appendChild(this.innerDomNode);
// Assign classes
this.outerDomNode.className = this["class"] || "";
// Insert element
parent.insertBefore(this.outerDomNode,nextSibling);
this.renderChildren(this.innerDomNode,null);
this.domNodes.push(this.outerDomNode);
};
/*
Compute the internal state of the widget
*/
ScrollableWidget.prototype.execute = function() {
// Get attributes
this.fallthrough = this.getAttribute("fallthrough","yes");
this["class"] = this.getAttribute("class");
// Make child widgets
this.makeChildWidgets();
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ScrollableWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes["class"]) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
exports.scrollable = ScrollableWidget;
})();

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