1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-24 03:44:41 +00:00

Compare commits

..

484 Commits

Author SHA1 Message Date
Jeremy Ruston
165538180e Version number update for 5.1.21 2019-09-10 16:32:45 +01:00
Jeremy Ruston
42060acb43 Preparing for release of v5.1.21 2019-09-10 16:32:30 +01:00
Jeremy Ruston
978d52f3e8 Merge branch 'tiddlywiki-com' 2019-09-10 16:21:55 +01:00
Jeremy Ruston
b8129b6e36 Update release note 2019-09-10 16:21:37 +01:00
Jeremy Ruston
b5e4cc0cc8 Docs: Clarify reveal widget animation requirements 2019-09-10 16:07:36 +01:00
Bimba Laszlo
3732c83ad4 Fix GitLab saver Base64 encoding (#4255) 2019-09-10 14:16:06 +01:00
Jeremy Ruston
ff6070f033 Update release note 2019-09-09 16:48:12 +01:00
Cameron Fischer
fb12807a33 Reverting changes to stringifyList (#4249)
I (Flibbles) changed it so that lists generated by stringifyList
would always be compatible with a filter parser, but since lists
are not, and never will be, a subset of filters, there isn't a
point.

More importantly, wrapping negative numbers like "-7" in brackets
would mess up some math stuff.
2019-09-09 14:56:40 +01:00
Jeremy Ruston
953038f0b2 Don't use field indexer when looking for blank/missing fields
Fixes #4247
2019-09-09 14:47:27 +01:00
Jeremy Ruston
f74e4c520d Add docs for tm-rename-tiddler
Fixes #4246
2019-09-09 14:38:29 +01:00
Xavier Cazin
85da202cca fr-FR: small fix in tiddler date format (#4250) 2019-09-09 14:28:56 +01:00
Simon Huber
00fb4190f2 Fix whitespace around fields inputs (II) (#4240) 2019-09-09 14:17:32 +01:00
Simon Huber
19d2aab6b9 Remove text-shadow for tags in sidebar (#4245)
For consistency with tags in the main story river
2019-09-07 09:27:00 +01:00
Jan-Oliver Kaiser
fff97e7326 Signing the CLA (#4244) 2019-09-07 09:06:19 +01:00
Jeremy Ruston
996ee52cf9 External-attachments plugin: Fix bug on Windows
Fixes #4237
2019-09-06 17:40:03 +01:00
Jeremy Ruston
bb036ced93 Translators plugin: Minor layout fixes 2019-09-06 15:40:36 +01:00
Jeremy Ruston
ef5c53bf9a Release note updates 2019-09-04 16:04:33 +01:00
Jeremy Ruston
6899be59e2 Fix date and time for for "Hidden Setting: Sync Polling Interval" 2019-09-03 19:26:23 +01:00
Jeremy Ruston
9e67be5b6c Fix date for "Hidden Setting: Sync Polling Interval" 2019-09-03 19:25:00 +01:00
Jeremy Ruston
7f5a5dbe09 Merge branch 'tiddlywiki-com' 2019-09-03 10:12:01 +01:00
Simon Huber
6fb2a33847 Add missing foreground color to tc-btn-invisible (#4203) 2019-09-03 09:50:24 +01:00
Bimba Laszlo
9305881efb Syncadapter uses different conditions for loading and saving (#4211)
The description was ambiguous.
2019-09-03 09:49:17 +01:00
Jeremy Ruston
6496107a32 Docs: Clarify that webserver API get all tiddlers only returns non-system tiddlers
Fixes #4212
2019-09-03 09:47:55 +01:00
Jeremy Ruston
0610a7b1eb Hidden setting: Sync Polling Interval 2019-09-03 09:42:16 +01:00
Jeremy Ruston
16652f926f Fix inverted default HTML-class for items in toc and toc-expandable 2019-09-03 09:41:34 +01:00
Mark Stegeman
dd09266b46 Fix inverted default HTML-class for items in toc and toc-expandable
5d36b484c6 swapped the "emptyValue" and "value" that determine the
HTML-class for toc items, but did not change the default values for
"itemClassFilter" in "toc" and "toc-expandable" to reflect this.
2019-09-02 19:31:13 +02:00
Jeremy Ruston
27858625df Merge pull request #4232 from markstegeman/patch-1
Signing the CLA
2019-09-02 18:28:03 +01:00
markstegeman
ab24d58b11 Signing the CLA 2019-09-02 19:27:06 +02:00
Jeremy Ruston
ba7e7fd649 fix "Open" SideBar tab (#4228) 2019-09-02 18:08:09 +01:00
Simon Huber
1873785ef6 Fix whitespace around field inputs (#4227) 2019-09-02 18:07:45 +01:00
Nils-Hero Lindemann
2008a617b5 Signing the CLA (#4204) 2019-09-02 15:55:24 +01:00
markkerrigan
8053cf1806 Signing the CLA (#4197) 2019-09-02 15:50:39 +01:00
Simon Huber
c81bf49704 fix "Open" SideBar tab 2019-09-01 11:00:09 +02:00
Nils-Hero Lindemann
1c5b3e3d8d Remove duplicate code from transcludeblock parser (#4221) 2019-08-30 17:20:16 +01:00
Jeremy Ruston
82d18ad1fa Update release note for v5.1.21 2019-08-30 15:34:26 +01:00
Simon Huber
4ef9ccbab9 Fix bug with wikitext in fieldnames #4218 2019-08-30 10:44:23 +01:00
Jeremy Ruston
83386f34b5 Restore performance instrumentation to be disabled by default
Fixes #4201
2019-08-30 10:42:01 +01:00
bimlas
b88812233c Hidden setting: Sync Polling Interval 2019-08-29 08:58:17 +02:00
Jeremy Ruston
471b73158a Fix overeager alerts from core module overwrite upgrade warning
This fixes a bug in #3634, and refines the logic so that the warning is only given if the incoming tiddler exists as a shadow tiddler. (In my case I have several draft core modules inactive in my notes wiki and they were erroneously suppressed from the upgrade).
2019-08-28 14:44:46 +01:00
StefanSTFG
990619b634 Fixed 3 typos in the example in line 88 (#4207)
1.     Removed closing square bracket after <currentTiddler>
2.    Changed capital 'P' in addprefix
3.    Added missing slash at the end
2019-08-27 17:10:00 +01:00
StefanSTFG
8d3dfdebe3 Signing the CLA (#4206) 2019-08-27 17:09:23 +01:00
Jeremy Ruston
654eda02c6 Remove reference to stacked story view from prerelease introduction
It's confusing
2019-08-24 12:17:17 +01:00
Jeremy Ruston
a170210069 Fix crash with action-deletefield and missing tiddler attribute
Fixes #4188
2019-08-24 11:39:00 +01:00
Cameron Fischer
67066fe86e Improve handling for titles starting with +-~= (#4084) (#4087)
* $tw.utils.stringifyList will wrap tiddlers starting with `+-~=` in brackets.
2019-08-24 12:35:03 +02:00
Simon Huber
fada96651e Update "Open" tab to use tv-config-story-list (#4189) 2019-08-24 11:27:20 +02:00
Rob Hoelz
0402dbd48d Pass pathFilters as an array (#4174)
* Pass pathFilters as an array

Otherwise, when we try to iterate over pathFilters in the filesystem
utils module, we end up iterating over each character in the filter
string, which ends up generating 'Filter error_ Missing [ in filter
expression.tid' as the tiddler's filename

Fixes GH #4173

* Allow for multiple path filters to be specified

...via $:/config/FileSystemPaths, split by newlines
2019-08-22 10:24:40 +02:00
Jeremy Ruston
bab1bca485 Coding style tweaks 2019-08-14 23:00:01 +01:00
Jeremy Ruston
a986e4f7d6 Prepare for v5.1.21-prerelease 2019-08-09 15:38:36 +01:00
Jeremy Ruston
f49c55fe3c Version number update for 5.1.20 2019-08-09 14:17:35 +01:00
Jeremy Ruston
ad175e222b Preparing for v5.1.20 release 2019-08-09 14:16:39 +01:00
Jeremy Ruston
2a3ea14437 Docs: More updates to build docs 2019-08-09 14:09:15 +01:00
Jeremy Ruston
762810361f Docs: Update the build docs 2019-08-09 14:08:13 +01:00
Jeremy Ruston
9244a2f4fd Bring over remaining scripts from build.jermolene.github.io 2019-08-09 10:30:26 +01:00
Jeremy Ruston
067e8a9f94 Merge branch 'tiddlywiki-com' 2019-08-09 10:29:46 +01:00
Jeremy Ruston
a91ae1a877 More Catalan updates 2019-08-08 15:22:57 +01:00
Bram Chen
2be09f23eb Corrected typo in help link for GitLab saver (#4169)
* for zh-Hant and zh-Hans
2019-08-08 09:55:49 +01:00
Xavier Cazin
59264bbf2a fr-FR translation updates (#4167)
* Typo in GitLab saver link

* Improve fr-FR DateFormat for ViewTemplate subtitles

* Update fr-FR translations for Saving/GitService
2019-08-07 18:01:02 +01:00
Bram Chen
803c2c749f Add chinese translations for Saving/GitService (#4137) 2019-08-06 21:05:35 +01:00
Jeremy Ruston
c3df892321 More release note tweaks 2019-08-06 18:46:28 +01:00
Jeremy Ruston
68e6298e7d Tweaks to release note 2019-08-06 17:41:11 +01:00
Jeremy Ruston
9df64c1ecf Update Catalan translation 2019-08-06 16:02:43 +01:00
Jeremy Ruston
b8ac2d7a06 Release note: update contributor list 2019-08-06 14:57:46 +01:00
Jeremy Ruston
41d30bebc8 Update release note 2019-08-06 14:53:23 +01:00
Jeremy Ruston
6df7b617fb Docs tweaks 2019-08-06 14:53:14 +01:00
Simon Huber
31e7dbf020 Add "preventScroll" option to tm-focus-selector message (#4157)
* add "delayed" option to tm-focus-selector message

this delays the focussing for the time of the animation duration if delayed="yes" or delayed="true"

this is useful when navigating the story river up and down with keyboard shortcuts and the shortcuts focus the title input if a navigated tiddler is in edit mode -> navigation doesn't jump but stays smooth

* Update rootwidget.js

* Update WidgetMessage_ tm-focus-selector.tid

* add preventScroll="true" tip
2019-08-06 13:12:21 +01:00
Jeremy Ruston
f49ab78ebd Docs: Add another example to Conditional Operators 2019-08-05 14:28:59 +01:00
Jeremy Ruston
41d3e80397 Update release note
More to come, I've only got as far as June 28th...
2019-08-05 14:28:42 +01:00
Simon Huber
e1bb532d98 Fix popups not being cancelled correctly (#4158) 2019-08-04 13:01:24 +01:00
Jeremy Ruston
8159c4a865 Fix navigator widget when story and/or history attributes are missing
To fix the crash described here: https://groups.google.com/d/msgid/tiddlywiki/c5461591-bf27-4c85-9f27-9eef14c38816%40googlegroups.com?utm_medium=email&utm_source=footer
2019-08-04 11:34:45 +01:00
Simon Huber
0903fd2fec Update katex plugin to latest v0.10.2 (#4133)
* update katex.min.js to v0.10.2

* update katex-without-fontface.min.js to latest

* Update katex.min.css

* Update katex.js

* update katex fonts

* Delete katex.js ...

... we're using katex.min.js

* add version number to plugin.info

* Update readme.tid

* Create katex.js

* Update plugin.info
2019-08-03 17:36:40 +01:00
Simon Huber
62a7fa4203 Pop storyview for fields list in EditTemplate (#4148) 2019-08-02 15:05:30 +01:00
Simon Huber
776ce0f65f Pop storyview for tabs macro (#4149) 2019-08-02 15:05:12 +01:00
Simon Huber
4952be6518 "Open" SideBar tab: use tv-story-list and tv-history-list (#4150) 2019-08-02 15:03:09 +01:00
Simon Huber
427fbfd623 Fix tags not animating in viewtemplate (#4142)
* fix tags not animating in viewtemplate

this PR uses the addprefix removesuffix filters, not a new filter as proposed in #3763

* use new `then` operator
2019-08-02 14:32:36 +01:00
Jeremy Ruston
17711657b6 Add then and else operators
Fixes #4147
2019-08-02 14:27:58 +01:00
Jeremy Ruston
394725f00c Fix edit-bitmap crash with missing tiddlers
Fixes #4141
2019-08-02 09:16:36 +01:00
Simon Huber
9a2de11db1 Pop storyview for topright and topleft bar (#4146)
* pop storyview for topright bar

* pop storyview for topleft bar
2019-08-02 09:03:51 +01:00
Simon Huber
fab67a463b Pop storyview: fix bug where targetElement is null (#4143) 2019-08-02 08:51:16 +01:00
Simon Huber
64fe260f4d Fix: correct handling of tc-popup-keep when cancelling ... (#4144)
... popups through focussing inputs
2019-08-02 08:49:06 +01:00
Simon Huber
8db893b9c9 Add pop storyview for pagecontrols (#4145)
this PR adds the pop storyview to the page-control buttons in the sidebar
2019-08-02 08:47:47 +01:00
Simon Huber
2d4831f920 Tag-picker: delete double-definition of tag-actions (#4139) 2019-08-01 17:32:39 +01:00
Jeremy Ruston
0a6870656f Fix typo in b5653babd 2019-07-31 21:39:52 +01:00
Bimba Laszlo
b5653babdf Add GitLab saver, apply common lingo to Git savers (#3931)
* Transform GitHub saver to work with GitLab as well

You can choose which provider you want to use, the data is given in the
same place.

I tried to avoid code duplication, so service providers' unique
properties are in separate files, the settings of the selected provider
are loaded.

In two fields I am not sure that it fits into the current structure:

* module-type: gitservice
  Which module is a `gitservice` type, it will be listed in the
  drop-down menu.
* default-api-url: https://gitlab.com/api/v4
  The default URL to access the provider's API.

This is just a sketch, not a final version, suggestions for modification
are welcome!

* Rename saver from GitHub to GitService, update docs

* Split GitHub and GitLab to separate savers, apply common lingo

Sadly, it doesn't seem to make much sense to search for common parts in
the code, because there might be a Git service that is very different
from the GitHub API (such as BitBucket). Therefore, I feel that Git
savers are not able to share other than the translations.

I deleted the defaults values from the translations and set it to the
text entry because they should not depend on the translations.

* Add more information about the password field

It is not clear how to create a personal access token, thus added a link
to the help pages. In addition, GitLab only accepts personal access
token, GitHub also accepts the password, so I made this clear.

* Extract commit message to lingo

* Fix indentation

* Use improved base64 encoder

Fix conflict with a06acc4eb8
2019-07-31 21:38:52 +01:00
Jeremy Ruston
3afaa9de9a Add support for anchored searches 2019-07-31 21:36:12 +01:00
Jeremy Ruston
dbaccf792d Use the new "match" operator across the core
Instead of the old "prefix" hack
2019-07-31 09:30:16 +01:00
Jeremy Ruston
5faae2547d Add "match" operator for string comparison
Fixes #4130
2019-07-31 09:11:12 +01:00
Jeremy Ruston
7f78065992 Fix unnecessary "list" field creation when renaming tiddlers
Fixes #4120
2019-07-30 17:10:53 +01:00
Simon Huber
cb1d35e230 More Plugins - Button: use primary color (#4075)
* Update AddPlugins.tid

* Update base.tid

* Update AddPlugins.tid

* Update AddPlugins.tid

* Update base.tid
2019-07-30 13:49:40 +01:00
Simon Huber
0a2d532a7b Fix bug where edit widget input-tag is empty (#4088) 2019-07-30 13:49:05 +01:00
Simon Huber
e669ec098f Fix beyboard widget empty parameters (#4094) 2019-07-30 13:47:56 +01:00
Jeremy Ruston
269fa5313f Fix for index ordering issue
Fixes #4082

This version removes selective updating of the tag index, instead completely clearing the index on each update. I'm investigating restoring that optimisation.
2019-07-28 16:39:34 +01:00
Simon Huber
b30746813b Fix: store noStateReference in popup.js (#4115) 2019-07-26 17:13:53 +01:00
Jeremy Ruston
32c5490a20 Improve contribution banner
* Make it work with titles with crazy characters
* Hide the banner for tiddlers that didn't originate on GitHub

Fixes #4116 and #4129
2019-07-26 12:46:27 +01:00
jed
e86d4d29d5 Fix th-renaming-tiddler (see #4023) (#4037)
* Remove the th-renaming-tiddler hook from navigatior.js

The hook is invoked in the renameTiddler function which would cause the same hook to be called twice, and the version in the navigator widget didn't have the correct inputs and return value according to the documentation.

* Make it so that the th-renaming-tiddler hook isn't called twice

by removing it from the navigator.js file
2019-07-24 18:12:09 +01:00
Jeremy Ruston
cbd07465f3 Fix test rig shadow tiddler behaviour
The test rig previously used a simplified implementation of shadow tiddlers which broke with the new indexing engine. There was also a problem that made that even if indexers were disabled they were still initialised.

This PR fixes both problems, in preparation for fixing #4082
2019-07-16 16:53:37 +01:00
Jeremy Ruston
27b75f3922 Fix missing .tid extension from #4112 2019-07-16 15:43:18 +01:00
morosanuae
8a53cca00d Adding the "Font Awesome 5 Free SVGs for TiddlyWiki" resource site (#4112) 2019-07-15 18:09:40 +01:00
Mario Pietsch
5d36b484c6 Toc cosmetic changes for tabbed-xxxx macros (#4101)
* toc cosmetic changes.

* toc in right sidebar should use toc-item if itemCalssFilter is not defined
2019-07-15 12:31:50 +01:00
Simon Huber
e2bad34e89 Fix bug and typo in framed.js (#4110) 2019-07-15 10:11:36 +01:00
Cameron Fischer
b67e088e55 Reducing function calls across board (#4102) 2019-07-14 16:20:27 +01:00
Jeremy Ruston
cb77f3f503 Make big green (etc) buttons a bit rounder 2019-07-14 16:11:28 +01:00
Jeremy Ruston
8226efa154 Merge pull request #4106 from BurningTreeC/patch-17
fix missing tag for advanced-search keyboard shortcut
2019-07-14 16:08:01 +01:00
Jeremy Ruston
ac49b4d20c Cancel open popups when inputs get focus 2019-07-14 16:07:36 +01:00
Simon Huber
78cc80db13 fix missing tag for advanced-search keyboard shortcut 2019-07-14 17:06:09 +02:00
Jeremy Ruston
2bcb36f151 Add advanced-search kb shortcut ctrl-shift-A 2019-07-14 15:49:15 +01:00
Jeremy Ruston
8e7c0907f8 Add checkactions attribute to Checkbox widget
See discussion at https://groups.google.com/d/msgid/tiddlywiki/526754d5-8786-49cd-aaa1-c77311670116%40googlegroups.com:

The history here is that in v5.1.14 we added an "actions" attribute to the checkbox widget that specified an action string to be specified whenever the state of the checkbox changed. The same action string is executed regardless of whether the checkbox was checked or unchecked.

Then in v5.1.16 we merged https://github.com/Jermolene/TiddlyWiki5/pull/3182 which added the "uncheckactions" attribute. The difference between the two is that the uncheckactions are only executed if the checkbox is unchecked. The main "actions" attribute is executed before any actions in "uncheckactions", which makes it possible to arrange things so that the "actions" attribute sets things to the checked state while the "uncheckactions" attribute overwrites those changes to set things to the unchecked state.

In retrospect, it would have made more sense to have also added a "checkactions" attribute that was executed only if the checkbox was checked. I'll investigate adding it for v5.1.20.
2019-07-14 13:42:43 +01:00
Simon Huber
66dc7df745 Update popup.js 2019-07-14 09:37:53 +02:00
Simon Huber
fd88be4173 Update ShortcutInfo.multids 2019-07-14 07:25:50 +02:00
Simon Huber
880a2aa153 Update ShortcutInfo.multids 2019-07-14 07:25:02 +02:00
Simon Huber
173e9c6c3a add advanced search key combination ctrl-shift-A 2019-07-14 07:23:47 +02:00
Simon Huber
a87a299aa9 add advanced-search kb shortcut 2019-07-14 07:22:46 +02:00
Jeremy Ruston
f5b2599432 Make it possible to distinguish the two different sidebar elements with the class "tc-sidebar-lists" 2019-07-11 22:00:28 +01:00
Simon Huber
ba2f4822dd Merge branch 'master' into patch-10 2019-07-11 18:19:49 +02:00
Jeremy Ruston
a3a25f2453 Fix bug with popup cancelling if state is in a field other than 'text' 2019-07-11 17:07:25 +01:00
Simon Huber
ecbbe87a0d popup cancelling - use state reference
in the google group there's a discussion: https://groups.google.com/forum/#!topic/tiddlywiki/_mDDZ1jpMgU

buttons allow setting a state-reference for popups but the popup mechanism doesn't respect that
2019-07-11 07:35:06 +02:00
Simon Huber
217670cdf3 Update engine.js 2019-07-10 09:57:59 +02:00
Simon Huber
345a6a0f90 Update framed.js 2019-07-10 09:57:11 +02:00
Simon Huber
c647b42574 Update simple.js 2019-07-10 09:56:34 +02:00
Simon Huber
7811614d53 Update popup.js 2019-07-10 09:55:32 +02:00
Simon Huber
8aa6427d67 Update factory.js 2019-07-10 09:54:35 +02:00
Jeremy Ruston
86286c6fce Don't generate filenames starting with a period 2019-07-09 12:22:52 +01:00
Simon Huber
f7da4bafae big-green button: border-radius 2px
make it a bit more beautiful
2019-07-08 11:14:32 +02:00
Jeremy Ruston
08c900786e Make katex toolbar (text buttons) button same color 2019-07-07 17:31:54 +01:00
Simon Huber
efa593bb50 make katex toolbar (text buttons) button same color 2019-07-07 18:00:17 +02:00
Jeremy Ruston
19f2280803 German translations 2019-07-07 13:02:47 +01:00
pmario
6721d70de5 german translations 2019-07-07 01:08:25 +02:00
Jeremy Ruston
7b3d190974 Create Hidden Setting ViewTemplate and EditTemplate.tid 2019-07-05 07:29:06 +01:00
Jeremy Ruston
3997600137 Update chinese translations 2019-07-05 07:23:11 +01:00
Jeremy Ruston
9f31867731 Update core/modules/savers/github.js 2019-07-05 07:21:53 +01:00
Bram Chen
a06acc4eb8 Update core/modules/savers/github.js
Using "$tw.utils.base64Encode()" to encode content of data instead of calling module library directly.
2019-07-05 11:03:05 +08:00
BramChen
6f3db0118e Update chinese translations
* Add hint of toggle-sidebar keyboard shortcut
2019-07-05 10:30:19 +08:00
Jeremy Ruston
f5acf3adaa Make Using Stamp show up in Recent tab 2019-07-04 22:27:19 +01:00
Jeremy Ruston
5ac2064d18 Add toggle-sidebar keyboard shortcut 2019-07-04 22:18:40 +01:00
Jeremy Ruston
2a4c60b23d Allow tm-open-window to specify a page title 2019-07-04 15:59:34 +01:00
Jeremy Ruston
3edaa652ee Reveal widget: add option to avoid clamping popup position
Fixes #4041
2019-07-04 15:58:27 +01:00
Simon Huber
77fedf9582 fix keyboard shortcut 2019-07-04 12:00:10 +02:00
Simon Huber
cf4c4532c3 Update Buttons.multids 2019-07-04 09:00:34 +02:00
Simon Huber
ea0e1357bf Update ShortcutInfo.multids 2019-07-04 08:59:23 +02:00
Simon Huber
ef7210adf4 add alt-shift-S to toggle sidebar 2019-07-04 08:57:49 +02:00
Simon Huber
e91fb29253 add keyboard shortcut toggle-sidebar 2019-07-04 08:56:17 +02:00
Simon Huber
f978355ea4 make Using Stamp show up in Recent tab
... just a "modified" update
2019-07-04 07:50:47 +02:00
Simon Huber
1e1b2e28b6 Create Hidden Setting ViewTemplate and EditTemplate.tid
this PR adds information about the hidden settings for View- and EditTemplate
2019-07-04 07:45:04 +02:00
Jeremy Ruston
d489f61f2a include wiki in options sent to generateTiddlerFilePath 2019-07-03 17:54:58 +01:00
Jeremy Ruston
727d660715 Story PageTemplate: configurable View- and EditTemplates (#4051)
* Story PageTemplate: configurable View- and EditTemplates

* add $:/config/ui/ViewTemplate

* add $:/config/ui/EditTemplate
2019-07-03 17:42:13 +01:00
Simon Huber
6e5566b907 Add whitespace trim to pagetemplate, story and sidebar (#4052)
* add whitespace trim to pagetemplate

* add whitespace trim to story pagetemplate

* add whitespace trim to sidebar pagetemplate
2019-07-03 17:41:23 +01:00
Bram Chen
958b3e7b7c Improve the base64 encode/decode utility functions (#4053)
Make good use of "$:/core/modules/utils/base64-utf8/base64-utf8.module.js"
* Add a new base64Encode()
* Both of base64Encode and base64Decode work for Nodejs and Browsers
2019-07-03 17:39:32 +01:00
Simon Huber
c578566dea add $:/config/ui/EditTemplate 2019-07-03 15:09:32 +02:00
Simon Huber
8a0aef4dcb add $:/config/ui/ViewTemplate 2019-07-03 15:08:43 +02:00
Simon Huber
35a71ad577 Story PageTemplate: configurable View- and EditTemplates 2019-07-03 15:07:06 +02:00
jed
c202ef4201 include wiki in options sent to generateTiddlerFilePath
This adds options.wiki to the object sent to the generateTiddlerFilePath

The function generateTiddlerFilePath can take a wiki in the options object, but generateTiddlerFileInfo doesn't pass the wiki to it.
2019-07-03 12:11:10 +02:00
Jeremy Ruston
f42351e235 Add new readme build script, and update the readme build 2019-07-02 16:53:23 +01:00
Jeremy Ruston
da61917797 list-links macro: trim whitespace
Fixes #4044
2019-07-02 16:53:02 +01:00
Simon Huber
16a53ae394 Use Resources tag for escapecss examples (#4040) 2019-07-02 16:25:34 +01:00
Simon Huber
d1948621d3 Docs for stamp-button optionally wrap selection (#4047)
* make stamp-button optionally wrap selection

* Update Using Stamp.tid
2019-07-02 16:24:48 +01:00
Bram Chen
de04755a0a Fix bug with not definded variable (#4049)
Using the variable "resolveCredentialsFilepath" to provide a good debug information.
2019-07-02 15:40:07 +01:00
Jeremy Ruston
02b141f97f Docs: typo in "Using the external JavaScript template" 2019-07-02 15:35:11 +01:00
Simon Huber
15b576618f Docs: Add information about hidden setting EditTabIndex (#4045) 2019-07-02 15:33:43 +01:00
Simon Huber
91db09bd1e Katex dropdown: add description hint (#4048)
* katex dropdown: add description hint

* Update katex-dropdown.tid
2019-07-02 15:04:57 +01:00
Simon Huber
d2f1debf92 Make escapecss tiddlers show in recent tab (#4032)
* make escapecss show in recent tab

* make escapecss examples show in recent tab
2019-06-29 08:40:46 +01:00
Bram Chen
f6c9150d32 Add chinese translations for hint of sidebar-search keyboard shortcut (#4027) 2019-06-29 08:21:06 +01:00
Simon Huber
2f723dd85a Add docs for escapecss operator (#4028)
* Create escapecss_Operator.tid

* Create escapecss Operator (Examples).tid
2019-06-29 08:17:11 +01:00
Simon Huber
42bde75de2 Update KeyboardShortcuts.tid (#4030) 2019-06-29 08:16:35 +01:00
Simon Huber
112443c054 Update/fix nord palette notification background (#4031) 2019-06-29 08:15:46 +01:00
Jeremy Ruston
7781cb1f8b Streamline wording for sidebar search shortcut 2019-06-28 17:35:17 +01:00
Jeremy Ruston
bf51ae0019 Add keyboard shortcut for focusing sidebar search
Fixes #4020

Fixes #4025
2019-06-28 17:28:24 +01:00
Jeremy Ruston
ed67f4a88b Add new tm-focus-selector message 2019-06-28 17:27:36 +01:00
Bram Chen
274dffe750 Update chinese translations for the revised PaletteManager (#4019)
* Palette/Editor/Delete/Hint
 * Palette/Editor/Names/External/Show
2019-06-26 16:44:31 +01:00
Simon Huber
14003b0e88 Make framed editor use tiddler-editor-background color (#3611)
so we can customise it better if we don't like what we see
2019-06-26 14:53:49 +01:00
Simon Huber
36c7e82cc0 Add/refactor PaletteManager (#3832)
* add PaletteManager

* add hint for "external" palette-names

* macro utility, for local \import only

this tiddler is never meant to be tagged $:/tags/Macro

contains only a colour macro which allows to call `<<colour "...">>` within a tiddler and get the parameter-name instead of the resolved color

used in the PaletteManager to reveal the original color below the color that just uses its color with the colour macrocall

example:

```
\define get-real-index(string)
\import $:/core/macros/utils
<$wikify $name="result" text="""$string$"""> <- does the "colour" macrocall, but the one that returns the parameter name
<<result>>
</$wikify>
\end
<$set name="color" value={{{ [{$:/palette}getindex[color-of-interest]] }}}>

-> <<colour primary>>

<$wikify name="real-color-index" text="""<$macrocall $name="get-real-index" string=<<color>>/>""">

<<real-color-index>> -> primary

...
```

* transclude PaletteManager in snippets/paletteeditor

* transclude PaletteManager in core/ui/ControlPanel/Palette

* Update ControlPanel.multids

* add style for color inputs in PaletteManager

* Update PaletteManager.tid

* Update PaletteManager.tid

* add tooltips & aria-labels

* Update ControlPanel.multids

* Update PaletteManager.tid

* Update PaletteManager.tid

* Update PaletteManager.tid
2019-06-26 12:36:13 +01:00
Simon Huber
31b141097d Tags edittemplate: replace &times; with svg (#3859)
* tags edittemplate: replace &times; with close-button svg

* make close-button smaller + v-aligned middle
2019-06-26 12:34:18 +01:00
Simon Huber
448d108d69 Make ContributionBanner more solid (#3645)
this makes the contribution banner work with "badly" named tiddlers, too
2019-06-26 12:33:44 +01:00
Simon Huber
69d3a47073 Add escapecss filter (#3546)
* add escapecss filter

this filter would allow creating valid css classes from titles containing special characters

we assign a class to an element using `encodeuricomponent[]` so that the class name is encoded

in a stylesheet we create the classname by `<title>escapecss[]` which applies the uri encoding and escapes characters that need to be escaped

* Update encodings.js

* refactor tagToCssSelector, add escapeCssSelector

* use escapeCssSelector

* escape using CSS.escape if it's available

* Update encodings.js

* revert factoring out escapeCssSelector
2019-06-26 12:32:01 +01:00
Simon Huber
e313b0b7ca CSS.escape as startup module (#3574)
* don't know what I'm doing - apply polyfill methods

* don't know what I'm doing add CSS.escape polyfill

* execute polyfills in load-modules

* Delete cssescape.js

* add css-escape polyfill as startup module

* Update load-modules.js

* this was for testing :)

* Update css-escape-polyfill.js

* Update css-escape-polyfill.js
2019-06-26 12:31:22 +01:00
Simon Huber
dc9f4e2de7 Pop storyview: animation - don't x-overflow page (#3857)
... this makes the animation when inserting tiddlers / navigating to tiddlers in the pop storyview less jumpy

it simply sets `overflow-x` to `hidden` for the time of the insert-animation
2019-06-26 11:50:52 +01:00
Robin Munn
cb2bf25563 Fix examples for sentencecase and titlecase (#4010) 2019-06-24 10:36:28 +01:00
Jeremy Ruston
e09ac2ab37 CI: Fix commit field in $:/build 2019-06-23 20:11:55 +01:00
Jeremy Ruston
b580baf5ee Add a "commit" field to the $:/build tiddler 2019-06-21 15:21:10 +01:00
Jeremy Ruston
a6500ba711 DynaView: Suppress local storage errors 2019-06-21 15:19:51 +01:00
Jeremy Ruston
fd8ede07bf Release note updates 2019-06-21 10:52:54 +01:00
Jeremy Ruston
c8d6f3b681 Fix tests for changes to split operator
We now retain any blank strings
2019-06-21 10:36:53 +01:00
Jeremy Ruston
6582b106ee Fixes to split operator, plus instructions for using it to do search and replace 2019-06-21 10:21:52 +01:00
Jeremy Ruston
90684f9f52 Add support for [is[blank]] to detect empty/blank strings 2019-06-21 10:20:37 +01:00
twMat
ceb2d9f119 Update StartupActions.tid (#4002)
Regarding the bulleted tag pills; they should probably also be removed in place of text but I see value in keeping them for the sake of being able to easily peek at what they tag. We should probably have a section under Ctrlpanel>Settings where any startupaction-tiddlers are listed but since we don't yet, then the mentioned tag pills could perhaps remain.... except for the one in the PR.
2019-06-21 08:36:09 +01:00
Robin Munn
9b27f82a80 Fix sentencecase operator, add titlecase operator (#4006) 2019-06-21 08:24:02 +01:00
Jeremy Ruston
d8b79723cd Docs: Remove broken example of checkbox actions attribute
See https://github.com/Jermolene/TiddlyWiki5/pull/3996#issuecomment-503596160
2019-06-19 15:56:07 +01:00
Jeremy Ruston
2e2ed7902c Add sentencecase operator
Fixes #4000
2019-06-19 12:11:02 +01:00
twMat
6fd70f9c11 Docs: Update CheckBox example (#3996) 2019-06-18 10:49:52 +01:00
Bimba Laszlo
6099ec576c Fix typo in docs of performance instrumentation (#3995) 2019-06-18 09:41:50 +01:00
Jeremy Ruston
47dc59cd54 Fix caption for "join" operator docs
Thanks @twMat
2019-06-17 21:44:50 +01:00
Jeremy Ruston
c963680f9c Release note updates 2019-06-17 21:27:50 +01:00
Robin Munn
e6ac709840 Clarify that the split operator does not dedupe (#3981) 2019-06-17 21:21:48 +01:00
Robin Munn
32a2bea7f5 Better examples for mathematics operators (#3982)
Include = before each number in the Mathematics Operators examples,
so that people get used to seeing that in math examples where dupes
are likely.

Only the Mathematics Operators tiddler really needed to be changed;
the example tiddlers for individual operators were already using =.

Fixes #3979.
2019-06-17 21:21:23 +01:00
Robin Munn
62829dc9d3 Add untrunc operator, the mirror of trunc (#3994) 2019-06-17 18:34:30 +01:00
Robin Munn
58cb300a0a Fix typo (#3984) 2019-06-17 18:32:35 +01:00
Robin Munn
a4dcc20797 Signing the CLA as rmunn (#3992) 2019-06-17 18:31:54 +01:00
Xavier Cazin
2002ff72b7 fr-FR translation for GitHub saver related strings (#3988) 2019-06-17 16:46:03 +01:00
Jeremy Ruston
250a1e5356 Release note: Typo 2019-06-14 09:26:24 +01:00
Jeremy Ruston
630a0ecf9e Remove test for concat operator 2019-06-13 16:55:55 +01:00
Jeremy Ruston
fef2ea97a1 Final chunk of docs for new maths/string operators 2019-06-13 16:53:23 +01:00
Jeremy Ruston
73eb7fbd4e Maths operators: Remove concat (same as addsuffix) and add splitregexp 2019-06-13 16:52:19 +01:00
Jeremy Ruston
fc09f8e331 Tree macro: allow separator to be customised 2019-06-13 08:47:42 +01:00
twMat
1a08430a0c Docs: Fix typo in TextReference.tid (#3978)
minor correction - or am I mistaken?
2019-06-12 22:03:01 +01:00
Jeremy Ruston
23dd8da22c Remove draft inadvertantly included in e5e5b1d73
Thanks @twMat
2019-06-12 12:48:14 +01:00
Jeremy Ruston
e5e5b1d739 Fixes for 7fcdc83ba
Thanks @twMat
2019-06-12 11:34:07 +01:00
Jeremy Ruston
7fcdc83bae First batch of docs for the maths operators 2019-06-11 17:18:51 +01:00
Jeremy Ruston
86387a9185 Add some error trapping to maths operators 2019-06-11 17:18:18 +01:00
Jeremy Ruston
dd7837d164 Fix issue with allafter operator
Fixes #3962
2019-06-11 09:38:14 +01:00
Jeremy Ruston
4a66ecbf6f Update release note 2019-06-10 21:06:25 +01:00
Jeremy Ruston
f02352f6a1 Use default link text when link widget has no content
Fixes #3974
2019-06-10 21:04:21 +01:00
Jeremy Ruston
cd412d8ccb Update release note 2019-06-10 18:24:38 +01:00
Jeremy Ruston
18fe112da7 Extend the enlist operator to optionally not de-duplicate 2019-06-10 17:54:46 +01:00
Jeremy Ruston
37bb75f0cf Add support for = prefix for filter runs that doesn't remove duplicates 2019-06-10 17:54:20 +01:00
Jeremy Ruston
ac1d5b828d Fix regression in 7fcd2f132
Previously we saved tiddlers as .tid files using this template that explicitly excludes the "bag" field:

https://github.com/Jermolene/TiddlyWiki5/blob/master/core/templates/tid-tiddler.tid

Now we generate both .tid and .json files programmatically, and so we have to explicitly exclude the bag field
2019-06-10 17:52:26 +01:00
Jeremy Ruston
55bc6e086f Tweaks and fixes for the release note 2019-06-09 17:26:34 +01:00
Jeremy Ruston
6fdc5c8cb2 Docs: Update performance notes 2019-06-09 17:09:35 +01:00
Jeremy Ruston
7590977dd5 Update release note 2019-06-09 17:09:11 +01:00
Jeremy Ruston
1e8a56768f Update ListWidget docs
Fixes #3964
2019-06-08 17:34:06 +01:00
Jeremy Ruston
8012a3508f Ensure tiddlyspot saver works with local storage disabled
Fixes #3955
2019-06-08 16:38:13 +01:00
Jeremy Ruston
abb3c01505 Catalan Translation update 2019-06-08 13:19:41 +01:00
Jeremy Ruston
28c732d2be Improve action-createtiddler to return a draft title too 2019-06-04 12:33:01 +01:00
Jeremy Ruston
72c64013c7 Fix control panel stylesheets tab to use $:/state/... instead of $:/config/... 2019-06-03 13:28:59 +01:00
Jeremy Ruston
9c2726c530 Remove $tw.perf.log() banner under Node.js 2019-06-03 13:28:41 +01:00
Xavier Cazin
427b56039b fr-FR translations of Help on the savewikifolder and deletetiddlers commands (#3966)
* fr-FR translation of Help on the savewikifolder command

* fr-FR translation of Help on the deletetiddlers command
2019-06-02 20:49:50 +01:00
LordRatte
736ac9052d Update TiddlyDrive info on Tiddlywiki.com (#3961)
* Update TiddlyDrive info

* Accept Licence
2019-05-31 18:11:17 +01:00
twMat
6c08fec2ee Update Saving on TiddlySpot.tid (#3960)
Included mention of community created (i.e created by me) "shortcut" to set up new TW5 on TS.
2019-05-31 16:05:35 +01:00
Jeremy Ruston
147d758931 Add version tags for deletetiddlers and savewikifolders commands
@BramChen -- I added the tag to the Chinese translations, too, let me know if it is not right.
2019-05-31 08:38:34 +01:00
Bram Chen
5f6abad3c5 Update chinese translations (#3959)
* Add chinese translations for Saving/GitHub/ServerURL

* Improve simplified chinese wording

* Add chinese help text for deletetiddlers command
2019-05-31 08:36:19 +01:00
Jeremy Ruston
5b09881679 Add new deletetiddlers command 2019-05-30 16:54:57 +01:00
donmor
496610aa49 Signing the CLA for @donmor (#3957) 2019-05-30 09:42:57 +01:00
Jeremy Ruston
c80fcf19c0 More browser storage fixes
See 698733a4a
2019-05-29 09:37:48 +01:00
Jeremy Ruston
698733a4ad Fix crashes when localStorage not available
As reported by @bimlas in https://github.com/Jermolene/TiddlyWiki5/issues/3945#issuecomment-496797809
2019-05-29 09:01:11 +01:00
Jeremy Ruston
a8f70b08a8 Add indexes to the wiki store to improve performance (#3951)
* First pass at modular wiki indexes

An exploratory experiment

* Fix tests

* Faster checking for existence of index methods

We don't really need to check the type

* Use the index for the has operator

* Fix typo

* Move iterator index methods into indexer modules

Now boot.js doesn't know the core indexers

* Fix up the other iterator index functions

* Fix crash with missing index branch

* Limit the field indexer to values less than 128 characters

* Fallback to the old manual scan if the index method returns null
* Sadly, we can no longe re-use the field indexer to accelerate the `has` operator, because the index now omits tiddlers that have field values longer than the limit

Still need to make the index configuration exposed somehow

* Rearrange tests so that we can test with and without indexers

We also need to expose the list of enabled indexers as a config option

* Test the field indexer with different length fields

So that we test the indexed and non-indexed codepaths
2019-05-24 21:07:37 +01:00
Jeremy Ruston
b992b79adb Merge branch 'tiddlywiki-com' 2019-05-24 18:24:59 +01:00
Jeremy Ruston
feab75a6d1 Add support for preloading plugins by path instead of name 2019-05-24 12:06:11 +01:00
Jeremy Ruston
2f8053265e Performance: Add average filter execution time 2019-05-20 12:50:10 +01:00
Jeremy Ruston
409a297a63 Docs: Fix inaccuracies in "has" filter docs 2019-05-18 15:55:34 +01:00
Kartik Saranathan
ba0da99b17 Docs: fix typo (#3949) 2019-05-16 17:28:09 +01:00
Jeremy Ruston
634ac92ba2 Update splash screen to add new release banner
See #3935
2019-05-11 19:48:06 +01:00
Jeremy Ruston
184fd9dda8 Docs for Performance Instrumentation improvements
Left off e8d1fbba6
2019-05-11 19:28:09 +01:00
Jeremy Ruston
94d18a2f18 KaTeX: Fix bug with embedded SVGs
See https://github.com/Jermolene/TiddlyWiki5/issues/2500#issuecomment-489976530
2019-05-11 17:31:35 +01:00
Jeremy Ruston
ff85fcfe93 Fix typo from e8d1fbba6 2019-05-10 16:03:24 +01:00
Jeremy Ruston
e8d1fbba6c Performance Instrumentation: Track execution times for individual filters
Fixes #3941
2019-05-10 15:56:01 +01:00
Jeremy Ruston
7869546fef Speed up reveal widget
It turns out that the `localeCompare` function used by `compareStateText()` is very, very slow. Replacing it with a straightforward equality test makes one of my test rigs be 10x faster...

Note that this PR reverts the behaviour of match/nomatch to that before #3157. That change was not backwards compatible in that the switch to localeCompare meant that é === e, now it doesn't again.
2019-05-10 08:47:00 +01:00
Jeremy Ruston
dddfb7ce67 Merge remote-tracking branch 'origin/tiddlywiki-com' 2019-05-03 11:20:39 +01:00
Jeremy Ruston
5ae14a16ec Classic Storyview: Optimise for animation duration of zero (part 2)
See fddc5d4ee
2019-05-02 21:21:22 +01:00
Jeremy Ruston
fddc5d4ee6 Classic Storyview: Optimise for animation duration of zero (part 1)
Approximtely 50% speed improvement in tests opening a storyview with 8,000 entries.

(I've deferred the indentation adjustments until the next commit so that the git diffs are clearer)
2019-05-02 21:20:24 +01:00
Jeremy Ruston
091864ddaf Browser messaging: suppress logging
Commented out because it can be useful for debugging.
2019-05-02 20:21:58 +01:00
Jermolene
07198b9cda Update view toolbar "new here" button
Avoiding textual substitution fixes probems with tiddler titles containing double square brackets.
2019-04-23 17:54:49 +01:00
Jermolene
4401e71498 Docs: Update WebServer Parameter: csrf-disable 2019-04-23 17:53:19 +01:00
Bram Chen
df416814b1 Update chinese translations (#3917)
* Add chinese translations for Saving/GitHub/ServerURL

* Improve simplified chinese wording
2019-04-16 15:56:05 +01:00
Jermolene
b7e0930122 savewikifolder: Fix custom plugin fields
We need to carry across all plugin fields into the tiddlywiki.info file
2019-04-16 11:59:34 +01:00
Jermolene
0a5c826816 GitHub Saver: Fix ServerURL name 2019-04-16 10:15:58 +01:00
Jermolene
25c0ebb523 GitHub Saver: Make server URL configurable 2019-04-15 21:30:59 +01:00
Jermolene
b32a5aa9af GitHub saver: Fix problem with saving to a non-existent directory 2019-04-15 21:08:04 +01:00
Jermolene
232eba2f7d Http utilities: add xhr object to callback 2019-04-15 21:07:23 +01:00
Talha Mansoor
04a4a0f92e Add support of language aliases in highlight.js plugin (#3898)
listLanguages() returns a list of supported languages. It does not
return language aliases.

highlight.js has extensive support of language aliases which can be 
viewed here

https://highlightjs.readthedocs.io/en/latest/css-classes-reference.html#language-names-and-aliases

But because of using listLanguages(), TW does not take advantage of 
alias.

getLanguage() method on the other hand supports aliases.

https://highlightjs.readthedocs.io/en/latest/api.html#getlanguage-name

To summarize, now user can use javascript, js or jsx for the code block. getLanguage() will return an object which means highlight.js supports
this language.
2019-04-15 18:45:45 +01:00
Jermolene
0513837228 Ensure tiddler.getFieldStringBlock uses a deterministic ordering
Makes diffs easier to track
2019-04-14 14:23:49 +01:00
Bram Chen
58cdbbf865 Add chinese help texts for the new savewikifolder command (#3911) 2019-04-14 14:14:20 +01:00
Jermolene
373afd72c8 Add savewikifolder command
Makes it much easier to convert a TiddlyWiki HTML file into a full wiki folder.
2019-04-14 12:04:00 +01:00
Jermolene
7fcd2f132e Filesystemadaptor: Improve handling of JSON files
Fixes #3875

* Use .json files (instead of .tid) for any tiddler whose fields contain values that can't be stored as a .tid file
* Save application/json tiddlers as .json files
* Refactor most of the file handling as re-usable utilities
2019-04-13 14:59:44 +01:00
Jermolene
edd3156430 Improve loading/importing of JSON files
First part of fix for #3875

The idea is to do a better of job of distinguishing JSON files that contain tiddlers versus those that contain plain blobs of JSON that should be stored as a single application/json tiddler.

Under Node.js, .json files with an accompanying metafile are always treated as a JSON blob. Without a meta file, those that appear to not contain valid tiddlers are returned as a JSON blob, otherwise the tiddlers within the file are imported.

In the browser, we don't have .meta files so we rely on the valid tiddler check.
2019-04-13 14:47:27 +01:00
Jermolene
8c72a28f0c Add ability to load plugins via the command line
Fixes #3907
2019-04-12 18:09:16 +01:00
00SS
61db047870 Docs: Update Headings in WikiText.tid (#3908)
Changed the example to use the **wikitext-example** macro and pointed out that wikitext only works till `<h6>`
2019-04-12 11:44:58 +01:00
Bimba Laszlo
9b72eabd1a Fix crash in GitHub saver (#3905)
If the path was not specified, RSOD error occurred when we wanted to
download the wiki:

  Uncaught TypeError: Cannot read property 'substring' of undefined
2019-04-11 08:21:55 +01:00
00SS
12b08b7abf Docs: Update ListMacro.tid (#3754)
Addressing 2 issues.
1) If the caption field of a tiddler is empty
2) A note addressing no input titles resulting in a Filter Run as brought up on [Google Groups](https://groups.google.com/forum/?hl=en#!topic/tiddlywikidev/VNl_cwu_rIE)
2019-04-10 11:22:12 +01:00
00SS
53124e1d82 DOCS: Update: TiddlyWiki5 Squared by Iannis Zannos.tid (#3773)
* Update TiddlyWiki5 Squared by Iannis Zannos.tid

Link no longer works. Changed it to the github page.

* Update TiddlyWiki5 Squared by Iannis Zannos.tid

Fixed URL linking to the "ur" field
2019-04-10 11:17:54 +01:00
00SS
4ecc99c9d5 DOCS: Correction: How to change the sort order of sub-branches in a TOC macro.tid (#3783)
Changed line
`<<toc-selective-expandable  "TableOfContents" "sort{fuzzy}">>`
to
`<<toc-selective-expandable  "TableOfContents" "sort{!!fuzzy}">>`

Tested that this is the correct code.
2019-04-10 11:17:07 +01:00
Bram Chen
61d87875ff Add chinese translations for configuration of GitHub saver (#3899) 2019-04-09 08:13:14 +01:00
Jermolene
73703da2e7 Minify base64-utif8 module
Minified with https://skalman.github.io/UglifyJS-online/
2019-04-08 21:37:32 +01:00
Jermolene
aa5eaa98fc Add a GitHub saver
Fixes #3890

I think it would be useful to have a simple tutorial for setting up saving via GitHub pages.
2019-04-08 21:08:58 +01:00
Simon Huber
662ae91067 Bugfix: reveal widget regression! (#3897) 2019-04-06 10:27:37 +01:00
Jermolene
d5fa68b46a Simplify PageTemplate
We no longer need to mess around with the currentTiddler variable to be able to access to the "name" field of the current language
2019-04-05 09:11:54 +01:00
Jermolene
6e81122fa3 Restore exclude parameter for selective TOC macros
Reverting 94607aa9cd
2019-03-30 12:10:42 +00:00
Jermolene
6575db07c7 Docs typo 2019-03-30 12:06:46 +00:00
Jermolene
f4d8c90191 Add missing "from-version" tags to new features 2019-03-30 10:55:22 +00:00
Jermolene
37ea659bf0 Refactor the dumpvariables macro as wikitext
Making it easier to customise
2019-03-30 10:52:49 +00:00
Jermolene
754c1251a9 Add new "variables" and "getvariables" operators 2019-03-30 10:52:28 +00:00
Jermolene
1c436cbbf3 DynaviewDemo: Rename tiddler-list field to story-list 2019-03-28 10:58:24 +00:00
Jermolene
94607aa9cd TOC macros: Remove redundant recursion protection
As discussed in #3881, it isn't really needed when user interaction is required to open child nodes.
2019-03-27 15:00:13 +00:00
Jermolene
62477c9fbb TOC Macros: fix recursion regression
Fixes #3881
2019-03-27 14:59:38 +00:00
jed
b1edcdb757 Add unusedtitle macro (#3880)
* Add uniquetitle macro

This macro is a wrapper on the $tw.wiki.generateNewTitle function to return a unique name, it has been requested multiple times in the forums.

* Add documentation tiddler for uniquetitle macro

* Add uniquetitle macro examples

* Change name from uniquetitle to unusedtitle for clarity

The title isn't unique, just not currently used in the wiki.

* Update uniquetitle to unusedtitle

* Change uniquetitle to unusedtitle

* Fix a typo
2019-03-26 21:57:58 +00:00
Brooks Boyd
d51a89135d Add signature for MidnightDesign, LLC to CLA Entity agreement (#3877) 2019-03-22 18:08:36 +00:00
Jermolene
d38b42f7c7 AWS Plugin: Don't error when no files to load 2019-03-22 17:27:20 +00:00
Jermolene
fffd0ee9e1 AWS: Add command for setting credentials profile 2019-03-22 09:20:25 +00:00
Jermolene
9f0d726f7d Dynaview: Simplify visibility tracking logic 2019-03-21 12:56:26 +00:00
Jermolene
7709192cc8 DynaView: Simplify visibility processing
And add a table of contents to the demo
2019-03-20 18:24:29 +00:00
Jermolene
02ae8969b2 Reveal widget: faulty logic for default handling
@BurningTreeC I think this might have been a typo in your recent refactorings; if you look back at an old version such as c0c1b557eb/core/modules/widgets/reveal.js then there is no sign of this fallback.

Fixes #3874
2019-03-20 16:50:34 +00:00
Simon Huber
a01dc6cb3d Docs: Typo 2019-03-18 12:40:15 +00:00
Simon Huber
f99fb4f9f5 Fix typos in WidgetSubclassingMechanism (#3870) 2019-03-17 18:13:13 +00:00
Jermolene
e52a616891 Add support for widget subclassing
Fixes #3865
2019-03-17 12:25:15 +00:00
Jermolene
05243a6c48 Docs: Add performance instrumentation docs 2019-03-16 16:39:08 +00:00
Jermolene
a89991cc46 Dynaview: Fix crash 2019-03-16 13:25:45 +00:00
Jermolene
f4fe254038 Clarify help for render command
The ordering of the bullet lists didn't match the order of the parameters
2019-03-16 13:25:34 +00:00
Jermolene
9f630b5829 v5.1.20 new release banner 2019-03-16 13:24:58 +00:00
Xavier Cazin
c904aeb05f fr-FR translation updates (#3856)
* update/improve translations of a few fr-FR strings

* update/add fr-FR for load and listen command docs
2019-03-13 09:34:44 +00:00
Simon Huber
efd7aa3a53 Make codemirror use tiddler-editor-border palette color (#3819) 2019-03-12 16:41:22 +00:00
Simon Huber
a4b24670f6 Update highlight.js to latest release v9.15.6 (#3635)
* update highlight.js to latest release v9.13.1

* update to v9.13.1 default.css

does the current default.css include adjustments for the different languages?

* Update highlight.pack.js

* Update readme.tid

* update highlight.pack to 9.15.6

* update version number + included languages
2019-03-12 12:04:38 +00:00
Simon Huber
2e0b2c8045 Palette manager: sort palettes by name, not description (#3853)
... currently it appears as if there was no sorting logic
2019-03-12 09:48:34 +00:00
Simon Huber
d068cb3625 Fix palette: missing type application/x-tiddler-dictionary (#3852) 2019-03-11 10:59:34 +00:00
Simon Huber
0d8c749f37 Rename SpartanDay to SpartanDay.tid (#3851)
* Rename SpartanDay to SpartanDay.tid

* Update SpartanDay.tid
2019-03-11 09:55:49 +00:00
Simon Huber
0303b7871b Rename SpartanNight to SpartanNight.tid (#3850) 2019-03-11 09:55:14 +00:00
Simon Huber
44d1a00bb0 Fix "cannot read substr of undefined" in removeprefix filter (#3826) 2019-03-11 09:38:15 +00:00
Simon Huber
784db30614 Fix removesuffix filter when title is undefined (#3827) 2019-03-11 09:37:49 +00:00
jdjdjdjdjdjd
26c6d6035e Add Spartan Day palette (#3846)
Ugh, hehe.. this is my first try at this. Hopefully got it right...
2019-03-11 09:25:54 +00:00
jdjdjdjdjdjd
b82cf3d070 Add Spartan Night palette (#3847)
* add Spartan Night palette

This and Spartan Day go hand in hand I feel like.

* Found a typo
2019-03-11 09:25:37 +00:00
jdjdjdjdjdjd
f07ffb2b41 Add @jdjdjdjdjdjd to the CLA (#3849) 2019-03-11 09:25:16 +00:00
Simon Huber
c9b16d88f3 Fix: reveal widget prevent undefined state (#3848)
the state didn't fall back to the default when there was no data-item to extract for a stateIndex

see the google group for a bug report: https://groups.google.com/forum/#!topic/TiddlyWiki/3jiFpayAIRc
2019-03-11 09:04:17 +00:00
Jermolene
256321cd42 Merge branch 'tiddlywiki-com' 2019-03-10 21:17:40 +00:00
Simon Huber
71aed78e2e Fix sticky draggable-placeholders in list macros (firefox) (#3823)
* fix draggable lists for firefox (sticky placeholders)

ff doesn't like whitespace and also those &nbsp; entities make problems

placeholder is styled in vanilla base

* tc-droppable-placeholder styles for tagged-draggable ...

and links-draggable lists

* make it beautiful
2019-03-10 20:05:18 +00:00
Simon Huber
0ab29e2c09 Community Palettes: Twilight by Thomas Elmiger (#3845) 2019-03-10 17:37:05 +00:00
Simon Huber
648c7ccd1f Add documentation for edit-text tabindex attribute (#3833)
* add tabindex attr to edit-text documentation

* add tabindex to edit widget documentation
2019-03-09 17:45:59 +00:00
Simon Huber
2dc70682cd Fix for SolarizedLight palette, missing tag and type (#3844) 2019-03-09 17:37:15 +00:00
Simon Huber
441011885c Fix: tm-full-screen when event.event undefined (#3835) 2019-03-09 17:09:34 +00:00
Simon Huber
449fd02cda Update Nord palette + solarized light palette (#3828)
* update Nord palette

* small change

* port solarized light palette

* Update SolarizedLight.tid
2019-03-09 17:08:58 +00:00
Joshua Fontany
a7dc8b5583 Signing the CLA (#3838)
* Signing the CLA

* added json mangler resource
2019-03-09 16:39:13 +00:00
Bram Chen
7478ba9165 Update Chinese languages (#3837)
* Add initial translation for zh-TW depends on zh-Hant

* Add initial translation for zh-CN depends on zh-Hans

* Add initial translation for zh-HK depends on zh-Hant

* Update chinese help texts for load command

    * for the new optional "noerror" parameter
2019-03-09 13:17:54 +00:00
Jermolene
12630d4a91 Provide an option for the load command to not error if no tiddlers are found 2019-03-08 16:43:04 +00:00
Jermolene
07635d7b3e Full edition: Fix plugin display 2019-03-07 18:46:38 +00:00
Jermolene
e61c71961b Fix default language
It is supposed to be the built-in core language, en-GB
2019-03-07 18:46:24 +00:00
Jermolene
f047e7cbf5 Add example startup action to switch to browser language 2019-03-07 18:45:52 +00:00
Jermolene
2c2d03f7a7 Refactor startup action execution so that they can switch language/theme 2019-03-07 18:43:23 +00:00
Jermolene
c036c22826 Add $:/info/browser/language to the info mechanism 2019-03-07 18:42:49 +00:00
Jermolene
6de13e2f60 Update release note 2019-03-05 22:22:55 +00:00
Jermolene
0c2689dd78 SaverHandler: Don't generate file if autosave disabled 2019-03-05 15:43:14 +00:00
Jermolene
a9e595c3f6 Dynaview: Add support for saving/restoring scroll position from local storage 2019-03-04 16:59:39 +00:00
Jermolene
348a0bc8bc Core: Allow startup navigation to be suppressed
Plugins can suppress it so that they can provide their own startup scroll handling
2019-03-04 16:59:15 +00:00
Jermolene
477c41f843 Add tooltip attribute to select widget 2019-03-04 12:24:16 +00:00
Simon Huber
0b1ce30a04 Add outline color to button, textarea, input (#3822)
* add outline-color to button, textarea, input

* add select elements, move to top

* use primary color
2019-03-03 21:22:13 +00:00
Simon Huber
e8b50df4a6 Porting the Nord palette (#3820)
https://github.com/arcticicestudio/nord

this palette is very popular, available for highlight.js, codemirror, all kinds of desktop/terminal applications ...
would be great to have it in tiddlywiki, too

this is a draft PR, certain things needs to be improved, but looks very good in tiddlywiki
2019-03-03 21:09:42 +00:00
Jermolene
2104017249 Browser-storage: Only save state tiddlers by default
And add it back to the prerelease now that it's a bit safer
2019-03-03 17:16:35 +00:00
Jeremy Ruston
148c1a0355 Clarify that filter operator brackets cannot be nested 2019-03-03 14:32:26 +00:00
Jermolene
dd4305d520 Browser-storage: Only delete our own items
We should only delete our own items because browsers share local storage with all file:// URIs
2019-03-03 11:30:14 +00:00
Simon Huber
638eb53429 Add tabindex attributes to edit templates (#3758)
* add tabindex attribute to editor-body edit-template

* add tabindex attr to fields edit-template

* add tabIndex variable to tags edit-template

* add tabindex attr to title edit-template

* add tabindex attr to type edit-template

* add tabindex attr to canonical-uri input

* add tabindex attr (as variable tabIndex) to tag-picker macro
2019-03-02 19:04:27 +01:00
Simon Huber
b6e2985ac6 Fix typo in edit-shortcut widget refresh - missing focus attr (#3815)
* fix edit-shortcut widget refresh - missing focus attr

* + typo fix. NOW it works
2019-03-02 18:16:55 +01:00
Simon Huber
87eab62b7e Make the keyboard-shortcut input focus automatically (#3776)
* add focus capability to edit-shortcut widget

* focus the keyboard-shortcut inputs in the control panel

... there's no other reason why it could have been opened other than just pressing a shorcut ...

... saves the mouseclick
2019-03-02 17:25:49 +01:00
Jermolene
fb0713ae78 Comments plugin: Fix extraneous paragraph in above story area
Fixes #3813
2019-03-02 16:18:50 +00:00
Simon Huber
16bb474fef Partial fix for the sticky dropzone on firefox (#3809)
in my tests listening for the dragend event and removing the tc-dragover class in that case removes the `tc-dragover` every time it should ...

without this, firefox often doesn't remove it and the green bar sticks at the top

investigating now if the droppable widget has a similar problem
2019-03-02 16:13:36 +01:00
Simon Huber
77e6f5c0e3 Fix for "Open" tab placeholders in FireFox (#3806)
* fix for "Open" tab placeholders in FireFox

this PR fixes the placeholders in FireFox not being removed on drag-leave from time to time

it consists of 2 mods where apparently both are needed:

- creating a `droppable-item` macro where whitespace is trimmed. that macro contains the droppable and inserts the placeholders
- removing the `&nbsp;` entity in favor of an inline style `height:2em;` on the placeholder div, putting it in a macro where whitespace can be trimmed, too

I'm investigating if there's a similar fix for the top page dropzone

* remove unnecessary whitespace trim, add css classes

`.tc-sidebar-tab-open-item { position: relative; }`

`.tc-sidebar-tab-open .tc-droppable-placeholer {  line-height:2em; height:2em; } `

* replace times entity with close-button

* add sidebar-open-tab styles
2019-03-02 14:54:23 +01:00
Simon Huber
41e338dc41 Add smartIndent to codemirror (#3810)
* add smartIndent config to codemirror

* add indentWithTabs config to codemirror

* make default tabSize same value as indentUnit

* make tab and enter do smart indentation
2019-03-02 14:46:10 +01:00
Jermolene
a6875df7ef Browser-storage: Add enable/disable and clear button 2019-03-01 22:06:14 +00:00
Jermolene
655fc31cee Server: Avoid displaying "undefined" for missing path prefix 2019-03-01 18:28:51 +00:00
Jermolene
18c00c2ef0 Don't allow $:/Import tiddler to be imported 2019-03-01 17:39:42 +00:00
Jermolene
b862348b06 Fix !is[variable] operator
Fixes #3804
2019-02-28 11:54:04 +00:00
Jermolene
36e76429b1 Add is[variable] filter
See discussion here https://groups.google.com/d/topic/tiddlywiki/4rEuAWc4EpM/discussion
2019-02-25 13:08:22 +00:00
Bimba Laszlo
181897514f Add links to plugins made by @bimlas (#3778) 2019-02-19 12:33:31 +01:00
Jermolene
810033bd71 Server: include path-prefix in display URL 2019-02-12 18:32:00 +00:00
Jermolene
6aab4d5524 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 2019-02-12 12:14:58 +00:00
Jermolene
72f2a94251 Ensure things work when $:/config/AnimationDuration is blank or not a valid number
Thanks @jdjdjdjdjdjd
2019-02-12 12:14:55 +00:00
Bram Chen
6dedcd958d Update chinese translations (#3762)
* Add advanced search canned filter for "tiddlers modified this session"
2019-02-10 09:24:30 +00:00
Simon Huber
f97d18bb6e Adding optional tabindex attr to simple, framed and cm engines (#3756)
* add optional tabindex attribute to factory.js

* add changedAttributes.tabindex to refresh mechanic

* add optional tabindex attribute to edit widget

* remove some extra whitespace

* remove some trailing whitespace

* add optional tabindex attribute to simple engine

* add optional tabindex attribute to framed engine

* add optional tabindex attribute to cm engine
2019-02-08 16:11:39 +00:00
Jermolene
9d7d3fefa0 Split operator: Remove empty strings when splitting
See the discussion on 9b2d527; thanks @kookma
2019-02-08 15:59:07 +00:00
Jermolene
6ff7a7d261 BrowserStorage: Make sure tiddlers loaded from local storage mark wiki as dirty
Thanks @xcazin
2019-02-08 15:38:23 +00:00
Jermolene
2710fae71d BrowserStorage: Use path to make unique item names for non-file URIs
Previously, we were only using the path to disambiguate files on a file:// URI. That meant that all wikis on tiddlywiki.com was sharing the same pool of local storage...
2019-02-08 15:19:20 +00:00
Jermolene
0e6855eba8 Add advanced search canned filter for "tiddlers modified this session" 2019-02-08 11:07:06 +00:00
Jermolene
8b04cfd4d5 Fix problem with extraneous raw markup in saved files
Previously, raw markup tiddlers were being saved even if they weren't included in the saveTiddlerFilter. This meant that, for example, using "save empty" button in GettingStarted would include the splash screen markup tiddler.
2019-02-07 18:30:17 +00:00
Jermolene
2c37c25c28 BrowserStorage: Add startup log and fix save filter
The previous filter was rejecting tiddlers that needed to be deleted.
2019-02-07 17:59:55 +00:00
Jermolene
adb07ccba0 Add a test for all filter with blank operand
Actually quite a useful way to get all of the tiddlers that were passed into the filter.
2019-02-07 17:59:12 +00:00
Jermolene
b64216cfa7 BrowserStorage: Add another warning 2019-02-07 15:15:05 +00:00
Jermolene
9601e570af Fix further typo in cdeabba 2019-02-07 15:07:21 +00:00
Jermolene
5c5628e10b Fix typo in cdeabba 2019-02-07 15:00:39 +00:00
Jermolene
cdeabbaf56 Remove browser-storage plugin from main prerelease
But make sure it's in the "full" edition.
2019-02-07 14:53:59 +00:00
Jermolene
5577f7a4fe BrowserStorage: Add support for a custom quota exceeded message 2019-02-07 14:46:23 +00:00
Jermolene
51b4f63c5c BrowserStorage: Add a filter to determine which tiddlers are saved 2019-02-07 14:35:25 +00:00
Jermolene
7df58a6813 Fixed bug with length operator
Thanks @BurningTreeC
2019-02-07 12:56:12 +00:00
Jermolene
158f96a207 Fix split operator testcase 2019-02-07 12:48:23 +00:00
Jermolene
dc29acd656 Fixed bug with split operator 2019-02-07 12:45:07 +00:00
Jermolene
af40485e37 Docs updates 2019-02-07 11:19:06 +00:00
Jermolene
9b2d52716a Add new string operators: length, join, split, concat etc. 2019-02-07 11:18:53 +00:00
Jermolene
64b665e706 More maths operators 2019-02-07 11:18:32 +00:00
Jermolene
f709641967 Upsdate release note 2019-02-06 18:22:29 +00:00
Jermolene
94f143bf64 Autofocus advanced search text edit input 2019-02-06 17:53:00 +00:00
Bram Chen
22fe4451c8 Update Chinese translations (#3735)
* Update chinese translations
* Add field descriptions for toc-link
* Add help texts for gzip parameter of listen command

* Add missing chinese warning message of "Upgrader/System"
2019-02-06 15:10:01 +00:00
Jermolene
1c982fba2d Fix sticky titles dropdown overlap
Fixes #3572
2019-02-06 14:20:34 +00:00
Jermolene
0ea00b59b0 Add numeric maths filter operators
There are other ways we could add maths to TW5 (including @EvanBalster's awesome https://github.com/EvanBalster/TiddlyWikiFormula) but the approach here has the merit of simplicity because it reuses the existing filter evaluation mechanism. That means that it's not ordinary "2+2" maths, it's a unique list processing language...

Docs to come

Fixes #254
2019-02-06 14:19:55 +00:00
Simon Huber
5e9fc661a9 Tentative: Remove conditional from wrap-selection text-operation (#3749)
As per the discussion in #3749, the original purpose of the removed condition is unknown, and so we cannot be certain that removing it is safe, but doing so seems the best way of discovering more...
2019-02-05 17:18:20 +00:00
Jermolene
e5f3301c1c Merge branch 'pr/3634' 2019-02-05 16:21:06 +00:00
Jermolene
b08a7e3f04 Wording tweaks 2019-02-05 16:20:44 +00:00
Jermolene
44c66b98a9 Add default prefix for tm-fold-all-tiddlers message 2019-02-05 16:01:24 +00:00
bimlas
ce256102a7 Suggested slightly "better English" wording for the warning 2019-02-04 22:09:31 +01:00
Jermolene
6f5f9ca2fb Browser-storage: Handle quota exceeded error 2019-02-03 17:29:32 +00:00
Jermolene
e31c5563ff BrowserStorage: A new plugin to save tiddlers to local storage
Experimental at this point.
2019-02-03 12:51:15 +00:00
Jermolene
70f5dff81e Add a boot hook for modifying the tiddler store 2019-02-03 12:01:57 +00:00
Jermolene
689e172e79 Move some utility functions into boot.js
So that they are available to code running earlier in the boot process
2019-02-03 12:01:38 +00:00
Diego Mesa
5ffcd7e5da When renaming a tiddler only show references if there are any (#3654)
* fixing 3648 - now non updated references are shown only when non zero

Signed-off-by: Diego Mesa <diego898@gmail.com>

* change to list widget

As per @jermolene comments I changed to the list widget

* Putting back the accidently removed title (will no longer use github interface).

Signed-off-by: Diego Mesa <diego898@gmail.com>

* making sure I dont overwrite currentTiddler

Signed-off-by: Diego Mesa <diego898@gmail.com>
2019-02-01 17:33:39 +00:00
Jermolene
5a37a84a54 Enhance plugin library search to all fields
Fixes #3741
2019-02-01 17:26:20 +00:00
Simon Huber
4228c3f9cc Fix bug in reveal widget when stateTitle tiddler is missing (#3745)
in the group this bug was reported

when the stateTitle is missing it tries to get a field string of an undefined tiddler ...
2019-02-01 16:53:29 +00:00
Jermolene
a4eb139f99 Innerwiki: Add support for draggable anchors 2019-02-01 10:43:42 +00:00
Jermolene
7bc1458749 Boot: Enhance domMaker to support namespaces and styles 2019-02-01 10:43:14 +00:00
Jermolene
92b8368115 Innerwiki: Improve examples 2019-01-30 16:58:04 +00:00
Jermolene
c4bb2110e3 Merge branch 'tiddlywiki-com' 2019-01-29 17:40:54 +00:00
Jermolene
f7d938e4bc Innerwiki: improve wiki state examples 2019-01-29 17:40:40 +00:00
Jermolene
8defe41458 Dynaview demo: Avoid hiding tiddlers that scroll out of view
We were getting some problems on Firefox/Safari whereby tiddlers would flicker between visible and invisible, spinning up my laptop fan.
2019-01-29 11:38:25 +00:00
Jermolene
6753a1485a Dynaview: turn off scroll anchoring 2019-01-29 11:37:26 +00:00
Jermolene
7f97e3080c Innerwiki: make sure we can click through the svg overlays 2019-01-28 19:32:35 +00:00
Jermolene
b6d901f888 Innerwiki: Add support for SVG overlays 2019-01-28 18:21:24 +00:00
00SS
90b7961629 Update TiddlerFields.tid (#3733)
#3680 Was getting too complicated for me so opened a new PR
2019-01-27 19:29:13 +00:00
00SS
c5aa855ce6 Docs: add example to CountWidget.tid (#3732)
* Update CountWidget.tid

Just a simple example added.

* Update CountWidget.tid

Made a slight addition to conform with the same style used in the Examples section of the $text widget: TextWidget.tid

* Update CountWidget.tid

Modified to use the Documentation display macro:
`<<wikitext-example-without-html>>`
2019-01-27 19:28:42 +00:00
admls
036ea400c5 Signing the CLA (#3734) 2019-01-27 19:27:45 +00:00
Moritz Ulrich
049244e8a8 WebServer: Enable deflate and gzip compression (#3677)
* get-index: Enable deflate and gzip compression

* Spaces -> Tabs

* listen: Add optional `gzip=yes` parameter (defaults to "no")

* get-index: Add comment explaining the usage of `zlib.*Sync` instead of async.
2019-01-27 16:23:24 +00:00
JesseWeinstein
95aca11719 Signing the CLA (#3695) 2019-01-27 14:53:58 +00:00
00SS
02fbae4200 Update field description lingo (#3698)
Made this new PR for for the master branch, and closed #3697 
This PR is needed for text shown in the update PR #3680 which is for the tiddlywiki-com branch
2019-01-27 14:52:29 +00:00
Jeremy Ruston
fc3227831f Docs: fix HTTPS command typos
Fixes #3713
2019-01-27 14:35:58 +00:00
00SS
72ec4d05e4 Update Editor toolbar.tid (#3720)
Small corrections
2019-01-27 14:31:39 +00:00
00SS
07aeaaa1a4 Docs: Update Hidden Setting SaveWikiButton Filename.tid (#3721)
Rewording to make clearer
2019-01-27 14:29:46 +00:00
Marxsal
790d606885 Docs: fixing header typo (#3722) 2019-01-27 14:28:33 +00:00
Jermolene
c6f1fb7627 Innerwiki demo: Adjust default tiddlers 2019-01-27 12:43:10 +00:00
Jermolene
44816ea0da Fix URL for innerwiki demo 2019-01-27 11:07:51 +00:00
Jermolene
ca7b62a5f6 Introduce "innerwiki" plugin
From the readme:

This plugin enables TiddlyWiki to embed a modified copy of itself (an "innerwiki"). The primary motivation is to be able to produce screenshot illustrations that are automatically up-to-date with the appearance of TiddlyWiki as it changes over time, or to produce the same screenshot in different languages
2019-01-27 10:57:56 +00:00
Jermolene
353821f442 TagManager: Remove extraneous caption field
Fixes #3727
2019-01-26 17:38:46 +00:00
Jermolene
4c1e3aa8d6 Merge branch 'tiddlywiki-com' 2019-01-22 11:52:38 +00:00
Jermolene
952826e0fa Dynaview: cleaning up
It turns out that we don't need to disable any scroll anchoring done by the browser as our implementation of scroll anchoring will adapt itself.

Also removing an unneeded paragraph tag from the view template.
2019-01-18 17:56:07 +00:00
Marxsal
e6aaafbc8d Grammar and tense fixes. (#3708) 2019-01-18 17:09:27 +00:00
Jermolene
79eb6a5ec1 Docs typo 2019-01-18 09:19:58 +00:00
Jermolene
7c0528340d Docs: Clarify use of "actionTiddler" variable 2019-01-18 08:57:08 +00:00
Jermolene
273768da1d Docs updates for TW5's new branch development model 2019-01-15 17:39:45 +00:00
Jermolene
52a30be7c6 Remove confusing reference to "global tiddlers" 2019-01-15 16:28:52 +00:00
00SS
479726c46e Update TextWidget.tid (#3696)
Used Example display method of <<wikitext-example-without-html>> and added another example.
2019-01-15 16:14:50 +00:00
Ben Webber
3afb251b3a Add en-US localization (#3689) 2019-01-14 09:44:04 +00:00
Johannes Löthberg
1f829dd5a8 Fix typo password -> username (#3686) 2019-01-14 09:42:09 +00:00
Simon Huber
95dbdff08a Fix bug with event.event.target being undefined (#3683) 2019-01-14 09:41:19 +00:00
dnebauer
bfd09133de Add howto for changing highlight languages (#3674)
* Create howto.tid

Howto explains customising the languages supported by the highlight plugin. This involves:

* Using the highlight.js download page to get a zip archive containing the files for a highlight.js server which supports a set of languages selected by the user
* Replacing the highlight plugin's `highlight.pack.js` file with the `highlight.pack.js` file from the downloaded archive

* Update plugin.info

Add howto.
2019-01-14 09:32:58 +00:00
dnebauer
dc74fc4306 Update url of highlight.js github project (#3672)
Github repo of the highlight.js project has changed from `github.com/isagalaev/highlight.js` to `github.com/highlightjs/highlight.js`.
2019-01-14 09:31:29 +00:00
Bram Chen
557053ab35 Fix outdated external-js template. (#3657)
Fix outdated external-js template.

Add the missing raw markup sections:
  * the top of the head
  * the top of the body
  * the bottom of the body
2019-01-14 09:18:57 +00:00
Ben Webber
317d75171c Sign CLA (#3690) 2019-01-14 09:17:20 +00:00
Johannes Löthberg
0e568fe69a Signing the CLA (#3687) 2019-01-14 09:16:00 +00:00
Moritz Ulrich
e2fe40a282 Sign the CLA (#3678) 2019-01-14 09:14:22 +00:00
dnebauer
193fb32423 Signing the CLA (#3671) 2019-01-14 09:11:53 +00:00
Jermolene
e14e69bedc DynaView plugin: add optional scroll position preservation 2019-01-11 17:50:52 +00:00
Jermolene
af9f90e8cd Merge branch 'master' into tiddlywiki-com 2019-01-08 15:23:13 +00:00
Jermolene
b899563971 CI: Fix repo for rebuilding tiddlywiki-com 2019-01-08 14:58:59 +00:00
00SS
d0afbe50a1 Update Plugins.tid (#3688)
In response to the two Jeremy Ruston posts at: https://groups.google.com/forum/#!topic/tiddlywiki/aPjljLW1yHE/discussion
2019-01-08 14:21:06 +00:00
00SS
0aac98f361 Signing the CLA (#3631)
* Signing the CLA

* Update cla-individual.md

I have edited the file to remove my "name." A real name was required for signing, which I did, and it is now in record. I would prefer the name not be on the TW.com website.
2019-01-08 14:19:51 +00:00
Jermolene
fa638b8b5b CI: Enable continuous integration
Going live!
2019-01-08 14:02:46 +00:00
Jermolene
4d5a79acb8 CI: Add branch to travis commit messages 2019-01-08 13:46:18 +00:00
Jermolene
fcfdb0632b CI: Trigger build of "tiddlywiki-com" branch 2019-01-08 13:27:08 +00:00
Jermolene
d14d7f0168 CI: Remove non-functional attempt to set build timezone
And also trigger a build for testing
2019-01-08 11:33:45 +00:00
Jermolene
83bea2a270 CI: Another attempt to fix the timezone 2019-01-08 11:16:31 +00:00
Jermolene
2b8efdc3ea CI: Fix building of test.html 2019-01-08 11:00:14 +00:00
Jermolene
27d0b2b491 CI: Try to fix the timezone of the build
To match the timezone of my development machine used for previous builds
2019-01-08 10:47:56 +00:00
Jermolene
824930682a CI: Fix plugin library version and build test.html 2019-01-08 10:34:50 +00:00
Jermolene
d8104e2c41 CI: Add timezone to datestamps 2019-01-08 10:01:23 +00:00
Jermolene
06f1f1a532 CI: Make sure we can see commit error messages 2019-01-07 21:44:07 +00:00
Jermolene
6121c0b5a7 CI: Fix date format 2019-01-07 21:34:30 +00:00
Jermolene
2c5b1c4a8c CI: Remove extraneous log information 2019-01-07 21:31:43 +00:00
Jermolene
3d687a7935 CI: Fix switched tiddlywiki versions 2019-01-07 21:30:58 +00:00
Jermolene
5d20a54713 CI: Figure out why master is building with the wrong version number 2019-01-07 21:27:05 +00:00
Jermolene
14623d33d2 CI: Fixes
Things are starting to work now...

* Now we extract the version number from package.json to use in making the plugin library
* We start building the whole site (eek, going to be slow)
2019-01-07 20:07:32 +00:00
Jermolene
37b335a136 CI: Try to quieten the commits 2019-01-07 18:48:40 +00:00
Jermolene
d5a25c9a96 CI: Start building properly 2019-01-07 18:40:22 +00:00
Jermolene
6c48c24332 CI: Include the date in the build details 2019-01-07 17:32:46 +00:00
Jermolene
86e27d64f2 CI: Fix up getting the git branch details into the build 2019-01-07 17:27:18 +00:00
Jermolene
decbe33f1f CI: More tweaking git commands... 2019-01-07 17:08:25 +00:00
Jermolene
8205893af9 CI: Further attempts to fix up the git integration 2019-01-07 17:01:12 +00:00
Jermolene
75158c0366 CI: Fixing up the Git integration 2019-01-07 16:51:06 +00:00
Jermolene
a2d4239db0 CI: Pull scripts out into files
Still trying to get the github integration working
2019-01-07 16:42:30 +00:00
Jermolene
1d9c932e16 CI: Attempt to pull pages branch from GitHub before the build, and push afterwards
Using a testing repository for now
2019-01-07 16:29:42 +00:00
Jermolene
58f7e7bd85 CI: Fixing getting the build details into a file 2019-01-07 11:40:52 +00:00
Jermolene
8f54231d62 CI: Start to get the build details into the build 2019-01-07 11:21:10 +00:00
Jermolene
97f7f8f111 CI: Doh! A simpler way to get the branch name 2019-01-07 10:44:19 +00:00
Jermolene
4e0b03b19f CI: Fix git branch detection
The old code was returning "HEAD" where we really want "master"
2019-01-07 10:38:48 +00:00
Jermolene
097b0e2d4a CI: Further attempts to pass Git details to our build script 2019-01-07 10:31:56 +00:00
Jermolene
87f077314b CI: Now try passing some details about the current git commit 2019-01-06 21:56:32 +00:00
Jermolene
7a07c84eac CI: Still trying to pass an environment variable 2019-01-06 21:49:20 +00:00
Jermolene
512d5662cc CI: Another attempt to fix passing an environment variable to a script 2019-01-06 21:41:36 +00:00
Jermolene
32974eebdb CI: Still trying to pass an environment variable to our build script 2019-01-06 21:14:32 +00:00
Jermolene
eca5df9f01 CI: Fixing setting up job-specific environment variables 2019-01-06 21:08:31 +00:00
Jermolene
c42eba3308 CI: Pass environment variable to the build job 2019-01-06 19:08:23 +00:00
Jermolene
77d286213f CI: Fix another yml problem 2019-01-05 18:35:56 +00:00
Jermolene
da864e23d6 CI: Fix YAML errors
I don't understand YAML
2019-01-05 12:10:55 +00:00
Jermolene
d58bc33df4 CI: Investigate conditional stages
For "master" we need to rebuild the prerelease; for "tiddlywiki-com" we need to rebuild the main release using the latest release. I want to have as much of the travis specific build logic expressed in travis.yml as possible, hence having to figure out Travis's syntax rather than doing everything in a script that tests the $TRAVIS_BRANCH environment variable...
2019-01-05 11:59:16 +00:00
Jermolene
c97c3cea74 CI: Fix intentionally broken test 2019-01-04 20:11:02 +00:00
Jermolene
e9f2a24f30 CI: Exit when tests fail 2019-01-04 20:07:37 +00:00
Jermolene
0b7f72ce5c CI: Output the build TW version number for debugging 2019-01-04 18:02:59 +00:00
Jermolene
52d328ee1b CI: Temporarily make one of the tests fail to make sure that failed tests work 2019-01-04 17:58:16 +00:00
Jermolene
ddf22ec2a4 We have to force the installation of TiddlyWiki
(This is so that we have the latest released version of TW5 for building the non-prerelease version)
2019-01-04 17:53:59 +00:00
Jermolene
6b4294923f Test edition: exit with an error code if the tests fail 2019-01-04 17:46:11 +00:00
Jermolene
2dd76007d3 CI: Stipulate the latest version of node 2019-01-04 17:45:52 +00:00
Jermolene
31470f676c Minimal first pass at continuous integration
For now, we're just using Travis CI to run the main build script
2019-01-04 17:25:30 +00:00
Jermolene
d6bffad8ab Remove references to obsolete "2bld" edition 2019-01-04 16:48:07 +00:00
Jermolene
6195069c5e Fix URL of prerelease plugin library for v5.1.20 2018-12-21 09:31:36 +00:00
Jermolene
8e3f9d6aba Version update for v5.1.20-prerelease 2018-12-20 17:27:36 +00:00
Jermolene
1793dc5e34 Plugin library version for prerelease 2018-12-20 17:10:35 +00:00
bimlas
18ed2faf82 Implement in $:/core/upgraders instead of navigator.js
The core module tiddlers are not blocked, they are only marked.
2018-12-10 23:05:41 +01:00
bimlas
38b088eabf Warn when importing core tiddlers
See https://groups.google.com/d/msg/tiddlywiki/YZlPGP0qX1o/3tUpyoHXDgAJ
2018-12-10 09:20:58 +01:00
601 changed files with 25292 additions and 17120 deletions

34
.travis.yml Normal file
View File

@@ -0,0 +1,34 @@
language: node_js
- "node"
stages:
- name: test
- name: build-prerelease
if: branch = "master"
- name: build-tiddlywiki-com
if: branch = "tiddlywiki-com"
jobs:
include:
- stage: test
script: ./bin/test.sh
- stage: build-prerelease
script:
- ./bin/travis-pre-build.sh
- export TW5_BUILD_TIDDLYWIKI='./tiddlywiki.js'
- export TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)
- export TW5_BUILD_DETAILS="Prerelease built from branch '$TRAVIS_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')"
- export TW5_BUILD_MAIN_EDITION='./editions/prerelease'
- export TW5_BUILD_OUTPUT='./output/prerelease'
- ./bin/build-site.sh
- ./bin/travis-push.sh
- stage: build-tiddlywiki-com
script:
- ./bin/travis-pre-build.sh
- export TW5_BUILD_TIDDLYWIKI='./node_modules/tiddlywiki/tiddlywiki.js'
- export TW5_BUILD_VERSION=$(./bin/get-plugin-library-version-number)
- export TW5_BUILD_DETAILS="Built from branch '$TRAVIS_BRANCH' at commit $(git rev-parse HEAD) of $(git remote get-url origin) at $(date +'%F %T %Z')"
- export TW5_BUILD_MAIN_EDITION='./editions/tw5.com'
- export TW5_BUILD_OUTPUT='./output'
- ./bin/build-site.sh
- ./bin/travis-push.sh

View File

@@ -1,15 +0,0 @@
@echo off
rem build TiddlyWiki 2.x
rem cook the TiddlyWiki 2.x.x index file
node .\tiddlywiki.js ^
editions\tw2 ^
--verbose ^
--output tmp\tw2 ^
--load editions\tw2\source\tiddlywiki.com\index.html.recipe ^
--rendertiddler $:/core/templates/tiddlywiki2.template.html index.html text/plain ^
|| exit 1
fc tmp\tw2\index.html editions\tw2\target\prebuilt.html

View File

@@ -1,15 +0,0 @@
#!/bin/bash
# build TiddlyWiki 2.x
# cook the TiddlyWiki 2.x.x index file
node ./tiddlywiki.js \
editions/tw2 \
--verbose \
--output tmp/tw2 \
--load editions/tw2/source/tiddlywiki.com/index.html.recipe \
--rendertiddler $:/core/templates/tiddlywiki2.template.html index.html text/plain \
|| exit 1
diff -q tmp/tw2/index.html editions/tw2/target/prebuilt.html

449
bin/build-site.sh Executable file
View File

@@ -0,0 +1,449 @@
#!/bin/bash
# Build all tiddlywiki.com assets.
# Default to the current version number for building the plugin library
if [ -z "$TW5_BUILD_VERSION" ]; then
TW5_BUILD_VERSION=v5.1.20
fi
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
# Default to using tw5.com as the main edition for /index.html
if [ -z "$TW5_BUILD_MAIN_EDITION" ]; then
TW5_BUILD_MAIN_EDITION=./editions/tw5.com
fi
echo "Using TW5_BUILD_MAIN_EDITION as [$TW5_BUILD_MAIN_EDITION]"
# Default to the version of TiddlyWiki installed in this repo
if [ -z "$TW5_BUILD_TIDDLYWIKI" ]; then
TW5_BUILD_TIDDLYWIKI=./tiddlywiki.js
fi
echo "Using TW5_BUILD_TIDDLYWIKI as [$TW5_BUILD_TIDDLYWIKI]"
# Set up the build details
if [ -z "$TW5_BUILD_DETAILS" ]; then
TW5_BUILD_DETAILS="$(git symbolic-ref --short HEAD)-$(git rev-parse HEAD) from $(git remote get-url origin)"
fi
echo "Using TW5_BUILD_DETAILS as [$TW5_BUILD_DETAILS]"
if [ -z "$TW5_BUILD_COMMIT" ]; then
TW5_BUILD_COMMIT="$(git rev-parse HEAD)"
fi
echo "Using TW5_BUILD_COMMIT as [$TW5_BUILD_COMMIT]"
# Set up the build output directory
if [ -z "$TW5_BUILD_OUTPUT" ]; then
TW5_BUILD_OUTPUT=./output
fi
mkdir -p $TW5_BUILD_OUTPUT
if [ ! -d "$TW5_BUILD_OUTPUT" ]; then
echo 'A valid TW5_BUILD_OUTPUT environment variable must be set'
exit 1
fi
echo "Using TW5_BUILD_OUTPUT as [$TW5_BUILD_OUTPUT]"
echo "Build details: $TW5_BUILD_DETAILS"
# Make the CNAME file that GitHub Pages requires
echo "tiddlywiki.com" > $TW5_BUILD_OUTPUT/CNAME
# Delete any existing static content
mkdir -p $TW5_BUILD_OUTPUT/static
mkdir -p $TW5_BUILD_OUTPUT/dev
mkdir -p $TW5_BUILD_OUTPUT/dev/static
rm $TW5_BUILD_OUTPUT/static/*
rm $TW5_BUILD_OUTPUT/dev/static/*
# Redirects
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
echo -e -n "title: $:/build\ncommit: $TW5_BUILD_COMMIT\n\n$TW5_BUILD_DETAILS\n" > $TW5_BUILD_OUTPUT/build.tid
######################################################
#
# Core distribution
#
######################################################
# /index.html Main site
# /favicon.ico Favicon for main site
# /static.html Static rendering of default tiddlers
# /alltiddlers.html Static rendering of all tiddlers
# /static/* Static single tiddlers
# /static/static.css Static stylesheet
# /static/favicon.ico Favicon for static pages
node $TW5_BUILD_TIDDLYWIKI \
$TW5_BUILD_MAIN_EDITION \
--verbose \
--version \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--build favicon static index \
|| exit 1
# /empty.html Empty
# /empty.hta For Internet Explorer
node $TW5_BUILD_TIDDLYWIKI \
./editions/empty \
--verbose \
--output $TW5_BUILD_OUTPUT \
--build empty \
|| exit 1
# /test.html Test edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/test \
--verbose \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all test.html text/plain \
|| exit 1
# /dev/index.html Developer docs
# /dev/favicon.ico Favicon for dev site
# /dev/static.html Static rendering of default tiddlers
# /dev/alltiddlers.html Static rendering of all tiddlers
# /dev/static/* Static single tiddlers
# /dev/static/static.css Static stylesheet
node $TW5_BUILD_TIDDLYWIKI \
./editions/dev \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/dev \
--build index favicon static \
|| exit 1
# /upgrade.html Custom edition for performing upgrades
node $TW5_BUILD_TIDDLYWIKI \
./editions/upgrade \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--build upgrade \
|| exit 1
# /encrypted.html Copy of the main file encrypted with the password "password"
node $TW5_BUILD_TIDDLYWIKI \
$TW5_BUILD_MAIN_EDITION \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--build encrypted \
|| exit 1
######################################################
#
# Editions
#
######################################################
# /editions/xlsx-utils/index.html xlsx-utils edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/xlsx-utils \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/xlsx-utils/ \
--build index \
|| exit 1
# /editions/resumebuilder/index.html Resume builder edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/resumebuilder \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/resumebuilder/ \
--build index \
|| exit 1
# /editions/text-slicer/index.html Text slicer edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/text-slicer \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/text-slicer/ \
--build index \
|| exit 1
# /editions/translators/index.html Translators edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/translators \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/translators/ \
--build index \
|| exit 1
# /editions/introduction/index.html Introduction edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/introduction \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/introduction/ \
--build index \
|| exit 1
# /editions/full/index.html Full edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/full \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/full/ \
--build index \
|| exit 1
# /editions/tw5.com-docs/index.html tiddlywiki.com docs edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/tw5.com-docs \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/tw5.com-docs/ \
--build index \
|| exit 1
######################################################
#
# Plugin demos
#
######################################################
# /plugins/tiddlywiki/innerwiki/index.html Demo wiki with Innerwiki plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/innerwikidemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/innerwiki/index.html text/plain \
|| exit 1
# /plugins/tiddlywiki/dynaview/index.html Demo wiki with DynaView plugin
# /plugins/tiddlywiki/dynaview/empty.html Empty wiki with DynaView plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/dynaviewdemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/dynaview/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/dynaview/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/katex/index.html Demo wiki with KaTeX plugin
# /plugins/tiddlywiki/katex/empty.html Empty wiki with KaTeX plugin
# TODO: Build the static file with the release of 5.1.3
# --rendertiddler $:/core/templates/static.template.html plugins/tiddlywiki/katex/static.html text/plain \
node $TW5_BUILD_TIDDLYWIKI \
./editions/katexdemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/katex/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/tahoelafs \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/d3demo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/codemirrordemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/codemirror/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/codemirror/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/markdown/index.html Demo wiki with Markdown plugin
# /plugins/tiddlywiki/markdown/empty.html Empty wiki with Markdown plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/markdowndemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/markdown/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/markdown/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/tw2parser/index.html Demo wiki with tw2parser plugin
# /plugins/tiddlywiki/tw2parser/empty.html Empty wiki with tw2parser plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/classicparserdemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/tw2parser/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tw2parser/empty.html text/plain \
|| exit 1
# /plugins/tiddlywiki/highlight/index.html Demo wiki with highlight plugin
# /plugins/tiddlywiki/highlight/empty.html Empty wiki with highlight plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/highlightdemo \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all plugins/tiddlywiki/highlight/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/highlight/empty.html text/plain \
|| exit 1
######################################################
#
# Language editions
#
######################################################
# Delete any existing static content
rm $TW5_BUILD_OUTPUT/languages/de-AT/static/*
rm $TW5_BUILD_OUTPUT/languages/de-DE/static/*
rm $TW5_BUILD_OUTPUT/languages/es-ES/static/*
rm $TW5_BUILD_OUTPUT/languages/fr-FR/static/*
rm $TW5_BUILD_OUTPUT/languages/ja-JP/static/*
rm $TW5_BUILD_OUTPUT/languages/ko-KR/static/*
rm $TW5_BUILD_OUTPUT/languages/zh-Hans/static/*
rm $TW5_BUILD_OUTPUT/languages/zh-Hant/static/*
# /languages/de-AT/index.html Demo wiki with de-AT language
# /languages/de-AT/empty.html Empty wiki with de-AT language
node $TW5_BUILD_TIDDLYWIKI \
./editions/de-AT \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/de-AT \
--build favicon empty static index \
|| exit 1
# /languages/de-DE/index.html Demo wiki with de-DE language
# /languages/de-DE/empty.html Empty wiki with de-DE language
node $TW5_BUILD_TIDDLYWIKI \
./editions/de-DE \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/de-DE \
--build favicon empty static index \
|| exit 1
# /languages/es-ES/index.html Demo wiki with es-ES language
# /languages/es-ES/empty.html Empty wiki with es-ES language
node $TW5_BUILD_TIDDLYWIKI \
./editions/es-ES \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/es-ES \
--build favicon empty static index \
|| exit 1
# /languages/fr-FR/index.html Demo wiki with fr-FR language
# /languages/fr-FR/empty.html Empty wiki with fr-FR language
node $TW5_BUILD_TIDDLYWIKI \
./editions/fr-FR \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/fr-FR \
--build favicon empty static index \
|| exit 1
# /languages/ja-JP/index.html Demo wiki with ja-JP language
# /languages/ja-JP/empty.html Empty wiki with ja-JP language
node $TW5_BUILD_TIDDLYWIKI \
./editions/ja-JP \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/ja-JP \
--build empty index \
|| exit 1
# /languages/ko-KR/index.html Demo wiki with ko-KR language
# /languages/ko-KR/empty.html Empty wiki with ko-KR language
node $TW5_BUILD_TIDDLYWIKI \
./editions/ko-KR \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/ko-KR \
--build favicon empty static index \
|| exit 1
# /languages/zh-Hans/index.html Demo wiki with zh-Hans language
# /languages/zh-Hans/empty.html Empty wiki with zh-Hans language
node $TW5_BUILD_TIDDLYWIKI \
./editions/zh-Hans \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/zh-Hans \
--build empty index \
|| exit 1
# /languages/zh-Hant/index.html Demo wiki with zh-Hant language
# /languages/zh-Hant/empty.html Empty wiki with zh-Hant language
node $TW5_BUILD_TIDDLYWIKI \
./editions/zh-Hant \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/languages/zh-Hant \
--build empty index \
|| exit 1
######################################################
#
# Plugin library
#
######################################################
node $TW5_BUILD_TIDDLYWIKI \
./editions/pluginlibrary \
--verbose \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/library/$TW5_BUILD_VERSION \
--build \
|| exit 1
# Delete the temporary build tiddler
rm $TW5_BUILD_OUTPUT/build.tid || exit 1

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env node
// Extract raw version number from package.json (without the optional "-prerelease" suffix)
if(!process.env["TW5_BUILD_TIDDLYWIKI"]) {
throw "TW5_BUILD_TIDDLYWIKI environment variable not set";
}
var fs = require("fs"),
path = require("path");
var filename = path.resolve(path.dirname(process.env["TW5_BUILD_TIDDLYWIKI"]),"./package.json"),
json = JSON.parse(fs.readFileSync(filename,"utf8"));
if(!json.version) {
throw "Missing version number in package.json";
}
process.stdout.write("v" + json.version.split("-")[0]);

7
bin/npm-publish.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
# publish to npm
./bin/clean.sh
npm publish || exit 1

8
bin/quick-bld.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Abbreviated build script for building prerelease
tiddlywiki editions/prerelease \
--verbose \
--build favicon index \
|| exit 1

17
bin/readme-bld.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Build readmes from corresponding tiddlers
# Default to the version of TiddlyWiki installed in this repo
if [ -z "$TW5_BUILD_TIDDLYWIKI" ]; then
TW5_BUILD_TIDDLYWIKI=./tiddlywiki.js
fi
# tw5.com readmes
node $TW5_BUILD_TIDDLYWIKI \
editions/tw5.com \
--verbose \
--output . \
--build readmes \
|| exit 1

View File

@@ -1,3 +1,4 @@
<h1 class="">Script Files</h1><p>The <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> repository contains several scripts in the <code>bin</code> folder that you can use to automate common tasks, or as a useful starting point for your own scripts. See <a class="tc-tiddlylink tc-tiddlylink-missing" href="https://tiddlywiki.com/static/Scripts%2520for%2520building%2520tiddlywiki.com.html">Scripts for building tiddlywiki.com</a> for details of the scripts used to build and release <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/</a>.</p><p>All the scripts expect to be run from the root folder of the repository.</p><h2 class=""><code>serve</code>: serves tw5.com</h2><pre><code>./bin/serve.sh -h
./bin/serve.sh [edition dir] [username] [password] [host] [port]</code></pre><p>Or:</p><pre><code>./bin/serve.cmd -h
./bin/serve.cmd [edition dir] [username] [password] [host] [port]</code></pre><p>This script starts <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> running as an HTTP server, defaulting to the content from the <code>tw5.com-server</code> edition. By default, the Node.js serves on port 8080. If the optional <code>username</code> parameter is provided, it is used for signing edits. If the <code>password</code> is provided then HTTP basic authentication is used. Run the script with the <code>-h</code> parameter to see online help.</p><p>To experiment with this configuration, run the script and then visit <code>http://127.0.0.1:8080</code> in a browser.</p><p>Changes made in the browser propagate to the server over HTTP (use the browser developer console to see these requests). The server then syncs changes to the file system (and logs each change to the screen).</p><h2 class=""><code>test</code>: build and run tests</h2><p>This script runs the <code>test</code> edition of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on the server to perform the server-side tests and to build <code>test.html</code> for running the tests in the browser.</p><h2 class=""><code>lazy</code>: serves tw5.com with lazily loaded images</h2><pre><code>./bin/lazy.sh &lt;username&gt; [&lt;password&gt;]</code></pre><p>Or:</p><pre><code>./bin/lazy.cmd &lt;username&gt; [&lt;password&gt;]</code></pre><p>This script serves the <code>tw5.com-server</code> edition content with <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/LazyLoading.html">LazyLoading</a> applied to images.</p><h2 class=""><code>2bld</code>: builds <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> 2.6.5</h2><p>This script builds <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> 2.6.5 from the original source and then displays the differences between them (<code>diff</code> is used for *nix, <code>fc</code> for Windows).</p>
./bin/serve.cmd [edition dir] [username] [password] [host] [port]</code></pre><p>This script starts <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> running as an HTTP server, defaulting to the content from the <code>tw5.com-server</code> edition. By default, the Node.js serves on port 8080. If the optional <code>username</code> parameter is provided, it is used for signing edits. If the <code>password</code> is provided then HTTP basic authentication is used. Run the script with the <code>-h</code> parameter to see online help.</p><p>To experiment with this configuration, run the script and then visit <code>http://127.0.0.1:8080</code> in a browser.</p><p>Changes made in the browser propagate to the server over HTTP (use the browser developer console to see these requests). The server then syncs changes to the file system (and logs each change to the screen).</p><h2 class=""><code>test</code>: build and run tests</h2><p>This script runs the <code>test</code> edition of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on the server to perform the server-side tests and to build <code>test.html</code> for running the tests in the browser.</p><h2 class=""><code>lazy</code>: serves tw5.com with lazily loaded images</h2><pre><code>./bin/lazy.sh &lt;username&gt; [&lt;password&gt;]</code></pre><p>Or:</p><pre><code>./bin/lazy.cmd &lt;username&gt; [&lt;password&gt;]</code></pre><p>This script serves the <code>tw5.com-server</code> edition content with <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/LazyLoading.html">LazyLoading</a> applied to images.
</p>

View File

@@ -7,6 +7,7 @@
node ./tiddlywiki.js \
./editions/test \
--verbose \
--version \
--rendertiddler $:/core/save/all test.html text/plain \
|| exit 1

10
bin/travis-pre-build.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Install latest current release from npm
# (we need to force because otherwise npm will refuse to install a module of the same name)
npm --force install tiddlywiki || exit 1
# Pull existing GitHub pages content
git clone --depth=1 --branch=master "https://github.com/Jermolene/jermolene.github.io.git" output

20
bin/travis-push.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
# Push output back to GitHub
cd output || exit 1
git config --global user.email "travis@travis-ci.org" || exit 1
git config --global user.name "Travis CI" || exit 1
git add -A . || exit 1
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER of $TRAVIS_BRANCH ($(date +'%F %T %Z'))" || exit 1
git remote add deploy "https://$GH_TOKEN@github.com/Jermolene/jermolene.github.io.git" &>/dev/null || exit 1
git push deploy master &>/dev/null || exit 1
cd .. || exit 1

17
bin/verbump.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Bump to a new version number
if [ -z "$1" ]
then
echo "Missing version (eg '5.1.38-prerelease')"
exit 1
fi
# Set the new version number (will also commit and tag the release)
npm version $1 -m "Version number update for $1" || exit 1
# Make sure our tags are pushed to the origin server
git push origin --tags || exit 1

View File

@@ -51,6 +51,63 @@ $tw.utils.isArray = function(value) {
return Object.prototype.toString.call(value) == "[object Array]";
};
/*
Check if an array is equal by value and by reference.
*/
$tw.utils.isArrayEqual = function(array1,array2) {
if(array1 === array2) {
return true;
}
array1 = array1 || [];
array2 = array2 || [];
if(array1.length !== array2.length) {
return false;
}
return array1.every(function(value,index) {
return value === array2[index];
});
};
/*
Push entries onto an array, removing them first if they already exist in the array
array: array to modify (assumed to be free of duplicates)
value: a single value to push or an array of values to push
*/
$tw.utils.pushTop = function(array,value) {
var t,p;
if($tw.utils.isArray(value)) {
// Remove any array entries that are duplicated in the new values
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);
}
} else {
p = array.indexOf(value);
if(p !== -1) {
array.splice(p,1);
}
array.push(value);
}
return array;
};
/*
Determine if a value is a date
*/
@@ -89,7 +146,9 @@ Helper for making DOM elements
tag: tag name
options: see below
Options include:
namespace: defaults to http://www.w3.org/1999/xhtml
attributes: hashmap of attribute values
style: hashmap of styles
text: text to add as a child node
children: array of further child nodes
innerHTML: optional HTML for element
@@ -99,7 +158,7 @@ eventListeners: array of event listeners (this option won't work until $tw.utils
*/
$tw.utils.domMaker = function(tag,options) {
var doc = options.document || document;
var element = doc.createElement(tag);
var element = doc.createElementNS(options.namespace || "http://www.w3.org/1999/xhtml",tag);
if(options["class"]) {
element.className = options["class"];
}
@@ -115,6 +174,9 @@ $tw.utils.domMaker = function(tag,options) {
$tw.utils.each(options.attributes,function(attribute,name) {
element.setAttribute(name,attribute);
});
$tw.utils.each(options.style,function(value,name) {
element.style[name] = value;
});
if(options.eventListeners) {
$tw.utils.addEventListeners(element,options.eventListeners);
}
@@ -252,13 +314,13 @@ $tw.utils.parseDate = function(value) {
// Stringify an array of tiddler titles into a list string
$tw.utils.stringifyList = function(value) {
if($tw.utils.isArray(value)) {
var result = [];
for(var t=0; t<value.length; t++) {
var result = new Array(value.length);
for(var t=0, l=value.length; t<l; t++) {
var entry = value[t] || "";
if(entry.indexOf(" ") !== -1) {
result.push("[[" + entry + "]]");
result[t] = "[[" + entry + "]]";
} else {
result.push(entry);
result[t] = entry;
}
}
return result.join(" ");
@@ -862,6 +924,61 @@ $tw.Tiddler.prototype.hasField = function(field) {
return $tw.utils.hop(this.fields,field);
};
/*
Compare two tiddlers for equality
tiddler: the tiddler to compare
excludeFields: array of field names to exclude from the comparison
*/
$tw.Tiddler.prototype.isEqual = function(tiddler,excludeFields) {
if(!(tiddler instanceof $tw.Tiddler)) {
return false;
}
excludeFields = excludeFields || [];
var self = this,
differences = []; // Fields that have differences
// Add to the differences array
function addDifference(fieldName) {
// Check for this field being excluded
if(excludeFields.indexOf(fieldName) === -1) {
// Save the field as a difference
$tw.utils.pushTop(differences,fieldName);
}
}
// Returns true if the two values of this field are equal
function isFieldValueEqual(fieldName) {
var valueA = self.fields[fieldName],
valueB = tiddler.fields[fieldName];
// Check for identical string values
if(typeof(valueA) === "string" && typeof(valueB) === "string" && valueA === valueB) {
return true;
}
// Check for identical array values
if($tw.utils.isArray(valueA) && $tw.utils.isArray(valueB) && $tw.utils.isArrayEqual(valueA,valueB)) {
return true;
}
// Check for identical date values
if($tw.utils.isDate(valueA) && $tw.utils.isDate(valueB) && valueA.getTime() === valueB.getTime()) {
return true;
}
// Otherwise the fields must be different
return false;
}
// Compare our fields
for(var fieldName in this.fields) {
if(!isFieldValueEqual(fieldName)) {
addDifference(fieldName);
}
}
// There's a difference for every field in the other tiddler that we don't have
for(fieldName in tiddler.fields) {
if(!(fieldName in this.fields)) {
addDifference(fieldName);
}
}
// Return whether there were any differences
return differences.length === 0;
};
/*
Register and install the built in tiddler field modules
*/
@@ -896,7 +1013,7 @@ $tw.modules.define("$:/boot/tiddlerfields/list","tiddlerfield",{
/*
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
enableIndexers - Array of indexer names to enable, or null to use all available indexers
*/
$tw.Wiki = function(options) {
options = options || {};
@@ -911,14 +1028,31 @@ $tw.Wiki = function(options) {
},
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:}
shadowTiddlers = Object.create(null), // Hashmap by title of {source:, tiddler:}
shadowTiddlerTitles = null,
getShadowTiddlerTitles = function() {
if(!shadowTiddlerTitles) {
shadowTiddlerTitles = Object.keys(shadowTiddlers);
}
return shadowTiddlerTitles;
};
},
enableIndexers = options.enableIndexers || null,
indexers = [],
indexersByName = Object.create(null);
this.addIndexer = function(indexer,name) {
// Bail if this indexer is not enabled
if(enableIndexers && enableIndexers.indexOf(name) === -1) {
return;
}
indexers.push(indexer);
indexersByName[name] = indexer;
indexer.init();
};
this.getIndexer = function(name) {
return indexersByName[name] || null;
};
// Add a tiddler to the store
this.addTiddler = function(tiddler) {
@@ -931,12 +1065,33 @@ $tw.Wiki = function(options) {
if(title) {
// Uncomment the following line for detailed logs of all tiddler writes
// console.log("Adding",title,tiddler)
// Record the old tiddler state
var updateDescriptor = {
old: {
tiddler: this.getTiddler(title),
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
}
// Save the new tiddler
tiddlers[title] = tiddler;
// Check we've got it's title
if(tiddlerTitles && tiddlerTitles.indexOf(title) === -1) {
tiddlerTitles.push(title);
}
// Record the new tiddler state
updateDescriptor["new"] = {
tiddler: tiddler,
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
// Update indexes
this.clearCache(title);
this.clearGlobalCache();
$tw.utils.each(indexers,function(indexer) {
indexer.update(updateDescriptor);
});
// Queue a change event
this.enqueueTiddlerEvent(title);
}
}
@@ -947,15 +1102,36 @@ $tw.Wiki = function(options) {
// Uncomment the following line for detailed logs of all tiddler deletions
// console.log("Deleting",title)
if($tw.utils.hop(tiddlers,title)) {
// Record the old tiddler state
var updateDescriptor = {
old: {
tiddler: this.getTiddler(title),
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
}
// Delete the tiddler
delete tiddlers[title];
// Delete it from the list of titles
if(tiddlerTitles) {
var index = tiddlerTitles.indexOf(title);
if(index !== -1) {
tiddlerTitles.splice(index,1);
}
}
// Record the new tiddler state
updateDescriptor["new"] = {
tiddler: this.getTiddler(title),
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
// Update indexes
this.clearCache(title);
this.clearGlobalCache();
$tw.utils.each(indexers,function(indexer) {
indexer.update(updateDescriptor);
});
// Queue a change event
this.enqueueTiddlerEvent(title,true);
}
};
@@ -1042,7 +1218,6 @@ $tw.Wiki = function(options) {
callback(tiddlers[title],title);
}
}
};
// Test for the existence of a tiddler (excludes shadow tiddlers)
@@ -1156,8 +1331,14 @@ $tw.Wiki = function(options) {
shadowTiddlerTitles = null;
this.clearCache(null);
this.clearGlobalCache();
$tw.utils.each(indexers,function(indexer) {
indexer.rebuild();
});
};
if(this.addIndexersToWiki) {
this.addIndexersToWiki();
}
};
// Dummy methods that will be filled in after boot
@@ -1352,8 +1533,40 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/html","tiddlerdeserializer",{
});
$tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
"application/json": function(text,fields) {
var data = JSON.parse(text);
return $tw.utils.isArray(data) ? data : [data];
var isTiddlerValid = function(data) {
// Not valid if it's not an object with a title property
if(typeof(data) !== "object" || !$tw.utils.hop(data,"title")) {
return false;
}
for(var f in data) {
if($tw.utils.hop(data,f)) {
// Check field name doesn't contain whitespace or control characters
if(typeof(data[f]) !== "string" || /[\x00-\x1F\s]/.test(f)) {
return false;
}
}
}
return true;
},
isTiddlerArrayValid = function(data) {
for(var t=0; t<data.length; t++) {
if(!isTiddlerValid(data[t])) {
return false;
}
}
return true;
},
data = JSON.parse(text);
if($tw.utils.isArray(data) && isTiddlerArrayValid(data)) {
return data;
} else if(isTiddlerValid(data)) {
return [data];
} else {
// Plain JSON file
fields.text = text;
fields.type = "application/json";
return [fields];
}
}
});
@@ -1506,9 +1719,11 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
typeInfo = type ? $tw.config.contentTypeInfo[type] : null,
data = fs.readFileSync(filepath,typeInfo ? typeInfo.encoding : "utf8"),
tiddlers = $tw.wiki.deserializeTiddlers(ext,data,fields),
metadata;
if(ext !== ".json" && tiddlers.length === 1) {
metadata = $tw.loadMetadataForFile(filepath);
if(metadata) {
if(type === "application/json") {
tiddlers = [{text: data, type: "application/json"}];
}
tiddlers = [$tw.utils.extend({},tiddlers[0],metadata)];
}
return {filepath: filepath, type: type, tiddlers: tiddlers, hasMetaFile: !!metadata};
@@ -1738,8 +1953,10 @@ $tw.loadPlugin = function(name,paths) {
var pluginFields = $tw.loadPluginFolder(pluginPath);
if(pluginFields) {
$tw.wiki.addTiddler(pluginFields);
return;
}
}
console.log("Warning: Cannot find plugin '" + name + "'");
};
/*
@@ -1753,7 +1970,7 @@ $tw.getLibraryItemSearchPaths = function(libraryPath,envVar) {
if(env) {
env.split(path.delimiter).map(function(item) {
if(item) {
pluginPaths.push(item)
pluginPaths.push(item);
}
});
}
@@ -1889,6 +2106,21 @@ $tw.loadTiddlersNode = function() {
});
// Load the core tiddlers
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
// Load any extra plugins
$tw.utils.each($tw.boot.extraPlugins,function(name) {
if(name.charAt(0) === "+") { // Relative path to plugin
var pluginFields = $tw.loadPluginFolder(name.substring(1));;
if(pluginFields) {
$tw.wiki.addTiddler(pluginFields);
}
} else {
var parts = name.split("/"),
type = parts[0];
if(parts.length === 3 && ["plugins","themes","languages"].indexOf(type) !== -1) {
$tw.loadPlugins([parts[1] + "/" + parts[2]],$tw.config[type + "Path"],$tw.config[type + "EnvVar"]);
}
}
});
// Load the tiddlers from the wiki directory
if($tw.boot.wikiPath) {
$tw.boot.wikiInfo = $tw.loadWikiTiddlers($tw.boot.wikiPath);
@@ -1952,6 +2184,12 @@ $tw.boot.startup = function(options) {
if($tw.boot.argv.length === 0) {
$tw.boot.argv = ["--help"];
}
// Parse any extra plugin references
$tw.boot.extraPlugins = $tw.boot.extraPlugins || [];
while($tw.boot.argv[0] && $tw.boot.argv[0].indexOf("+") === 0) {
$tw.boot.extraPlugins.push($tw.boot.argv[0].substring(1));
$tw.boot.argv.splice(0,1);
}
// 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
@@ -2037,6 +2275,8 @@ $tw.boot.startup = function(options) {
if($tw.preloadTiddlers) {
$tw.wiki.addTiddlers($tw.preloadTiddlers);
}
// Give hooks a chance to modify the store
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
// Unpack plugin tiddlers
$tw.wiki.readPluginInfo();
$tw.wiki.registerPluginTiddlers("plugin",$tw.safeMode ? ["$:/core"] : undefined);

View File

@@ -1,4 +1,3 @@
<h1 class="">Contributing to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a></h1><p>We welcome contributions to the code and documentation of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> in several ways:</p><ul><li><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/ReportingBugs.html">ReportingBugs</a></li><li>Helping to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Improving%2520TiddlyWiki%2520Documentation.html">improve our documentation</a></li><li>Contributing to the code via <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5" rel="noopener noreferrer" target="_blank">GitHub</a><ul><li>See <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/dev</a> for more details</li></ul></li></ul><p>There are other ways to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/HelpingTiddlyWiki.html">help TiddlyWiki</a> too.</p><h1 class="">Contributor License Agreement</h1><p>Like other <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/OpenSource.html">OpenSource</a> projects, <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> needs a signed contributor license agreement from individual contributors. This is a legal agreement that allows contributors to assert that they own the copyright of their contribution, and that they agree to license it to the <a class="tc-tiddlylink tc-tiddlylink-missing" href="https://tiddlywiki.com/static/UnaMesa.html">UnaMesa</a> Association (the legal entity that owns <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on behalf of the community).</p><ul><li>For individuals use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a></li><li>For entities use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a></li></ul><h1 class="">How to sign the CLA</h1><p>Create a <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/GitHub.html">GitHub</a> pull request to add your name to <code>cla-individual.md</code> or <code>cla-entity.md</code>, with the date in the format (YYYY/MM/DD).</p><p><strong>step by step</strong></p><ol><li>Navigate to <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a> or <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a> according to whether you are signing as an individual or representative of an organisation</li><li>Click the &quot;edit&quot; button at the top-right corner (clicking this button will fork the project so you can edit the file)</li><li>Add your name at the bottom<ul><li>eg: <code>Jeremy Ruston, @Jermolene, 2011/11/22</code></li></ul></li><li>Below the edit box for the CLA text you should see a box labelled <strong>Propose file change</strong></li><li>Enter a brief title to explain the change (eg, &quot;Signing the CLA&quot;)</li><li>Click the green button labelled <strong>Propose file change</strong></li><li>On the following screen, click the green button labelled <strong>Create pull request</strong></li></ol><hr><p><em>The CLA documents used for this project were created using <a class="tc-tiddlylink-external" href="http://www.harmonyagreements.org" rel="noopener noreferrer" target="_blank">Harmony Project Templates</a>. &quot;HA-CLA-I-LIST Version 1.0&quot; for &quot;CLA-individual&quot; and &quot;HA-CLA-E-LIST Version 1.0&quot; for &quot;CLA-entity&quot;.</em></p><p>Remarks
----—</p><ul><li><ul><li>When not owning the copyright in the entire work of authorship**</li></ul></li></ul><p>In this case, please clearly state so, since otherwise we assume that you are the legal copyright holder of the contributed work! Please provide links and additional information that clarify under which license the rest of the code is distributed.
<h1 class="">Contributing to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a></h1><p>We welcome contributions to the code and documentation of <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> in several ways:</p><ul><li><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/ReportingBugs.html">ReportingBugs</a></li><li>Helping to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Improving%2520TiddlyWiki%2520Documentation.html">improve our documentation</a></li><li>Contributing to the code via <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5" rel="noopener noreferrer" target="_blank">GitHub</a><ul><li>See <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/dev</a> for more details</li></ul></li></ul><p>There are other ways to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/HelpingTiddlyWiki.html">help TiddlyWiki</a> too.</p><h1 class="">Contributor License Agreement</h1><p>Like other <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/OpenSource.html">OpenSource</a> projects, <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a> needs a signed contributor license agreement from individual contributors. This is a legal agreement that allows contributors to assert that they own the copyright of their contribution, and that they agree to license it to the <a class="tc-tiddlylink tc-tiddlylink-missing" href="https://tiddlywiki.com/static/UnaMesa.html">UnaMesa</a> Association (the legal entity that owns <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on behalf of the community).</p><ul><li>For individuals use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a></li><li>For entities use: <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a></li></ul><h1 class="">How to sign the CLA</h1><p>Create a <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/GitHub.html">GitHub</a> pull request to add your name to <code>cla-individual.md</code> or <code>cla-entity.md</code>, with the date in the format (YYYY/MM/DD).</p><p><strong>step by step</strong></p><ol><li>Navigate to <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-individual.md" rel="noopener noreferrer" target="_blank">licenses/CLA-individual</a> or <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/tree/master/licenses/cla-entity.md" rel="noopener noreferrer" target="_blank">licenses/CLA-entity</a> according to whether you are signing as an individual or representative of an organisation</li><li>Ensure that the &quot;branch&quot; dropdown at the top left is set to <code>tiddlywiki-com</code></li><li>Click the &quot;edit&quot; button at the top-right corner (clicking this button will fork the project so you can edit the file)</li><li>Add your name at the bottom<ul><li>eg: <code>Jeremy Ruston, @Jermolene, 2011/11/22</code></li></ul></li><li>Below the edit box for the CLA text you should see a box labelled <strong>Propose file change</strong></li><li>Enter a brief title to explain the change (eg, &quot;Signing the CLA&quot;)</li><li>Click the green button labelled <strong>Propose file change</strong></li><li>On the following screen, click the green button labelled <strong>Create pull request</strong></li></ol><hr><p><em>The CLA documents used for this project were created using <a class="tc-tiddlylink-external" href="http://www.harmonyagreements.org" rel="noopener noreferrer" target="_blank">Harmony Project Templates</a>. &quot;HA-CLA-I-LIST Version 1.0&quot; for &quot;CLA-individual&quot; and &quot;HA-CLA-E-LIST Version 1.0&quot; for &quot;CLA-entity&quot;.</em></p><h2 class="">Remarks</h2><p><strong>If you do not own the copyright in the entire work of authorship</strong>:</p><p>In this case, please clearly state so and provide links and any additional information that clarify under which license the rest of the code is distributed.
</p><p><em>This file was automatically generated by <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki5.html">TiddlyWiki5</a></em>
</p>

View File

@@ -32,6 +32,7 @@ ExportTiddler/Caption: export tiddler
ExportTiddler/Hint: Export tiddler
ExportTiddlers/Caption: export tiddlers
ExportTiddlers/Hint: Export tiddlers
SidebarSearch/Hint: Select the sidebar search field
Fold/Caption: fold tiddler
Fold/Hint: Fold the body of this tiddler
Fold/FoldBar/Caption: fold-bar
@@ -181,6 +182,7 @@ Subscript/Caption: subscript
Subscript/Hint: Apply subscript formatting to selection
Superscript/Caption: superscript
Superscript/Hint: Apply superscript formatting to selection
ToggleSidebar/Hint: Toggle the sidebar visibility
Transcludify/Caption: transclusion
Transcludify/Hint: Wrap selection in curly brackets
Underline/Caption: underline

View File

@@ -47,6 +47,8 @@ LoadedModules/Hint: These are the currently loaded tiddler modules linked to the
Palette/Caption: Palette
Palette/Editor/Clone/Caption: clone
Palette/Editor/Clone/Prompt: It is recommended that you clone this shadow palette before editing it
Palette/Editor/Delete/Hint: delete this entry from the current palette
Palette/Editor/Names/External/Show: Show color names that are not part of the current palette
Palette/Editor/Prompt/Modified: This shadow palette has been modified
Palette/Editor/Prompt: Editing
Palette/Editor/Reset/Caption: reset
@@ -89,6 +91,18 @@ Saving/DownloadSaver/Hint: These settings apply to the HTML5-compatible download
Saving/General/Caption: General
Saving/General/Hint: These settings apply to all the loaded savers
Saving/Hint: Settings used for saving the entire TiddlyWiki as a single file via a saver module
Saving/GitService/Branch: Target branch for saving
Saving/GitService/CommitMessage: Saved by TiddlyWiki
Saving/GitService/Description: These settings are only used when saving to <<service-name>>
Saving/GitService/Filename: Filename of target file (e.g. `index.html`)
Saving/GitService/Path: Path to target file (e.g. `/wiki/`)
Saving/GitService/Repo: Target repository (e.g. `Jermolene/TiddlyWiki5`)
Saving/GitService/ServerURL: Server API URL
Saving/GitService/UserName: Username
Saving/GitService/GitHub/Caption: ~GitHub Saver
Saving/GitService/GitHub/Password: Password, OAUTH token, or personal access token (see [[GitHub help page|https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line]] for details)
Saving/GitService/GitLab/Caption: ~GitLab Saver
Saving/GitService/GitLab/Password: Personal access token for API (see [[GitLab help page|https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html]] for details)
Saving/TiddlySpot/Advanced/Heading: Advanced Settings
Saving/TiddlySpot/BackupDir: Backup Directory
Saving/TiddlySpot/Backups: Backups

View File

@@ -14,8 +14,9 @@ draft.of: For draft tiddlers, contains the title of the tiddler of which this is
draft.title: For draft tiddlers, contains the proposed new title of the tiddler
footer: The footer text for a wizard
hack-to-give-us-something-to-compare-against: A temporary storage field used in [[$:/core/templates/static.content]]
hide-body: The view template will hide bodies of tiddlers if set to: ''yes''
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
library: Indicates that a tiddler should be saved as a JavaScript library if set to: ''yes''
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, or at the end of the list if this field is present but empty
@@ -31,5 +32,6 @@ subtitle: The subtitle text for a wizard
tags: A list of tags associated with a tiddler
text: The body text of a tiddler
title: The unique name of a tiddler
toc-link: Suppresses the tiddler's link in a Table of Contents tree if set to: ''no''
type: The content type of a tiddler
version: Version information for a plugin

View File

@@ -10,6 +10,7 @@ Orphans: Orphan tiddlers
SystemTiddlers: System tiddlers
ShadowTiddlers: Shadow tiddlers
OverriddenShadowTiddlers: Overridden shadow tiddlers
SessionTiddlers: Tiddlers modified since the wiki was loaded
SystemTags: System tags
StoryList: Tiddlers in the story river, excluding <$text text="$:/AdvancedSearch"/>
TypedTiddlers: Non wiki-text tiddlers

View File

@@ -0,0 +1,8 @@
title: $:/language/Help/deletetiddlers
description: Deletes a group of tiddlers
<<.from-version "5.1.20">> Deletes a group of tiddlers identified by a filter.
```
--deletetiddlers <filter>
```

View File

@@ -28,6 +28,7 @@ All parameters are optional with safe defaults, and can be specified in any orde
* ''tls-cert'' - pathname of TLS certificate file (relative to wiki folder)
* ''tls-key'' - pathname of TLS key file (relative to wiki folder)
* ''debug-level'' - optional debug level; set to "debug" to view request details (defaults to "none")
* ''gzip'' - set to "yes" to enable gzip compression for some http endpoints (defaults to "no")
For information on opening up your instance to the entire local network, and possible security concerns, see the WebServer tiddler at TiddlyWiki.com.

View File

@@ -4,10 +4,12 @@ description: Load tiddlers from a file
Load tiddlers from TiddlyWiki (`.html`), `.tiddler`, `.tid`, `.json` or other local files. The processing applied to incoming files is determined by the file extension. Use the alternative `import` command if you need to specify the deserializer and encoding explicitly.
```
--load <filepath>
--load <dirpath>
--load <filepath> [noerror]
--load <dirpath> [noerror]
```
By default, the load command raises an error if no tiddlers are found. The error can be suppressed by providing the optional "noerror" parameter.
To load tiddlers from an encrypted TiddlyWiki file you should first specify the password with the PasswordCommand. For example:
```

View File

@@ -13,8 +13,8 @@ A name and value for an additional variable may optionally also be specified.
* ''tiddler-filter'': A filter identifying the tiddler(s) to be rendered
* ''filename-filter'': Optional filter transforming tiddler titles into pathnames. If omitted, defaults to `[is[tiddler]addsuffix[.html]]`, which uses the unchanged tiddler title as the filename
* ''template'': Optional template through which each tiddler is rendered
* ''render-type'': Optional render type: `text/html` (the default) returns the full HTML text and `text/plain` just returns the text content (ie it ignores HTML tags and other unprintable material)
* ''template'': Optional template through which each tiddler is rendered
* ''name'': Name of optional variable
* ''value'': Value of optional variable

View File

@@ -0,0 +1,19 @@
title: $:/language/Help/savewikifolder
description: Saves a wiki to a new wiki folder
<<.from-version "5.1.20">> Saves the current wiki as a wiki folder, including tiddlers, plugins and configuration:
```
--savewikifolder <wikifolderpath> [<filter>]
```
* The target wiki folder must be empty or non-existent
* The filter specifies which tiddlers should be included. It is optional, defaulting to `[all[tiddlers]]`
* Plugins from the official plugin library are replaced with references to those plugins in the `tiddlywiki.info` file
* Custom plugins are unpacked into their own folder
A common usage is to convert a TiddlyWiki HTML file into a wiki folder:
```
tiddlywiki --load ./mywiki.html --savewikifolder ./mywikifolder
```

View File

@@ -18,4 +18,6 @@ Upgrader/Plugins/Suppressed/Version: Blocked plugin (due to incoming <<incoming>
Upgrader/Plugins/Upgraded: Upgraded plugin from <<incoming>> to <<upgraded>>
Upgrader/State/Suppressed: Blocked temporary state tiddler
Upgrader/System/Suppressed: Blocked system tiddler
Upgrader/System/Warning: Core module tiddler
Upgrader/System/Alert: You are about to import a tiddler that will overwrite a core module tiddler. This is not recommended as it may make the system unstable
Upgrader/ThemeTweaks/Created: Migrated theme tweak from <$text text=<<from>>/>

View File

@@ -0,0 +1,42 @@
/*\
title: $:/core/modules/commands/deletetiddlers.js
type: application/javascript
module-type: command
Command to delete tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "deletetiddlers",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filter";
}
var self = this,
wiki = this.commander.wiki,
filter = this.params[0],
tiddlers = wiki.filterTiddlers(filter);
$tw.utils.each(tiddlers,function(title) {
wiki.deleteTiddler(title);
});
return null;
};
exports.Command = Command;
})();

View File

@@ -38,7 +38,7 @@ Command.prototype.execute = function() {
count++;
});
});
if(!count) {
if(!count && self.params[1] !== "noerror") {
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
} else {
self.callback(null);

View File

@@ -0,0 +1,184 @@
/*\
title: $:/core/modules/commands/savewikifolder.js
type: application/javascript
module-type: command
Command to save the current wiki as a wiki folder
--savewikifolder <wikifolderpath> [<filter>]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "savewikifolder",
synchronous: true
};
var fs,path;
if($tw.node) {
fs = require("fs");
path = require("path");
}
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing wiki folder path";
}
var wikifoldermaker = new WikiFolderMaker(this.params[0],this.params[1],this.commander);
return wikifoldermaker.save();
};
function WikiFolderMaker(wikiFolderPath,wikiFilter,commander) {
this.wikiFolderPath = wikiFolderPath;
this.wikiFilter = wikiFilter || "[all[tiddlers]]";
this.commander = commander;
this.wiki = commander.wiki;
this.savedPaths = []; // So that we can detect filename clashes
}
WikiFolderMaker.prototype.log = function(str) {
if(this.commander.verbose) {
console.log(str);
}
};
WikiFolderMaker.prototype.tiddlersToIgnore = [
"$:/boot/boot.css",
"$:/boot/boot.js",
"$:/boot/bootprefix.js",
"$:/core",
"$:/library/sjcl.js",
"$:/temp/info-plugin"
];
/*
Returns null if successful, or an error string if there was an error
*/
WikiFolderMaker.prototype.save = function() {
var self = this;
// Check that the output directory doesn't exist
if(fs.existsSync(this.wikiFolderPath) && !$tw.utils.isDirectoryEmpty(this.wikiFolderPath)) {
return "The unpackwiki command requires that the output wiki folder be empty";
}
// Get the tiddlers from the source wiki
var tiddlerTitles = this.wiki.filterTiddlers(this.wikiFilter);
// Initialise a new tiddlwiki.info file
var newWikiInfo = {};
// Process each incoming tiddler in turn
$tw.utils.each(tiddlerTitles,function(title) {
var tiddler = self.wiki.getTiddler(title);
if(tiddler) {
if(self.tiddlersToIgnore.indexOf(title) !== -1) {
// Ignore the core plugin and the ephemeral info plugin
self.log("Ignoring tiddler: " + title);
} else {
var type = tiddler.fields.type,
pluginType = tiddler.fields["plugin-type"];
if(type === "application/json" && pluginType) {
// Plugin tiddler
var libraryDetails = self.findPluginInLibrary(title);
if(libraryDetails) {
// A plugin from the core library
self.log("Adding built-in plugin: " + libraryDetails.name);
newWikiInfo[libraryDetails.type] = newWikiInfo[libraryDetails.type] || [];
$tw.utils.pushTop(newWikiInfo[libraryDetails.type],libraryDetails.name);
} else {
// A custom plugin
self.log("Processing custom plugin: " + title);
self.saveCustomPlugin(tiddler);
}
} else {
// Ordinary tiddler
self.saveTiddler("tiddlers",tiddler);
}
}
}
});
// Save the tiddlywiki.info file
this.saveJSONFile("tiddlywiki.info",newWikiInfo);
self.log("Writing tiddlywiki.info: " + JSON.stringify(newWikiInfo,null,$tw.config.preferences.jsonSpaces));
return null;
};
/*
Test whether the specified tiddler is a plugin in the plugin library
*/
WikiFolderMaker.prototype.findPluginInLibrary = function(title) {
var parts = title.split("/"),
pluginPath, type, name;
if(parts[0] === "$:") {
if(parts[1] === "languages" && parts.length === 3) {
pluginPath = "languages" + path.sep + parts[2];
type = parts[1];
name = parts[2];
} else if(parts[1] === "plugins" || parts[1] === "themes" && parts.length === 4) {
pluginPath = parts[1] + path.sep + parts[2] + path.sep + parts[3];
type = parts[1];
name = parts[2] + "/" + parts[3];
}
}
if(pluginPath && type && name) {
pluginPath = path.resolve($tw.boot.bootPath,"..",pluginPath);
if(fs.existsSync(pluginPath)) {
return {
pluginPath: pluginPath,
type: type,
name: name
};
}
}
return false;
};
WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
var self = this,
pluginTitle = pluginTiddler.fields.title,
titleParts = pluginTitle.split("/"),
directory = $tw.utils.generateTiddlerFilepath(titleParts[titleParts.length - 1],{
directory: path.resolve(this.wikiFolderPath,pluginTiddler.fields["plugin-type"] + "s")
}),
pluginInfo = pluginTiddler.getFieldStrings({exclude: ["text","type"]});
this.saveJSONFile(directory + path.sep + "plugin.info",pluginInfo);
self.log("Writing " + directory + path.sep + "plugin.info: " + JSON.stringify(pluginInfo,null,$tw.config.preferences.jsonSpaces));
var pluginTiddlers = JSON.parse(pluginTiddler.fields.text).tiddlers; // A hashmap of tiddlers in the plugin
$tw.utils.each(pluginTiddlers,function(tiddler) {
self.saveTiddler(directory,new $tw.Tiddler(tiddler));
});
};
WikiFolderMaker.prototype.saveTiddler = function(directory,tiddler) {
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
directory: path.resolve(this.wikiFolderPath,directory),
wiki: this.wiki
});
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
};
WikiFolderMaker.prototype.saveJSONFile = function(filename,json) {
this.saveTextFile(filename,JSON.stringify(json,null,$tw.config.preferences.jsonSpaces));
};
WikiFolderMaker.prototype.saveTextFile = function(filename,data) {
this.saveFile(filename,"utf8",data);
};
WikiFolderMaker.prototype.saveFile = function(filename,encoding,data) {
var filepath = path.resolve(this.wikiFolderPath,filename);
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,data,encoding);
};
exports.Command = Command;
})();

View File

@@ -42,6 +42,7 @@ function FramedEngine(options) {
this.iframeNode.style.border = "none";
this.iframeNode.style.padding = "0";
this.iframeNode.style.resize = "none";
this.iframeNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
this.iframeDoc.body.style.margin = "0";
this.iframeDoc.body.style.padding = "0";
this.widget.domNodes.push(this.iframeNode);
@@ -70,11 +71,15 @@ function FramedEngine(options) {
if(this.widget.editRows) {
this.domNode.setAttribute("rows",this.widget.editRows);
}
if(this.widget.editTabIndex) {
this.iframeNode.setAttribute("tabindex",this.widget.editTabIndex);
}
// Copy the styles from the dummy textarea
this.copyStyles();
// Add event listeners
$tw.utils.addEventListeners(this.domNode,[
{name: "click",handlerObject: this,handlerMethod: "handleClickEvent"},
{name: "focus",handlerObject: this,handlerMethod: "handleFocusEvent"},
{name: "input",handlerObject: this,handlerMethod: "handleInputEvent"},
{name: "keydown",handlerObject: this.widget,handlerMethod: "handleKeydownEvent"}
]);
@@ -92,6 +97,7 @@ FramedEngine.prototype.copyStyles = function() {
this.domNode.style.display = "block";
this.domNode.style.width = "100%";
this.domNode.style.margin = "0";
this.domNode.style["background-color"] = this.widget.wiki.extractTiddlerDataItem(this.widget.wiki.getTiddlerText("$:/palette"),"tiddler-editor-background");
// In Chrome setting -webkit-text-fill-color overrides the placeholder text colour
this.domNode.style["-webkit-text-fill-color"] = "currentcolor";
};
@@ -147,6 +153,14 @@ FramedEngine.prototype.focus = function() {
this.domNode.select();
}
};
/*
Handle the focus event
*/
FramedEngine.prototype.handleFocusEvent = function(event) {
this.widget.cancelPopups();
return true;
};
/*
Handle a click

View File

@@ -49,6 +49,9 @@ function SimpleEngine(options) {
if(this.widget.editClass) {
this.domNode.className = this.widget.editClass;
}
if(this.widget.editTabIndex) {
this.domNode.setAttribute("tabindex",this.widget.editTabIndex);
}
// Add an input event handler
$tw.utils.addEventListeners(this.domNode,[
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
@@ -119,6 +122,7 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
Handle a dom "focus" event
*/
SimpleEngine.prototype.handleFocusEvent = function(event) {
this.widget.cancelPopups();
if(this.widget.editFocusPopup) {
$tw.popup.triggerPopup({
domNode: this.domNode,

View File

@@ -176,6 +176,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.editMinHeight = this.getAttribute("minHeight",DEFAULT_MIN_TEXT_AREA_HEIGHT);
this.editFocusPopup = this.getAttribute("focusPopup");
this.editFocus = this.getAttribute("focus");
this.editTabIndex = this.getAttribute("tabindex");
// Get the default editor element tag and type
var tag,type;
if(this.editField === "text") {
@@ -192,7 +193,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
type = type || "text";
}
// Get the rest of our parameters
this.editTag = this.getAttribute("tag",tag);
this.editTag = this.getAttribute("tag",tag) || "input";
this.editType = this.getAttribute("type",type);
// Make the child widgets
this.makeChildWidgets();
@@ -207,7 +208,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
EditTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Completely rerender if any of our attributes have changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE]) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE]) {
this.refreshSelf();
return true;
} else if(changedTiddlers[this.editTitle]) {
@@ -216,7 +217,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
}
this.engine.fixHeight();
if(this.editShowToolbar) {
return this.refreshChildren(changedTiddlers);
return this.refreshChildren(changedTiddlers);
} else {
return false;
}
@@ -247,6 +248,13 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
}
};
/*
Cancel Popups
*/
EditTextWidget.prototype.cancelPopups = function() {
$tw.popup.cancel(0,this.engine.domNode);
};
/*
Handle a dom "keydown" event, which we'll bubble up to our container for the keyboard widgets benefit
*/
@@ -266,7 +274,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
el.dispatchEvent(clickEvent);
event.preventDefault();
event.stopPropagation();
return true;
return true;
}
}
}

View File

@@ -16,14 +16,12 @@ exports["wrap-selection"] = function(event,operation) {
if(operation.selStart === operation.selEnd) {
// No selection; check if we're within the prefix/suffix
if(operation.text.substring(operation.selStart - event.paramObject.prefix.length,operation.selStart + event.paramObject.suffix.length) === event.paramObject.prefix + event.paramObject.suffix) {
// Remove the prefix and suffix unless they comprise the entire text
if(operation.selStart > event.paramObject.prefix.length || (operation.selEnd + event.paramObject.suffix.length) < operation.text.length ) {
operation.cutStart = operation.selStart - event.paramObject.prefix.length;
operation.cutEnd = operation.selEnd + event.paramObject.suffix.length;
operation.replacement = "";
operation.newSelStart = operation.cutStart;
operation.newSelEnd = operation.newSelStart;
}
// Remove the prefix and suffix
operation.cutStart = operation.selStart - event.paramObject.prefix.length;
operation.cutEnd = operation.selEnd + event.paramObject.suffix.length;
operation.replacement = "";
operation.newSelStart = operation.cutStart;
operation.newSelEnd = operation.newSelStart;
} else {
// Wrap the cursor instead
operation.cutStart = operation.selStart;

View File

@@ -119,7 +119,7 @@ exports.parseFilter = function(filterString) {
p = 0, // Current position in the filter string
match;
var whitespaceRegExp = /(\s+)/mg,
operandRegExp = /((?:\+|\-|~)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
operandRegExp = /((?:\+|\-|~|=)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
while(p < filterString.length) {
// Skip any whitespace
whitespaceRegExp.lastIndex = p;
@@ -248,6 +248,10 @@ exports.compileFilter = function(filterString) {
return function(results,source,widget) {
$tw.utils.pushTop(results,operationSubFunction(source,widget));
};
case "=": // The results of the operation are pushed into the result without deduplication
return function(results,source,widget) {
Array.prototype.push.apply(results,operationSubFunction(source,widget));
};
case "-": // The results of this operation are removed from the main result
return function(results,source,widget) {
$tw.utils.removeArrayEntries(results,operationSubFunction(source,widget));
@@ -270,7 +274,7 @@ exports.compileFilter = function(filterString) {
})());
});
// Return a function that applies the operations to a source iterator of tiddler titles
return $tw.perf.measure("filter",function filterFunction(source,widget) {
return $tw.perf.measure("filter: " + filterString,function filterFunction(source,widget) {
if(!source) {
source = self.each;
} else if(typeof source === "object") { // Array or hashmap

View File

@@ -0,0 +1,30 @@
/*\
title: $:/core/modules/filters/else.js
type: application/javascript
module-type: filteroperator
Filter operator for replacing an empty input list with a constant, passing a non-empty input list straight through
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.else = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(title);
});
if(results.length === 0) {
return [operator.operand];
} else {
return results;
}
};
})();

View File

@@ -98,4 +98,13 @@ exports.escaperegexp = function(source,operator,options) {
return results;
};
exports.escapecss = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
// escape any character with a special meaning in CSS using CSS.escape()
results.push(CSS.escape(title));
});
return results;
};
})();

View File

@@ -16,7 +16,16 @@ Filter operator returning its operand parsed as a list
Export our filter function
*/
exports.enlist = function(source,operator,options) {
var list = $tw.utils.parseStringArray(operator.operand);
var allowDuplicates = false;
switch(operator.suffix) {
case "raw":
allowDuplicates = true;
break;
case "dedupe":
allowDuplicates = false;
break;
}
var list = $tw.utils.parseStringArray(operator.operand,allowDuplicates);
if(operator.prefix === "!") {
var results = [];
source(function(tiddler,title) {

View File

@@ -16,7 +16,7 @@ Filter operator for comparing fields for equality
Export our filter function
*/
exports.field = function(source,operator,options) {
var results = [],
var results = [],indexedResults,
fieldname = (operator.suffix || operator.operator || "title").toLowerCase();
if(operator.prefix === "!") {
if(operator.regexp) {
@@ -53,6 +53,12 @@ exports.field = function(source,operator,options) {
}
});
} else {
if(source.byField && operator.operand) {
indexedResults = source.byField(fieldname,operator.operand);
if(indexedResults) {
return indexedResults
}
}
source(function(tiddler,title) {
if(tiddler) {
var text = tiddler.getFieldString(fieldname);

View File

@@ -0,0 +1,26 @@
/*\
title: $:/core/modules/filters/getvariable.js
type: application/javascript
module-type: filteroperator
Filter operator for replacing input values by the value of the variable with the same name, or blank if the variable is missing
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.getvariable = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(options.widget.getVariable(title) || "");
});
return results;
};
})();

View File

@@ -45,7 +45,7 @@ exports.has = function(source,operator,options) {
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && !(tiddler.fields[operator.operand] === "" || tiddler.fields[operator.operand].length === 0)) {
results.push(title);
}
});
});
}
}
return results;

View File

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

View File

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

View File

@@ -0,0 +1,53 @@
/*\
title: $:/core/modules/filters/match.js
type: application/javascript
module-type: filteroperator
Filter operator for checking if a title matches a string
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.match = function(source,operator,options) {
var results = [],
suffixes = (operator.suffixes || [])[0] || [];
if(suffixes.indexOf("caseinsensitive") !== -1) {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title.toLowerCase() !== (operator.operand || "").toLowerCase()) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(title.toLowerCase() === (operator.operand || "").toLowerCase()) {
results.push(title);
}
});
}
} else {
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(title !== operator.operand) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(title === operator.operand) {
results.push(title);
}
});
}
}
return results;
};
})();

View File

@@ -0,0 +1,146 @@
/*\
title: $:/core/modules/filters/math.js
type: application/javascript
module-type: filteroperator
Filter operators for math. Unary/binary operators work on each item in turn, and return a new item list.
Sum/product/maxall/minall operate on the entire list, returning a single item.
Note that strings are converted to numbers automatically. Trailing non-digits are ignored.
* "" converts to 0
* "12kk" converts to 12
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.negate = makeNumericBinaryOperator(
function(a) {return -a}
);
exports.abs = makeNumericBinaryOperator(
function(a) {return Math.abs(a)}
);
exports.ceil = makeNumericBinaryOperator(
function(a) {return Math.ceil(a)}
);
exports.floor = makeNumericBinaryOperator(
function(a) {return Math.floor(a)}
);
exports.round = makeNumericBinaryOperator(
function(a) {return Math.round(a)}
);
exports.trunc = makeNumericBinaryOperator(
function(a) {return Math.trunc(a)}
);
exports.untrunc = makeNumericBinaryOperator(
function(a) {return Math.ceil(Math.abs(a)) * Math.sign(a)}
);
exports.sign = makeNumericBinaryOperator(
function(a) {return Math.sign(a)}
);
exports.add = makeNumericBinaryOperator(
function(a,b) {return a + b;}
);
exports.subtract = makeNumericBinaryOperator(
function(a,b) {return a - b;}
);
exports.multiply = makeNumericBinaryOperator(
function(a,b) {return a * b;}
);
exports.divide = makeNumericBinaryOperator(
function(a,b) {return a / b;}
);
exports.remainder = makeNumericBinaryOperator(
function(a,b) {return a % b;}
);
exports.max = makeNumericBinaryOperator(
function(a,b) {return Math.max(a,b);}
);
exports.min = makeNumericBinaryOperator(
function(a,b) {return Math.min(a,b);}
);
exports.fixed = makeNumericBinaryOperator(
function(a,b) {return Number.prototype.toFixed.call(a,Math.min(Math.max(b,0),100));}
);
exports.precision = makeNumericBinaryOperator(
function(a,b) {return Number.prototype.toPrecision.call(a,Math.min(Math.max(b,1),100));}
);
exports.exponential = makeNumericBinaryOperator(
function(a,b) {return Number.prototype.toExponential.call(a,Math.min(Math.max(b,0),100));}
);
exports.sum = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value},
0 // Initial value
);
exports.product = makeNumericReducingOperator(
function(accumulator,value) {return accumulator * value},
1 // Initial value
);
exports.maxall = makeNumericReducingOperator(
function(accumulator,value) {return Math.max(accumulator,value)},
-Infinity // Initial value
);
exports.minall = makeNumericReducingOperator(
function(accumulator,value) {return Math.min(accumulator,value)},
Infinity // Initial value
);
function makeNumericBinaryOperator(fnCalc) {
return function(source,operator,options) {
var result = [],
numOperand = parseNumber(operator.operand);
source(function(tiddler,title) {
result.push(stringifyNumber(fnCalc(parseNumber(title),numOperand)));
});
return result;
};
}
function makeNumericReducingOperator(fnCalc,initialValue) {
initialValue = initialValue || 0;
return function(source,operator,options) {
var result = [];
source(function(tiddler,title) {
result.push(title);
});
return [stringifyNumber(result.reduce(function(accumulator,currentValue) {
return fnCalc(accumulator,parseNumber(currentValue));
},initialValue))];
};
}
function parseNumber(str) {
return parseFloat(str) || 0;
}
function stringifyNumber(num) {
return num + "";
}
})();

View File

@@ -18,7 +18,7 @@ Export our filter function
exports.removesuffix = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
if(title.substr(-operator.operand.length) === operator.operand) {
if(title && title.substr(-operator.operand.length) === operator.operand) {
results.push(title.substr(0,title.length - operator.operand.length));
}
});

View File

@@ -43,6 +43,7 @@ exports.search = function(source,operator,options) {
caseSensitive: hasFlag("casesensitive"),
literal: hasFlag("literal"),
whitespace: hasFlag("whitespace"),
anchored: hasFlag("anchored"),
regexp: hasFlag("regexp"),
words: hasFlag("words")
});

View File

@@ -0,0 +1,93 @@
/*\
title: $:/core/modules/filters/strings.js
type: application/javascript
module-type: filteroperator
Filter operators for strings. Unary/binary operators work on each item in turn, and return a new item list.
Sum/product/maxall/minall operate on the entire list, returning a single item.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.length = makeStringBinaryOperator(
function(a) {return ["" + ("" + a).length];}
);
exports.uppercase = makeStringBinaryOperator(
function(a) {return [("" + a).toUpperCase()];}
);
exports.lowercase = makeStringBinaryOperator(
function(a) {return [("" + a).toLowerCase()];}
);
exports.sentencecase = makeStringBinaryOperator(
function(a) {return [$tw.utils.toSentenceCase(a)];}
);
exports.titlecase = makeStringBinaryOperator(
function(a) {return [$tw.utils.toTitleCase(a)];}
);
exports.trim = makeStringBinaryOperator(
function(a) {return [$tw.utils.trim(a)];}
);
exports.split = makeStringBinaryOperator(
function(a,b) {return ("" + a).split(b);}
);
exports.join = makeStringReducingOperator(
function(accumulator,value,operand) {
if(accumulator === null) {
return value;
} else {
return accumulator + operand + value;
}
},null
);
function makeStringBinaryOperator(fnCalc) {
return function(source,operator,options) {
var result = [];
source(function(tiddler,title) {
Array.prototype.push.apply(result,fnCalc(title,operator.operand || ""));
});
return result;
};
}
function makeStringReducingOperator(fnCalc,initialValue) {
return function(source,operator,options) {
var result = [];
source(function(tiddler,title) {
result.push(title);
});
return [result.reduce(function(accumulator,currentValue) {
return fnCalc(accumulator,currentValue,operator.operand || "");
},initialValue)];
};
}
exports.splitregexp = function(source,operator,options) {
var result = [],
suffix = operator.suffix || "",
flags = (suffix.indexOf("m") !== -1 ? "m" : "") + (suffix.indexOf("i") !== -1 ? "i" : ""),
regExp;
try {
regExp = new RegExp(operator.operand || "",flags);
} catch(ex) {
return ["RegExp error: " + ex];
}
source(function(tiddler,title) {
Array.prototype.push.apply(result,title.split(regExp));
});
return result;
};
})();

View File

@@ -16,7 +16,7 @@ Filter operator for checking for the presence of a tag
Export our filter function
*/
exports.tag = function(source,operator,options) {
var results = [];
var results = [],indexedResults;
if((operator.suffix || "").toLowerCase() === "strict" && !operator.operand) {
// New semantics:
// Always return copy of input if operator.operand is missing
@@ -25,9 +25,10 @@ exports.tag = function(source,operator,options) {
});
} else {
// Old semantics:
var tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
var tiddlers;
if(operator.prefix === "!") {
// Returns a copy of the input if operator.operand is missing
tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
source(function(tiddler,title) {
if(tiddlers.indexOf(title) === -1) {
results.push(title);
@@ -35,12 +36,20 @@ exports.tag = function(source,operator,options) {
});
} else {
// Returns empty results if operator.operand is missing
source(function(tiddler,title) {
if(tiddlers.indexOf(title) !== -1) {
results.push(title);
if(source.byTag) {
indexedResults = source.byTag(operator.operand);
if(indexedResults) {
return indexedResults;
}
});
results = options.wiki.sortByList(results,operator.operand);
} else {
tiddlers = options.wiki.getTiddlersWithTag(operator.operand);
source(function(tiddler,title) {
if(tiddlers.indexOf(title) !== -1) {
results.push(title);
}
});
results = options.wiki.sortByList(results,operator.operand);
}
}
}
return results;

View File

@@ -0,0 +1,26 @@
/*\
title: $:/core/modules/filters/then.js
type: application/javascript
module-type: filteroperator
Filter operator for replacing any titles with a constant
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.then = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(operator.operand);
});
return results;
};
})();

View File

@@ -0,0 +1,26 @@
/*\
title: $:/core/modules/filters/variables.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the names of the active variables
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.variables = function(source,operator,options) {
var names = [];
for(var variable in options.widget.variables) {
names.push(variable);
}
return names.sort();
};
})();

View File

@@ -95,7 +95,7 @@ Extended filter operators to manipulate the current list.
exports.allafter = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index === -1 || index > (results.length - 2)) ? [] :
return (index === -1) ? [] :
(operator.suffix) ? results.slice(index) :
results.slice(index + 1);
};
@@ -106,7 +106,7 @@ Extended filter operators to manipulate the current list.
exports.allbefore = function (source, operator) {
var results = prepare_results(source),
index = results.indexOf(operator.operand);
return (index < 0) ? [] :
return (index === -1) ? [] :
(operator.suffix) ? results.slice(0, index + 1) :
results.slice(0, index);
};

View File

@@ -0,0 +1,143 @@
/*\
title: $:/core/modules/indexers/field-indexer.js
type: application/javascript
module-type: indexer
Indexes the tiddlers with each field value
\*/
(function(){
/*jslint node: true, browser: true */
/*global modules: false */
"use strict";
var DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH = 128;
function FieldIndexer(wiki) {
this.wiki = wiki;
}
FieldIndexer.prototype.init = function() {
this.index = null;
this.maxIndexedValueLength = DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH;
this.addIndexMethods();
}
// Provided for testing
FieldIndexer.prototype.setMaxIndexedValueLength = function(length) {
this.index = null;
this.maxIndexedValueLength = length;
};
FieldIndexer.prototype.addIndexMethods = function() {
var self = this;
this.wiki.each.byField = function(name,value) {
var titles = self.wiki.allTitles(),
lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) {
return titles.indexOf(title) !== -1;
});
};
this.wiki.eachShadow.byField = function(name,value) {
var titles = self.wiki.allShadowTitles(),
lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) {
return titles.indexOf(title) !== -1;
});
};
this.wiki.eachTiddlerPlusShadows.byField = function(name,value) {
var lookup = self.lookup(name,value);
return lookup ? lookup.slice(0) : null;
};
this.wiki.eachShadowPlusTiddlers.byField = function(name,value) {
var lookup = self.lookup(name,value);
return lookup ? lookup.slice(0) : null;
};
};
/*
Tear down and then rebuild the index as if all tiddlers have changed
*/
FieldIndexer.prototype.rebuild = function() {
// Invalidate the index so that it will be rebuilt when it is next used
this.index = null;
};
/*
Build the index for a particular field
*/
FieldIndexer.prototype.buildIndexForField = function(name) {
var self = this;
// Hashmap by field name of hashmap by field value of array of tiddler titles
this.index = this.index || Object.create(null);
this.index[name] = Object.create(null);
var baseIndex = this.index[name];
// Update the index for each tiddler
this.wiki.eachTiddlerPlusShadows(function(tiddler,title) {
if(name in tiddler.fields) {
var value = tiddler.getFieldString(name);
// Skip any values above the maximum length
if(value.length < self.maxIndexedValueLength) {
baseIndex[value] = baseIndex[value] || [];
baseIndex[value].push(title);
}
}
});
};
/*
Update the index in the light of a tiddler value changing; note that the title must be identical. (Renames are handled as a separate delete and create)
updateDescriptor: {old: {tiddler: <tiddler>, shadow: <boolean>, exists: <boolean>},new: {tiddler: <tiddler>, shadow: <boolean>, exists: <boolean>}}
*/
FieldIndexer.prototype.update = function(updateDescriptor) {
var self = this;
// Don't do anything if the index hasn't been built yet
if(this.index === null) {
return;
}
// Remove the old tiddler from the index
if(updateDescriptor.old.tiddler) {
$tw.utils.each(this.index,function(indexEntry,name) {
if(name in updateDescriptor.old.tiddler.fields) {
var value = updateDescriptor.old.tiddler.getFieldString(name),
tiddlerList = indexEntry[value];
if(tiddlerList) {
var index = tiddlerList.indexOf(updateDescriptor.old.tiddler.fields.title);
if(index !== -1) {
tiddlerList.splice(index,1);
}
}
}
});
}
// Add the new tiddler to the index
if(updateDescriptor["new"].tiddler) {
$tw.utils.each(this.index,function(indexEntry,name) {
if(name in updateDescriptor["new"].tiddler.fields) {
var value = updateDescriptor["new"].tiddler.getFieldString(name);
if(value.length < self.maxIndexedValueLength) {
indexEntry[value] = indexEntry[value] || [];
indexEntry[value].push(updateDescriptor["new"].tiddler.fields.title);
}
}
});
}
};
// Lookup the given field returning a list of tiddler titles
FieldIndexer.prototype.lookup = function(name,value) {
// Fail the lookup if the value is too long
if(value.length >= this.maxIndexedValueLength) {
return null;
}
// Update the index if it has yet to be built
if(this.index === null || !this.index[name]) {
this.buildIndexForField(name);
}
return this.index[name][value] || [];
};
exports.FieldIndexer = FieldIndexer;
})();

View File

@@ -0,0 +1,98 @@
/*\
title: $:/core/modules/indexers/tag-indexer.js
type: application/javascript
module-type: indexer
Indexes the tiddlers with each tag
\*/
(function(){
/*jslint node: true, browser: true */
/*global modules: false */
"use strict";
function TagIndexer(wiki) {
this.wiki = wiki;
}
TagIndexer.prototype.init = function() {
this.subIndexers = [
new TagSubIndexer(this,"each"),
new TagSubIndexer(this,"eachShadow"),
new TagSubIndexer(this,"eachTiddlerPlusShadows"),
new TagSubIndexer(this,"eachShadowPlusTiddlers")
];
$tw.utils.each(this.subIndexers,function(subIndexer) {
subIndexer.addIndexMethod();
});
};
TagIndexer.prototype.rebuild = function() {
$tw.utils.each(this.subIndexers,function(subIndexer) {
subIndexer.rebuild();
});
};
TagIndexer.prototype.update = function(updateDescriptor) {
$tw.utils.each(this.subIndexers,function(subIndexer) {
subIndexer.update(updateDescriptor);
});
};
function TagSubIndexer(indexer,iteratorMethod) {
this.indexer = indexer;
this.iteratorMethod = iteratorMethod;
this.index = null; // Hashmap of tag title to {isSorted: bool, titles: [array]} or null if not yet initialised
}
TagSubIndexer.prototype.addIndexMethod = function() {
var self = this;
this.indexer.wiki[this.iteratorMethod].byTag = function(tag) {
return self.lookup(tag).slice(0);
};
};
TagSubIndexer.prototype.rebuild = function() {
var self = this;
// Hashmap by tag of array of {isSorted:, titles:[]}
this.index = Object.create(null);
// Add all the tags
this.indexer.wiki[this.iteratorMethod](function(tiddler,title) {
$tw.utils.each(tiddler.fields.tags,function(tag) {
if(!self.index[tag]) {
self.index[tag] = {isSorted: false, titles: [title]};
} else {
self.index[tag].titles.push(title);
}
});
});
};
TagSubIndexer.prototype.update = function(updateDescriptor) {
this.index = null;
};
TagSubIndexer.prototype.lookup = function(tag) {
// Update the index if it has yet to be built
if(this.index === null) {
this.rebuild();
}
var indexRecord = this.index[tag];
if(indexRecord) {
if(!indexRecord.isSorted) {
if(this.indexer.wiki.sortByList) {
indexRecord.titles = this.indexer.wiki.sortByList(indexRecord.titles,tag);
}
indexRecord.isSorted = true;
}
return indexRecord.titles;
} else {
return [];
}
};
exports.TagIndexer = TagIndexer;
})();

View File

@@ -35,6 +35,8 @@ exports.getInfoTiddlerFields = function() {
// Screen size
infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.toString()});
infoTiddlerFields.push({title: "$:/info/browser/screen/height", text: window.screen.height.toString()});
// Language
infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""});
}
return infoTiddlerFields;
};

View File

@@ -1,41 +0,0 @@
/*\
title: $:/core/modules/macros/dumpvariables.js
type: application/javascript
module-type: macro
Macro to dump all active variable values
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Information about this macro
*/
exports.name = "dumpvariables";
exports.params = [
];
/*
Run the macro
*/
exports.run = function() {
var output = ["|!Variable |!Value |"],
variables = [], variable;
for(variable in this.variables) {
variables.push(variable);
}
variables.sort();
for(var index=0; index<variables.length; index++) {
var variable = variables[index];
output.push("|" + variable + " |<input size=50 value=<<" + variable + ">>/> |")
}
return output.join("\n");
};
})();

View File

@@ -0,0 +1,34 @@
/*\
title: $:/core/modules/macros/unusedtitle.js
type: application/javascript
module-type: macro
Macro to return a new title that is unused in the wiki. It can be given a name as a base.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Information about this macro
*/
exports.name = "unusedtitle";
exports.params = [
{name: "baseName"},
{name: "options"}
];
/*
Run the macro
*/
exports.run = function(baseName, options) {
if(!baseName) {
baseName = $tw.language.getString("DefaultNewTiddlerTitle");
}
return this.wiki.generateNewTitle(baseName, options);
};
})();

View File

@@ -27,8 +27,6 @@ exports.init = function(parser) {
};
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

View File

@@ -21,6 +21,7 @@ function SaverHandler(options) {
var self = this;
this.wiki = options.wiki;
this.dirtyTracking = options.dirtyTracking;
this.preloadDirty = options.preloadDirty || [];
this.pendingAutoSave = false;
// Make a logger
this.logger = new $tw.utils.Logger("saver-handler");
@@ -33,7 +34,13 @@ function SaverHandler(options) {
// Compile the dirty tiddler filter
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
// Count of changes that have not yet been saved
this.numChanges = 0;
var filteredChanges = self.filterFn.call(self.wiki,function(iterator) {
$tw.utils.each(self.preloadDirty,function(title) {
var tiddler = self.wiki.getTiddler(title);
iterator(tiddler,title);
});
});
this.numChanges = filteredChanges.length;
// Listen out for changes to tiddlers
this.wiki.addEventListener("change",function(changes) {
// Filter the changes so that we only count changes to tiddlers that we care about
@@ -144,8 +151,12 @@ Save the wiki contents. Options are:
SaverHandler.prototype.saveWiki = function(options) {
options = options || {};
var self = this,
method = options.method || "save",
variables = options.variables || {},
method = options.method || "save";
// Ignore autosave if disabled
if(method === "autosave" && this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes") {
return false;
}
var variables = options.variables || {},
template = options.template || "$:/core/save/all",
downloadType = options.downloadType || "text/plain",
text = this.wiki.renderTiddler(downloadType,template,options),
@@ -164,10 +175,6 @@ SaverHandler.prototype.saveWiki = function(options) {
}
}
};
// Ignore autosave if disabled
if(method === "autosave" && this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes") {
return false;
}
// Call the highest priority saver that supports this method
for(var t=this.savers.length-1; t>=0; t--) {
var saver = this.savers[t];

View File

@@ -0,0 +1,118 @@
/*\
title: $:/core/modules/savers/github.js
type: application/javascript
module-type: saver
Saves wiki by pushing a commit to the GitHub v3 REST API
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Select the appropriate saver module and set it up
*/
var GitHubSaver = function(wiki) {
this.wiki = wiki;
};
GitHubSaver.prototype.save = function(text,method,callback) {
var self = this,
username = this.wiki.getTiddlerText("$:/GitHub/Username"),
password = $tw.utils.getPassword("github"),
repo = this.wiki.getTiddlerText("$:/GitHub/Repo"),
path = this.wiki.getTiddlerText("$:/GitHub/Path"),
filename = this.wiki.getTiddlerText("$:/GitHub/Filename"),
branch = this.wiki.getTiddlerText("$:/GitHub/Branch") || "master",
endpoint = this.wiki.getTiddlerText("$:/GitHub/ServerURL") || "https://api.github.com",
headers = {
"Accept": "application/vnd.github.v3+json",
"Content-Type": "application/json;charset=UTF-8",
"Authorization": "Basic " + window.btoa(username + ":" + password)
};
// Bail if we don't have everything we need
if(!username || !password || !repo || !path || !filename) {
return false;
}
// Make sure the path start and ends with a slash
if(path.substring(0,1) !== "/") {
path = "/" + path;
}
if(path.substring(path.length - 1) !== "/") {
path = path + "/";
}
// Compose the base URI
var uri = endpoint + "/repos/" + repo + "/contents" + path;
// Perform a get request to get the details (inc shas) of files in the same path as our file
$tw.utils.httpRequest({
url: uri,
type: "GET",
headers: headers,
data: {
ref: branch
},
callback: function(err,getResponseDataJson,xhr) {
var getResponseData,sha = "";
if(err && xhr.status !== 404) {
return callback(err);
}
if(xhr.status !== 404) {
getResponseData = JSON.parse(getResponseDataJson);
$tw.utils.each(getResponseData,function(details) {
if(details.name === filename) {
sha = details.sha;
}
});
}
var data = {
message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
content: $tw.utils.base64Encode(text),
branch: branch,
sha: sha
};
// Perform a PUT request to save the file
$tw.utils.httpRequest({
url: uri + filename,
type: "PUT",
headers: headers,
data: JSON.stringify(data),
callback: function(err,putResponseDataJson,xhr) {
if(err) {
return callback(err);
}
var putResponseData = JSON.parse(putResponseDataJson);
callback(null);
}
});
}
});
return true;
};
/*
Information about this saver
*/
GitHubSaver.prototype.info = {
name: "github",
priority: 2000,
capabilities: ["save", "autosave"]
};
/*
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
return true;
};
/*
Create an instance of this saver
*/
exports.create = function(wiki) {
return new GitHubSaver(wiki);
};
})();

View File

@@ -0,0 +1,120 @@
/*\
title: $:/core/modules/savers/gitlab.js
type: application/javascript
module-type: saver
Saves wiki by pushing a commit to the GitLab REST API
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: true */
"use strict";
/*
Select the appropriate saver module and set it up
*/
var GitLabSaver = function(wiki) {
this.wiki = wiki;
};
GitLabSaver.prototype.save = function(text,method,callback) {
/* See https://docs.gitlab.com/ee/api/repository_files.html */
var self = this,
username = this.wiki.getTiddlerText("$:/GitLab/Username"),
password = $tw.utils.getPassword("gitlab"),
repo = this.wiki.getTiddlerText("$:/GitLab/Repo"),
path = this.wiki.getTiddlerText("$:/GitLab/Path"),
filename = this.wiki.getTiddlerText("$:/GitLab/Filename"),
branch = this.wiki.getTiddlerText("$:/GitLab/Branch") || "master",
endpoint = this.wiki.getTiddlerText("$:/GitLab/ServerURL") || "https://gitlab.com/api/v4",
headers = {
"Content-Type": "application/json;charset=UTF-8",
"Private-Token": password
};
// Bail if we don't have everything we need
if(!username || !password || !repo || !path || !filename) {
return false;
}
// Make sure the path start and ends with a slash
if(path.substring(0,1) !== "/") {
path = "/" + path;
}
if(path.substring(path.length - 1) !== "/") {
path = path + "/";
}
// Compose the base URI
var uri = endpoint + "/projects/" + encodeURIComponent(repo) + "/repository/";
// Perform a get request to get the details (inc shas) of files in the same path as our file
$tw.utils.httpRequest({
url: uri + "tree/" + encodeURIComponent(path.replace(/^\/+|\/$/g, '')),
type: "GET",
headers: headers,
data: {
ref: branch
},
callback: function(err,getResponseDataJson,xhr) {
var getResponseData,sha = "";
if(err && xhr.status !== 404) {
return callback(err);
}
var requestType = "POST";
if(xhr.status !== 404) {
getResponseData = JSON.parse(getResponseDataJson);
$tw.utils.each(getResponseData,function(details) {
if(details.name === filename) {
requestType = "PUT";
sha = details.sha;
}
});
}
var data = {
commit_message: $tw.language.getRawString("ControlPanel/Saving/GitService/CommitMessage"),
content: text,
branch: branch,
sha: sha
};
// Perform a request to save the file
$tw.utils.httpRequest({
url: uri + "files/" + encodeURIComponent(path.replace(/^\/+/, '') + filename),
type: requestType,
headers: headers,
data: JSON.stringify(data),
callback: function(err,putResponseDataJson,xhr) {
if(err) {
return callback(err);
}
var putResponseData = JSON.parse(putResponseDataJson);
callback(null);
}
});
}
});
return true;
};
/*
Information about this saver
*/
GitLabSaver.prototype.info = {
name: "gitlab",
priority: 2000,
capabilities: ["save", "autosave"]
};
/*
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
return true;
};
/*
Create an instance of this saver
*/
exports.create = function(wiki) {
return new GitLabSaver(wiki);
};
})();

View File

@@ -41,7 +41,7 @@ BasicAuthenticator.prototype.init = function() {
this.credentialsData = credentialsData;
}
} else {
return "Error: Unable to load user credentials from '" + credentialsFilepath + "'";
return "Error: Unable to load user credentials from '" + resolveCredentialsFilepath + "'";
}
}
// Add the hardcoded username and password if specified

View File

@@ -12,14 +12,38 @@ GET /
/*global $tw: false */
"use strict";
var zlib = require("zlib");
exports.method = "GET";
exports.path = /^\/$/;
exports.handler = function(request,response,state) {
response.writeHead(200, {"Content-Type": state.server.get("root-serve-type")});
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler"));
response.end(text,"utf8");
var acceptEncoding = request.headers["accept-encoding"];
if(!acceptEncoding) {
acceptEncoding = "";
}
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
responseHeaders = {
"Content-Type": state.server.get("root-serve-type")
};
/*
If the gzip=yes flag for `listen` is set, check if the user agent permits
compression. If so, compress our response. Note that we use the synchronous
functions from zlib to stay in the imperative style. The current `Server`
doesn't depend on this, and we may just as well use the async versions.
*/
if(state.server.enableGzip) {
if (/\bdeflate\b/.test(acceptEncoding)) {
responseHeaders["Content-Encoding"] = "deflate";
text = zlib.deflateSync(text);
} else if (/\bgzip\b/.test(acceptEncoding)) {
responseHeaders["Content-Encoding"] = "gzip";
text = zlib.gzipSync(text);
}
}
response.writeHead(200,responseHeaders);
response.end(text);
};
}());

View File

@@ -43,6 +43,8 @@ function Server(options) {
$tw.utils.extend({},this.defaultVariables,options.variables);
// Initialise CSRF
this.csrfDisable = this.get("csrf-disable") === "yes";
// Initialize Gzip compression
this.enableGzip = this.get("gzip") === "yes";
// Initialise authorization
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
this.authorizationPrincipals = {
@@ -84,7 +86,8 @@ Server.prototype.defaultVariables = {
"tiddler-render-template": "$:/core/templates/server/static.tiddler.html",
"system-tiddler-render-type": "text/plain",
"system-tiddler-render-template": "$:/core/templates/wikified-tiddler",
"debug-level": "none"
"debug-level": "none",
"gzip": "no"
};
Server.prototype.get = function(name) {
@@ -229,17 +232,19 @@ Server.prototype.requestHandler = function(request,response) {
/*
Listen for requests
port: optional port number (falls back to value of "port" variable)
host: optional host address (falls back to value of "hist" variable)
host: optional host address (falls back to value of "host" variable)
prefix: optional prefix (falls back to value of "path-prefix" variable)
*/
Server.prototype.listen = function(port,host) {
Server.prototype.listen = function(port,host,prefix) {
// Handle defaults for port and host
port = port || this.get("port");
host = host || this.get("host");
prefix = prefix || this.get("path-prefix") || "";
// Check for the port being a string and look it up as an environment variable
if(parseInt(port,10).toString() !== port) {
port = process.env[port] || 8080;
}
$tw.utils.log("Serving on " + this.protocol + "://" + host + ":" + port,"brown/orange");
$tw.utils.log("Serving on " + this.protocol + "://" + host + ":" + port + prefix,"brown/orange");
$tw.utils.log("(press ctrl-C to exit)","red");
// Warn if required plugins are missing
if(!$tw.wiki.getTiddler("$:/plugins/tiddlywiki/tiddlyweb") || !$tw.wiki.getTiddler("$:/plugins/tiddlywiki/filesystem")) {

View File

@@ -144,9 +144,9 @@ exports.startup = function() {
});
// Listen for window messages from other windows
window.addEventListener("message",function listener(event){
console.log("browser-messaging: ",document.location.toString())
console.log("browser-messaging: Received message from",event.origin);
console.log("browser-messaging: Message content",event.data);
// console.log("browser-messaging: ",document.location.toString())
// console.log("browser-messaging: Received message from",event.origin);
// console.log("browser-messaging: Message content",event.data);
switch(event.data.verb) {
case "GET-RESPONSE":
if(event.data.status.charAt(0) === "2") {

View File

@@ -0,0 +1,114 @@
/*\
title: $:/core/modules/startup/CSSescape.js
type: application/javascript
module-type: startup
Polyfill for CSS.escape()
\*/
(function(root,factory){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
// Export name and synchronous status
exports.name = "css-escape";
exports.platforms = ["browser"];
exports.after = ["startup"];
exports.synchronous = true;
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
// https://github.com/umdjs/umd/blob/master/returnExports.js
exports.startup = factory(root);
}(typeof global != 'undefined' ? global : this, function(root) {
if (root.CSS && root.CSS.escape) {
return;
}
// https://drafts.csswg.org/cssom/#serialize-an-identifier
var cssEscape = function(value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: theres no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}
if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
index == 0 &&
length == 1 &&
codeUnit == 0x002D
) {
result += '\\' + string.charAt(index);
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return result;
};
if (!root.CSS) {
root.CSS = {};
}
root.CSS.escape = cssEscape;
}));

View File

@@ -27,6 +27,7 @@ exports.startup = function() {
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
$tw.modules.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
$tw.modules.applyMethods("wikimethod",$tw.Wiki.prototype);
$tw.wiki.addIndexersToWiki();
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
$tw.wiki.initParsers();

View File

@@ -71,9 +71,10 @@ exports.startup = function() {
timerId;
function refresh() {
// Process the refresh
$tw.hooks.invokeHook("th-page-refreshing");
$tw.pageWidgetNode.refresh(deferredChanges);
deferredChanges = Object.create(null);
$tw.hooks.invokeHook("th-page-refreshed");
$tw.hooks.invokeHook("th-page-refreshed");
}
// Add the change event handler
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {

View File

@@ -34,6 +34,19 @@ exports.startup = function() {
$tw.rootWidget.addEventListener("tm-copy-to-clipboard",function(event) {
$tw.utils.copyToClipboard(event.param);
});
// Install the tm-focus-selector message
$tw.rootWidget.addEventListener("tm-focus-selector",function(event) {
var selector = event.param || "",
element;
try {
element = document.querySelector(selector);
} catch(e) {
console.log("Error in selector: ",selector)
}
if(element && element.focus) {
element.focus(event.paramObject);
}
});
// Install the scroller
$tw.pageScroller = new $tw.utils.PageScroller();
$tw.rootWidget.addEventListener("tm-scroll",function(event) {
@@ -42,15 +55,16 @@ exports.startup = function() {
var fullscreen = $tw.utils.getFullScreenApis();
if(fullscreen) {
$tw.rootWidget.addEventListener("tm-full-screen",function(event) {
var fullScreenDocument = event.event ? event.event.target.ownerDocument : document;
if(event.param === "enter") {
event.event.target.ownerDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
fullScreenDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
} else if(event.param === "exit") {
event.event.target.ownerDocument[fullscreen._exitFullscreen]();
fullScreenDocument[fullscreen._exitFullscreen]();
} else {
if(event.event.target.ownerDocument[fullscreen._fullscreenElement]) {
event.event.target.ownerDocument[fullscreen._exitFullscreen]();
if(fullScreenDocument[fullscreen._fullscreenElement]) {
fullScreenDocument[fullscreen._exitFullscreen]();
} else {
event.event.target.ownerDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
fullScreenDocument.documentElement[fullscreen._requestFullscreen](Element.ALLOW_KEYBOARD_INPUT);
}
}
});

View File

@@ -55,6 +55,27 @@ exports.startup = function() {
$tw.version = $tw.utils.extractVersionInfo();
// Set up the performance framework
$tw.perf = new $tw.Performance($tw.wiki.getTiddlerText(PERFORMANCE_INSTRUMENTATION_CONFIG_TITLE,"no") === "yes");
// Create a root widget for attaching event handlers. By using it as the parentWidget for another widget tree, one can reuse the event handlers
$tw.rootWidget = new widget.widget({
type: "widget",
children: []
},{
wiki: $tw.wiki,
document: $tw.browser ? document : $tw.fakeDocument
});
// Execute any startup actions
var executeStartupTiddlers = function(tag) {
$tw.utils.each($tw.wiki.filterTiddlers("[all[shadows+tiddlers]tag[" + tag + "]!has[draft.of]]"),function(title) {
$tw.rootWidget.invokeActionString($tw.wiki.getTiddlerText(title),$tw.rootWidget);
});
};
executeStartupTiddlers("$:/tags/StartupAction");
if($tw.browser) {
executeStartupTiddlers("$:/tags/StartupAction/Browser");
}
if($tw.node) {
executeStartupTiddlers("$:/tags/StartupAction/Node");
}
// Kick off the language manager and switcher
$tw.language = new $tw.Language();
$tw.languageSwitcher = new $tw.PluginSwitcher({
@@ -62,7 +83,7 @@ exports.startup = function() {
pluginType: "language",
controllerTitle: "$:/language",
defaultPlugins: [
"$:/languages/en-US"
"$:/languages/en-GB"
],
onSwitch: function(plugins) {
if($tw.browser) {
@@ -95,27 +116,6 @@ exports.startup = function() {
handlerMethod: "handleKeydownEvent"
}]);
}
// Create a root widget for attaching event handlers. By using it as the parentWidget for another widget tree, one can reuse the event handlers
$tw.rootWidget = new widget.widget({
type: "widget",
children: []
},{
wiki: $tw.wiki,
document: $tw.browser ? document : $tw.fakeDocument
});
// Execute any startup actions
var executeStartupTiddlers = function(tag) {
$tw.utils.each($tw.wiki.filterTiddlers("[all[shadows+tiddlers]tag[" + tag + "]!has[draft.of]]"),function(title) {
$tw.rootWidget.invokeActionString($tw.wiki.getTiddlerText(title),$tw.rootWidget);
});
};
executeStartupTiddlers("$:/tags/StartupAction");
if($tw.browser) {
executeStartupTiddlers("$:/tags/StartupAction/Browser");
}
if($tw.node) {
executeStartupTiddlers("$:/tags/StartupAction/Node");
}
// Clear outstanding tiddler store change events to avoid an unnecessary refresh cycle at startup
$tw.wiki.clearTiddlerEventQueue();
// Find a working syncadaptor
@@ -130,7 +130,11 @@ exports.startup = function() {
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki, syncadaptor: $tw.syncadaptor});
}
// Setup the saver handler
$tw.saverHandler = new $tw.SaverHandler({wiki: $tw.wiki, dirtyTracking: !$tw.syncadaptor});
$tw.saverHandler = new $tw.SaverHandler({
wiki: $tw.wiki,
dirtyTracking: !$tw.syncadaptor,
preloadDirty: $tw.boot.preloadDirty || []
});
// Host-specific startup
if($tw.browser) {
// Install the popup manager

View File

@@ -36,7 +36,9 @@ var HELP_OPEN_EXTERNAL_WINDOW = "http://tiddlywiki.com/#WidgetMessage%3A%20tm-op
exports.startup = function() {
// Open startup tiddlers
openStartupTiddlers();
openStartupTiddlers({
disableHistory: $tw.boot.disableStartupNavigation
});
if($tw.browser) {
// Set up location hash update
$tw.wiki.addEventListener("change",function(changes) {
@@ -106,6 +108,7 @@ exports.startup = function() {
/*
Process the location hash to open the specified tiddlers. Options:
disableHistory: if true $:/History is NOT updated
defaultToCurrentStory: If true, the current story is retained as the default, instead of opening the default tiddlers
*/
function openStartupTiddlers(options) {
@@ -146,15 +149,18 @@ function openStartupTiddlers(options) {
}
// Save the story list
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: storyList},$tw.wiki.getModificationFields());
// If a target tiddler was specified add it to the history stack
if(target && target !== "") {
// The target tiddler doesn't need double square brackets, but we'll silently remove them if they're present
if(target.indexOf("[[") === 0 && target.substr(-2) === "]]") {
target = target.substr(2,target.length - 4);
}
$tw.wiki.addToHistory(target);
} else if(storyList.length > 0) {
$tw.wiki.addToHistory(storyList[0]);
// Update history
if(!options.disableHistory) {
// If a target tiddler was specified add it to the history stack
if(target && target !== "") {
// The target tiddler doesn't need double square brackets, but we'll silently remove them if they're present
if(target.indexOf("[[") === 0 && target.substr(-2) === "]]") {
target = target.substr(2,target.length - 4);
}
$tw.wiki.addToHistory(target);
} else if(storyList.length > 0) {
$tw.wiki.addToHistory(storyList[0]);
}
}
}

View File

@@ -28,6 +28,7 @@ exports.startup = function() {
var refreshHandler,
title = event.param || event.tiddlerTitle,
paramObject = event.paramObject || {},
windowTitle = paramObject.windowTitle || title,
template = paramObject.template || "$:/core/templates/single.tiddler.window",
width = paramObject.width || "700",
height = paramObject.height || "600",
@@ -51,7 +52,7 @@ exports.startup = function() {
// Initialise the document
srcDocument.write("<html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
srcDocument.close();
srcDocument.title = title;
srcDocument.title = windowTitle;
srcWindow.addEventListener("beforeunload",function(event) {
delete windows[title];
$tw.wiki.removeEventListener("change",refreshHandler);

View File

@@ -19,6 +19,7 @@ var ClassicStoryView = function(listWidget) {
};
ClassicStoryView.prototype.navigateTo = function(historyInfo) {
var duration = $tw.utils.getAnimationDuration()
var listElementIndex = this.listWidget.findListItem(0,historyInfo.title);
if(listElementIndex === undefined) {
return;
@@ -29,80 +30,90 @@ ClassicStoryView.prototype.navigateTo = function(historyInfo) {
if(!(targetElement instanceof Element)) {
return;
}
// Scroll the node into view
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement});
if(duration) {
// Scroll the node into view
this.listWidget.dispatchEvent({type: "tm-scroll", target: targetElement});
} else {
targetElement.scrollIntoView();
}
};
ClassicStoryView.prototype.insert = function(widget) {
var targetElement = widget.findFirstDomNode(),
duration = $tw.utils.getAnimationDuration();
// Abandon if the list entry isn't a DOM element (it might be a text node)
if(!(targetElement instanceof Element)) {
return;
}
// Get the current height of the tiddler
var computedStyle = window.getComputedStyle(targetElement),
currMarginBottom = parseInt(computedStyle.marginBottom,10),
currMarginTop = parseInt(computedStyle.marginTop,10),
currHeight = targetElement.offsetHeight + currMarginTop;
// Reset the margin once the transition is over
setTimeout(function() {
var duration = $tw.utils.getAnimationDuration();
if(duration) {
var targetElement = widget.findFirstDomNode();
// Abandon if the list entry isn't a DOM element (it might be a text node)
if(!(targetElement instanceof Element)) {
return;
}
// Get the current height of the tiddler
var computedStyle = window.getComputedStyle(targetElement),
currMarginBottom = parseInt(computedStyle.marginBottom,10),
currMarginTop = parseInt(computedStyle.marginTop,10),
currHeight = targetElement.offsetHeight + currMarginTop;
// Reset the margin once the transition is over
setTimeout(function() {
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: ""}
]);
},duration);
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: ""}
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
},duration);
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
$tw.utils.forceLayout(targetElement);
// Transition to the final position
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + duration + "ms " + easing + ", " +
"margin-bottom " + duration + "ms " + easing},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
$tw.utils.forceLayout(targetElement);
// Transition to the final position
$tw.utils.setStyle(targetElement,[
{transition: "opacity " + duration + "ms " + easing + ", " +
"margin-bottom " + duration + "ms " + easing},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
]);
}
};
ClassicStoryView.prototype.remove = function(widget) {
var targetElement = widget.findFirstDomNode(),
duration = $tw.utils.getAnimationDuration(),
removeElement = function() {
widget.removeChildDomNodes();
};
// Abandon if the list entry isn't a DOM element (it might be a text node)
if(!(targetElement instanceof Element)) {
removeElement();
return;
var duration = $tw.utils.getAnimationDuration();
if(duration) {
var targetElement = widget.findFirstDomNode(),
removeElement = function() {
widget.removeChildDomNodes();
};
// Abandon if the list entry isn't a DOM element (it might be a text node)
if(!(targetElement instanceof Element)) {
removeElement();
return;
}
// Get the current height of the tiddler
var currWidth = targetElement.offsetWidth,
computedStyle = window.getComputedStyle(targetElement),
currMarginBottom = parseInt(computedStyle.marginBottom,10),
currMarginTop = parseInt(computedStyle.marginTop,10),
currHeight = targetElement.offsetHeight + currMarginTop;
// Remove the dom nodes of the widget at the end of the transition
setTimeout(removeElement,duration);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "translateX(0px)"},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
"opacity " + duration + "ms " + easing + ", " +
"margin-bottom " + duration + "ms " + easing},
{transform: "translateX(-" + currWidth + "px)"},
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
} else {
widget.removeChildDomNodes();
}
// Get the current height of the tiddler
var currWidth = targetElement.offsetWidth,
computedStyle = window.getComputedStyle(targetElement),
currMarginBottom = parseInt(computedStyle.marginBottom,10),
currMarginTop = parseInt(computedStyle.marginTop,10),
currHeight = targetElement.offsetHeight + currMarginTop;
// Remove the dom nodes of the widget at the end of the transition
setTimeout(removeElement,duration);
// Animate the closure
$tw.utils.setStyle(targetElement,[
{transition: "none"},
{transform: "translateX(0px)"},
{marginBottom: currMarginBottom + "px"},
{opacity: "1.0"}
]);
$tw.utils.forceLayout(targetElement);
$tw.utils.setStyle(targetElement,[
{transition: $tw.utils.roundTripPropertyName("transform") + " " + duration + "ms " + easing + ", " +
"opacity " + duration + "ms " + easing + ", " +
"margin-bottom " + duration + "ms " + easing},
{transform: "translateX(-" + currWidth + "px)"},
{marginBottom: (-currHeight) + "px"},
{opacity: "0.0"}
]);
};
exports.classic = ClassicStoryView;

View File

@@ -44,7 +44,14 @@ PopStoryView.prototype.insert = function(widget) {
{transition: "none"},
{transform: "none"}
]);
$tw.utils.setStyle(widget.document.body,[
{"overflow-x": ""}
]);
},duration);
// Prevent the page from overscrolling due to the zoom factor
$tw.utils.setStyle(widget.document.body,[
{"overflow-x": "hidden"}
]);
// Set up the initial position of the element
$tw.utils.setStyle(targetElement,[
{transition: "none"},
@@ -65,7 +72,7 @@ PopStoryView.prototype.remove = function(widget) {
var targetElement = widget.findFirstDomNode(),
duration = $tw.utils.getAnimationDuration(),
removeElement = function() {
if(targetElement.parentNode) {
if(targetElement && targetElement.parentNode) {
widget.removeChildDomNodes();
}
};

View File

@@ -75,67 +75,16 @@ Get all the fields as a name:value block. Options:
*/
exports.getFieldStringBlock = function(options) {
options = options || {};
var exclude = options.exclude || [];
var fields = [];
for(var field in this.fields) {
if($tw.utils.hop(this.fields,field)) {
if(exclude.indexOf(field) === -1) {
fields.push(field + ": " + this.getFieldString(field));
}
var exclude = options.exclude || [],
fields = Object.keys(this.fields).sort(),
result = [];
for(var t=0; t<fields.length; t++) {
var field = fields[t];
if(exclude.indexOf(field) === -1) {
result.push(field + ": " + this.getFieldString(field));
}
}
return fields.join("\n");
};
/*
Compare two tiddlers for equality
tiddler: the tiddler to compare
excludeFields: array of field names to exclude from the comparison
*/
exports.isEqual = function(tiddler,excludeFields) {
if(!(tiddler instanceof $tw.Tiddler)) {
return false;
}
excludeFields = excludeFields || [];
var self = this,
differences = []; // Fields that have differences
// Add to the differences array
function addDifference(fieldName) {
// Check for this field being excluded
if(excludeFields.indexOf(fieldName) === -1) {
// Save the field as a difference
$tw.utils.pushTop(differences,fieldName);
}
}
// Returns true if the two values of this field are equal
function isFieldValueEqual(fieldName) {
var valueA = self.fields[fieldName],
valueB = tiddler.fields[fieldName];
// Check for identical string values
if(typeof(valueA) === "string" && typeof(valueB) === "string" && valueA === valueB) {
return true;
}
// Check for identical array values
if($tw.utils.isArray(valueA) && $tw.utils.isArray(valueB) && $tw.utils.isArrayEqual(valueA,valueB)) {
return true;
}
// Otherwise the fields must be different
return false;
}
// Compare our fields
for(var fieldName in this.fields) {
if(!isFieldValueEqual(fieldName)) {
addDifference(fieldName);
}
}
// There's a difference for every field in the other tiddler that we don't have
for(fieldName in tiddler.fields) {
if(!(fieldName in this.fields)) {
addDifference(fieldName);
}
}
// Return whether there were any differences
return differences.length === 0;
return result.join("\n");
};
exports.getFieldDay = function(field) {

View File

@@ -13,11 +13,13 @@ Upgrader module that suppresses certain system tiddlers that shouldn't be import
"use strict";
var DONT_IMPORT_LIST = ["$:/StoryList","$:/HistoryList"],
DONT_IMPORT_PREFIX_LIST = ["$:/temp/","$:/state/"];
DONT_IMPORT_PREFIX_LIST = ["$:/temp/","$:/state/","$:/Import"],
WARN_IMPORT_PREFIX_LIST = ["$:/core/modules/"];
exports.upgrade = function(wiki,titles,tiddlers) {
var self = this,
messages = {};
messages = {},
showAlert = false;
// Check for tiddlers on our list
$tw.utils.each(titles,function(title) {
if(DONT_IMPORT_LIST.indexOf(title) !== -1) {
@@ -31,8 +33,19 @@ exports.upgrade = function(wiki,titles,tiddlers) {
messages[title] = $tw.language.getString("Import/Upgrader/State/Suppressed");
}
}
for(var t=0; t<WARN_IMPORT_PREFIX_LIST.length; t++) {
var prefix = WARN_IMPORT_PREFIX_LIST[t];
if(title.substr(0,prefix.length) === prefix && wiki.isShadowTiddler(title)) {
showAlert = true;
messages[title] = $tw.language.getString("Import/Upgrader/System/Warning");
}
}
}
});
if(showAlert) {
var logger = new $tw.utils.Logger("import");
logger.alert($tw.language.getString("Import/Upgrader/System/Alert"));
}
return messages;
};

View File

@@ -0,0 +1,124 @@
// From https://gist.github.com/Nijikokun/5192472
//
// UTF8 Module
//
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
//
// copyright: MIT
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
(function (name, definition, context, dependencies) {
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
else { context[name] = definition.apply(context); }
})('utf8', function () {
return {
encode: function (string) {
if (typeof string !== 'string') return string;
else string = string.replace(/\r\n/g, "\n");
var output = "", i = 0, charCode;
for (i; i < string.length; i++) {
charCode = string.charCodeAt(i);
if (charCode < 128)
output += String.fromCharCode(charCode);
else if ((charCode > 127) && (charCode < 2048))
output += String.fromCharCode((charCode >> 6) | 192),
output += String.fromCharCode((charCode & 63) | 128);
else
output += String.fromCharCode((charCode >> 12) | 224),
output += String.fromCharCode(((charCode >> 6) & 63) | 128),
output += String.fromCharCode((charCode & 63) | 128);
}
return output;
},
decode: function (string) {
if (typeof string !== 'string') return string;
var output = "", i = 0, charCode = 0;
while (i < string.length) {
charCode = string.charCodeAt(i);
if (charCode < 128)
output += String.fromCharCode(charCode),
i++;
else if ((charCode > 191) && (charCode < 224))
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63)),
i += 2;
else
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63)),
i += 3;
}
return output;
}
};
}, this);
// Base64 Module
//
// Cleaner, modularized and properly scoped base64 encoding and decoding module for strings.
//
// copyright: MIT
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
(function (name, definition, context, dependencies) {
if (typeof context['module'] !== 'undefined' && context['module']['exports']) { if (dependencies && context['require']) { for (var i = 0; i < dependencies.length; i++) context[dependencies[i]] = context['require'](dependencies[i]); } context['module']['exports'] = definition.apply(context); }
else if (typeof context['define'] !== 'undefined' && context['define'] === 'function' && context['define']['amd']) { define(name, (dependencies || []), definition); }
else { context[name] = definition.apply(context); }
})('base64', function (utf8) {
var $this = this;
var $utf8 = utf8 || this.utf8;
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function (input) {
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
if (typeof input !== 'string') return input;
else input = $utf8.encode(input);
var output = "", a, b, c, d, e, f, g, i = 0;
while (i < input.length) {
a = input.charCodeAt(i++);
b = input.charCodeAt(i++);
c = input.charCodeAt(i++);
d = a >> 2;
e = ((a & 3) << 4) | (b >> 4);
f = ((b & 15) << 2) | (c >> 6);
g = c & 63;
if (isNaN(b)) f = g = 64;
else if (isNaN(c)) g = 64;
output += map.charAt(d) + map.charAt(e) + map.charAt(f) + map.charAt(g);
}
return output;
},
decode: function (input) {
if (typeof $utf8 === 'undefined') throw { error: "MissingMethod", message: "UTF8 Module is missing." };
if (typeof input !== 'string') return input;
else input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
var output = "", a, b, c, d, e, f, g, i = 0;
while (i < input.length) {
d = map.indexOf(input.charAt(i++));
e = map.indexOf(input.charAt(i++));
f = map.indexOf(input.charAt(i++));
g = map.indexOf(input.charAt(i++));
a = (d << 2) | (e >> 4);
b = ((e & 15) << 4) | (f >> 2);
c = ((f & 3) << 6) | g;
output += String.fromCharCode(a);
if (f != 64) output += String.fromCharCode(b);
if (g != 64) output += String.fromCharCode(c);
}
return $utf8.decode(output);
}
}
}, this, [ "utf8" ]);

View File

@@ -0,0 +1,9 @@
// From https://gist.github.com/Nijikokun/5192472
//
// UTF8 Module
//
// Cleaner and modularized utf-8 encoding and decoding library for javascript.
//
// copyright: MIT
// author: Nijiko Yonskai, @nijikokun, nijikokun@gmail.com
!function(r,e,o,t){void 0!==o.module&&o.module.exports?o.module.exports=e.apply(o):void 0!==o.define&&"function"===o.define&&o.define.amd?define("utf8",[],e):o.utf8=e.apply(o)}(0,function(){return{encode:function(r){if("string"!=typeof r)return r;r=r.replace(/\r\n/g,"\n");for(var e,o="",t=0;t<r.length;t++)(e=r.charCodeAt(t))<128?o+=String.fromCharCode(e):e>127&&e<2048?(o+=String.fromCharCode(e>>6|192),o+=String.fromCharCode(63&e|128)):(o+=String.fromCharCode(e>>12|224),o+=String.fromCharCode(e>>6&63|128),o+=String.fromCharCode(63&e|128));return o},decode:function(r){if("string"!=typeof r)return r;for(var e="",o=0,t=0;o<r.length;)(t=r.charCodeAt(o))<128?(e+=String.fromCharCode(t),o++):t>191&&t<224?(e+=String.fromCharCode((31&t)<<6|63&r.charCodeAt(o+1)),o+=2):(e+=String.fromCharCode((15&t)<<12|(63&r.charCodeAt(o+1))<<6|63&r.charCodeAt(o+2)),o+=3);return e}}},this),function(r,e,o,t){if(void 0!==o.module&&o.module.exports){if(t&&o.require)for(var n=0;n<t.length;n++)o[t[n]]=o.require(t[n]);o.module.exports=e.apply(o)}else void 0!==o.define&&"function"===o.define&&o.define.amd?define("base64",t||[],e):o.base64=e.apply(o)}(0,function(r){var e=r||this.utf8,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=e.encode(r);for(var t,n,i,d,f,a,h,c="",u=0;u<r.length;)d=(t=r.charCodeAt(u++))>>2,f=(3&t)<<4|(n=r.charCodeAt(u++))>>4,a=(15&n)<<2|(i=r.charCodeAt(u++))>>6,h=63&i,isNaN(n)?a=h=64:isNaN(i)&&(h=64),c+=o.charAt(d)+o.charAt(f)+o.charAt(a)+o.charAt(h);return c},decode:function(r){if(void 0===e)throw{error:"MissingMethod",message:"UTF8 Module is missing."};if("string"!=typeof r)return r;r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");for(var t,n,i,d,f,a,h="",c=0;c<r.length;)t=o.indexOf(r.charAt(c++))<<2|(d=o.indexOf(r.charAt(c++)))>>4,n=(15&d)<<4|(f=o.indexOf(r.charAt(c++)))>>2,i=(3&f)<<6|(a=o.indexOf(r.charAt(c++))),h+=String.fromCharCode(t),64!=f&&(h+=String.fromCharCode(n)),64!=a&&(h+=String.fromCharCode(i));return e.decode(h)}}},this,["utf8"]);

View File

@@ -0,0 +1,14 @@
{
"tiddlers": [
{
"file": "base64-utf8.module.min.js",
"fields": {
"type": "application/javascript",
"title": "$:/core/modules/utils/base64-utf8/base64-utf8.module.js",
"module-type": "library"
},
"prefix": "(function(){",
"suffix": "}).call(exports);"
}
]
}

View File

@@ -136,22 +136,31 @@ exports.getBoundingPageRect = function(element) {
Saves a named password in the browser
*/
exports.savePassword = function(name,password) {
var done = false;
try {
if(window.localStorage) {
localStorage.setItem("tw5-password-" + name,password);
}
window.localStorage.setItem("tw5-password-" + name,password);
done = true;
} catch(e) {
}
if(!done) {
$tw.savedPasswords = $tw.savedPasswords || Object.create(null);
$tw.savedPasswords[name] = password;
}
};
/*
Retrieve a named password from the browser
*/
exports.getPassword = function(name) {
var value;
try {
return window.localStorage ? localStorage.getItem("tw5-password-" + name) : "";
value = window.localStorage.getItem("tw5-password-" + name);
} catch(e) {
return "";
}
if(value !== undefined) {
return value;
} else {
return ($tw.savedPasswords || Object.create(null))[name] || "";
}
};

View File

@@ -17,7 +17,7 @@ A quick and dirty HTTP function; to be refactored later. Options are:
url: URL to retrieve
headers: hashmap of headers to send
type: GET, PUT, POST etc
callback: function invoked with (err,data)
callback: function invoked with (err,data,xhr)
returnProp: string name of the property to return as first argument of callback
*/
exports.httpRequest = function(options) {
@@ -48,7 +48,7 @@ exports.httpRequest = function(options) {
return;
}
// Something went wrong
options.callback($tw.language.getString("Error/XMLHttpRequest") + ": " + this.status);
options.callback($tw.language.getString("Error/XMLHttpRequest") + ": " + this.status,null,this);
}
};
// Make the request
@@ -67,7 +67,7 @@ exports.httpRequest = function(options) {
try {
request.send(data);
} catch(e) {
options.callback(e);
options.callback(e,null,this);
}
return request;
};

View File

@@ -30,7 +30,7 @@ Modal.prototype.display = function(title,options) {
options = options || {};
this.srcDocument = options.variables && (options.variables.rootwindow === "true" ||
options.variables.rootwindow === "yes") ? document :
(options.event.event ? options.event.event.target.ownerDocument : document);
(options.event.event && options.event.event.target ? options.event.event.target.ownerDocument : document);
this.srcWindow = this.srcDocument.defaultView;
var self = this,
refreshHandler,

View File

@@ -120,7 +120,8 @@ Popup.prototype.show = function(options) {
this.popups.push({
title: options.title,
wiki: options.wiki,
domNode: options.domNode
domNode: options.domNode,
noStateReference: options.noStateReference
});
}
// Set the state tiddler
@@ -148,17 +149,46 @@ Popup.prototype.show = function(options) {
}
};
/*
Detect if a Popup contains an input field that has focus
Returns true or false
*/
Popup.prototype.detectInputWithinPopup = function(node) {
var withinPopup = false,
currNode = node;
for(var i=0; i<this.popups.length; i++) {
var popup = (this.popups[i] && this.popups[i].domNode) ? this.popups[i].domNode : null;
while(node && popup) {
if(node === popup || (node.classList && (node.classList.contains("tc-popup-keep") || (node !== currNode && node.classList.contains("tc-popup-handle"))))) {
withinPopup = true;
}
node = node.parentNode;
}
}
return withinPopup;
};
/*
Cancel all popups at or above a specified level or DOM node
level: popup level to cancel (0 cancels all popups)
*/
Popup.prototype.cancel = function(level) {
Popup.prototype.cancel = function(level,focusedInputNode) {
var numPopups = this.popups.length;
level = Math.max(0,Math.min(level,numPopups));
for(var t=level; t<numPopups; t++) {
var popup = this.popups.pop();
if(popup.title) {
popup.wiki.deleteTiddler(popup.title);
var inputWithinPopup;
if(focusedInputNode) {
inputWithinPopup = this.detectInputWithinPopup(focusedInputNode);
}
if(!inputWithinPopup) {
var popup = this.popups.pop();
if(popup.title) {
if(popup.noStateReference) {
popup.wiki.deleteTiddler(popup.title);
} else {
popup.wiki.deleteTiddler($tw.utils.parseTextReference(popup.title).title);
}
}
}
}
if(this.popups.length === 0) {

View File

@@ -33,6 +33,10 @@ var PageScroller = function() {
};
};
PageScroller.prototype.isScrolling = function() {
return this.idRequestFrame !== null;
}
PageScroller.prototype.cancelScroll = function(srcWindow) {
if(this.idRequestFrame) {
this.cancelAnimationFrame.call(srcWindow,this.idRequestFrame);

View File

@@ -45,10 +45,28 @@ var TW_Element = function(tag,namespace) {
this.attributes = {};
this.isRaw = false;
this.children = [];
this.style = {};
this._style = {};
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
};
Object.defineProperty(TW_Element.prototype, "style", {
get: function() {
return this._style;
},
set: function(str) {
var self = this;
str = str || "";
$tw.utils.each(str.split(";"),function(declaration) {
var parts = declaration.split(":"),
name = $tw.utils.trim(parts[0]),
value = $tw.utils.trim(parts[1]);
if(name && value) {
self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value;
}
});
}
});
Object.defineProperty(TW_Element.prototype, "nodeType", {
get: function() {
return 1;
@@ -169,13 +187,13 @@ Object.defineProperty(TW_Element.prototype, "outerHTML", {
}
}
}
if(this.style) {
if(this._style) {
var style = [];
for(var s in this.style) {
style.push(s + ":" + this.style[s] + ";");
for(var s in this._style) {
style.push($tw.utils.convertPropertyNameToStyleName(s) + ":" + this._style[s] + ";");
}
if(style.length > 0) {
output.push(" style=\"",style.join(""),"\"")
output.push(" style=\"",style.join(""),"\"");
}
}
output.push(">");

View File

@@ -181,4 +181,169 @@ exports.deleteEmptyDirs = function(dirpath,callback) {
});
};
/*
Create a fileInfo object for saving a tiddler:
filepath: the absolute path to the file containing the tiddler
type: the type of the tiddler file (NOT the type of the tiddler)
hasMetaFile: true if the file also has a companion .meta file
Options include:
directory: absolute path of root directory to which we are saving
pathFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters
*/
exports.generateTiddlerFileInfo = function(tiddler,options) {
var fileInfo = {};
// Check if the tiddler has any unsafe fields that can't be expressed in a .tid or .meta file: containing control characters, or leading/trailing whitespace
var hasUnsafeFields = false;
$tw.utils.each(tiddler.getFieldStrings(),function(value,fieldName) {
if(fieldName !== "text") {
hasUnsafeFields = hasUnsafeFields || /[\x00-\x1F]/mg.test(value);
hasUnsafeFields = hasUnsafeFields || ($tw.utils.trim(value) !== value);
}
});
// Check for field values
if(hasUnsafeFields) {
// Save as a JSON file
fileInfo.type = "application/json";
fileInfo.hasMetaFile = false;
} else {
// Save as a .tid or a text/binary file plus a .meta file
var tiddlerType = tiddler.fields.type || "text/vnd.tiddlywiki";
if(tiddlerType === "text/vnd.tiddlywiki") {
// Save as a .tid file
fileInfo.type = "application/x-tiddler";
fileInfo.hasMetaFile = false;
} else {
// Save as a text/binary file and a .meta file
fileInfo.type = tiddlerType;
fileInfo.hasMetaFile = true;
}
}
// Take the file extension from the tiddler content type
var contentTypeInfo = $tw.config.contentTypeInfo[fileInfo.type] || {extension: ""};
// Generate the filepath
fileInfo.filepath = $tw.utils.generateTiddlerFilepath(tiddler.fields.title,{
extension: contentTypeInfo.extension,
directory: options.directory,
pathFilters: options.pathFilters,
wiki: options.wiki
});
return fileInfo;
};
/*
Generate the filepath for saving a tiddler
Options include:
extension: file extension to be added the finished filepath
directory: absolute path of root directory to which we are saving
pathFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters
*/
exports.generateTiddlerFilepath = function(title,options) {
var self = this,
directory = options.directory || "",
extension = options.extension || "",
filepath;
// Check if any of the pathFilters applies
if(options.pathFilters && options.wiki) {
$tw.utils.each(options.pathFilters,function(filter) {
if(!filepath) {
var source = options.wiki.makeTiddlerIterator([title]),
result = options.wiki.filterTiddlers(filter,null,source);
if(result.length > 0) {
filepath = result[0];
}
}
});
}
// If not, generate a base pathname
if(!filepath) {
filepath = title;
// If the filepath already ends in the extension then remove it
if(filepath.substring(filepath.length - extension.length) === extension) {
filepath = filepath.substring(0,filepath.length - extension.length);
}
// Remove any forward or backward slashes so we don't create directories
filepath = filepath.replace(/\/|\\/g,"_");
}
// Don't let the filename start with a dot because such files are invisible on *nix
filepath = filepath.replace(/^\./g,"_");
// Remove any characters that can't be used in cross-platform filenames
filepath = $tw.utils.transliterate(filepath.replace(/<|>|\:|\"|\||\?|\*|\^/g,"_"));
// Truncate the filename if it is too long
if(filepath.length > 200) {
filepath = filepath.substr(0,200);
}
// If the resulting filename is blank (eg because the title is just punctuation characters)
if(!filepath) {
// ...then just use the character codes of the title
filepath = "";
$tw.utils.each(title.split(""),function(char) {
if(filepath) {
filepath += "-";
}
filepath += char.charCodeAt(0).toString();
});
}
// Add a uniquifier if the file already exists
var fullPath,
count = 0;
do {
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
count++;
} while(fs.existsSync(fullPath));
// Return the full path to the file
return fullPath;
};
/*
Save a tiddler to a file described by the fileInfo:
filepath: the absolute path to the file containing the tiddler
type: the type of the tiddler file (NOT the type of the tiddler)
hasMetaFile: true if the file also has a companion .meta file
*/
exports.saveTiddlerToFile = function(tiddler,fileInfo,callback) {
$tw.utils.createDirectory(path.dirname(fileInfo.filepath));
if(fileInfo.hasMetaFile) {
// Save the tiddler as a separate body and meta file
var typeInfo = $tw.config.contentTypeInfo[tiddler.fields.type || "text/plain"] || {encoding: "utf8"};
fs.writeFile(fileInfo.filepath,tiddler.fields.text,typeInfo.encoding,function(err) {
if(err) {
return callback(err);
}
fs.writeFile(fileInfo.filepath + ".meta",tiddler.getFieldStringBlock({exclude: ["text","bag"]}),"utf8",callback);
});
} else {
// Save the tiddler as a self contained templated file
if(fileInfo.type === "application/x-tiddler") {
fs.writeFile(fileInfo.filepath,tiddler.getFieldStringBlock({exclude: ["text","bag"]}) + (!!tiddler.fields.text ? "\n\n" + tiddler.fields.text : ""),"utf8",callback);
} else {
fs.writeFile(fileInfo.filepath,JSON.stringify([tiddler.getFieldStrings({exclude: ["bag"]})],null,$tw.config.preferences.jsonSpaces),"utf8",callback);
}
}
};
/*
Save a tiddler to a file described by the fileInfo:
filepath: the absolute path to the file containing the tiddler
type: the type of the tiddler file (NOT the type of the tiddler)
hasMetaFile: true if the file also has a companion .meta file
*/
exports.saveTiddlerToFileSync = function(tiddler,fileInfo) {
$tw.utils.createDirectory(path.dirname(fileInfo.filepath));
if(fileInfo.hasMetaFile) {
// Save the tiddler as a separate body and meta file
var typeInfo = $tw.config.contentTypeInfo[tiddler.fields.type || "text/plain"] || {encoding: "utf8"};
fs.writeFileSync(fileInfo.filepath,tiddler.fields.text,typeInfo.encoding);
fs.writeFileSync(fileInfo.filepath + ".meta",tiddler.getFieldStringBlock({exclude: ["text","bag"]}),"utf8");
} else {
// Save the tiddler as a self contained templated file
if(fileInfo.type === "application/x-tiddler") {
fs.writeFileSync(fileInfo.filepath,tiddler.getFieldStringBlock({exclude: ["text","bag"]}) + (!!tiddler.fields.text ? "\n\n" + tiddler.fields.text : ""),"utf8");
} else {
fs.writeFileSync(fileInfo.filepath,JSON.stringify([tiddler.getFieldStrings({exclude: ["bag"]})],null,$tw.config.preferences.jsonSpaces),"utf8");
}
}
};
})();

View File

@@ -33,6 +33,13 @@ Logger.prototype.log = function(/* args */) {
}
};
/*
Log a structure as a table
*/
Logger.prototype.table = function(value) {
(console.table || console.log)(value);
};
/*
Alert a message
*/

View File

@@ -14,10 +14,17 @@ Performance measurement.
function Performance(enabled) {
this.enabled = !!enabled;
this.measures = {}; // Hashmap of current values of measurements
this.measures = {}; // Hashmap by measurement name of {time:, invocations:}
this.logger = new $tw.utils.Logger("performance");
this.showGreeting();
}
Performance.prototype.showGreeting = function() {
if($tw.browser) {
this.logger.log("Execute $tw.perf.log(); to see filter execution timings");
}
};
/*
Wrap performance reporting around a top level function
*/
@@ -25,13 +32,9 @@ 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).toFixed(2) + "ms");
for(var m in self.measures) {
self.logger.log("+" + m + ": " + self.measures[m].toFixed(2) + "ms");
}
return result;
};
} else {
@@ -39,6 +42,29 @@ Performance.prototype.report = function(name,fn) {
}
};
Performance.prototype.log = function() {
var self = this,
totalTime = 0,
orderedMeasures = Object.keys(this.measures).sort(function(a,b) {
if(self.measures[a].time > self.measures[b].time) {
return -1;
} else if (self.measures[a].time < self.measures[b].time) {
return + 1;
} else {
return 0;
}
});
$tw.utils.each(orderedMeasures,function(name) {
totalTime += self.measures[name].time;
});
var results = []
$tw.utils.each(orderedMeasures,function(name) {
var measure = self.measures[name];
results.push({name: name,invocations: measure.invocations, avgTime: measure.time / measure.invocations, totalTime: measure.time, percentTime: (measure.time / totalTime) * 100})
});
self.logger.table(results);
};
/*
Wrap performance measurements around a subfunction
*/
@@ -47,9 +73,12 @@ Performance.prototype.measure = function(name,fn) {
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);
result = fn.apply(this,arguments);
if(!(name in self.measures)) {
self.measures[name] = {time: 0, invocations: 0};
}
self.measures[name].time += $tw.utils.timer(startTime);
self.measures[name].invocations++;
return result;
};
} else {

View File

@@ -12,6 +12,8 @@ Various static utility functions.
/*global $tw: false */
"use strict";
var base64utf8 = require("$:/core/modules/utils/base64-utf8/base64-utf8.module.js");
/*
Display a message, in colour if we're on a terminal
*/
@@ -92,6 +94,20 @@ exports.trim = function(str) {
}
};
/*
Convert a string to sentence case (ie capitalise first letter)
*/
exports.toSentenceCase = function(str) {
return (str || "").replace(/^\S/, function(c) {return c.toUpperCase();});
}
/*
Convert a string to title case (ie capitalise each initial letter)
*/
exports.toTitleCase = function(str) {
return (str || "").replace(/(^|\s)\S/g, function(c) {return c.toUpperCase();});
}
/*
Find the line break preceding a given position in a string
Returns position immediately after that line break, or the start of the string
@@ -132,23 +148,6 @@ exports.count = function(object) {
return Object.keys(object || {}).length;
};
/*
Check if an array is equal by value and by reference.
*/
exports.isArrayEqual = function(array1,array2) {
if(array1 === array2) {
return true;
}
array1 = array1 || [];
array2 = array2 || [];
if(array1.length !== array2.length) {
return false;
}
return array1.every(function(value,index) {
return value === array2[index];
});
};
/*
Determine whether an array-item is an object-property
*/
@@ -161,46 +160,6 @@ exports.hopArray = function(object,array) {
return false;
};
/*
Push entries onto an array, removing them first if they already exist in the array
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
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);
}
} else {
p = array.indexOf(value);
if(p !== -1) {
array.splice(p,1);
}
array.push(value);
}
return array;
};
/*
Remove entries from an array
array: array to modify
@@ -708,7 +667,7 @@ exports.extractVersionInfo = function() {
Get the animation duration in ms
*/
exports.getAnimationDuration = function() {
return parseInt($tw.wiki.getTiddlerText("$:/config/AnimationDuration","400"),10);
return parseInt($tw.wiki.getTiddlerText("$:/config/AnimationDuration","400"),10) || 0;
};
/*
@@ -726,12 +685,14 @@ exports.hashString = function(str) {
Decode a base64 string
*/
exports.base64Decode = function(string64) {
if($tw.browser) {
// TODO
throw "$tw.utils.base64Decode() doesn't work in the browser";
} else {
return Buffer.from(string64,"base64").toString();
}
return base64utf8.base64.decode.call(base64utf8,string64);
};
/*
Encode a string to base64
*/
exports.base64Encode = function(string64) {
return base64utf8.base64.encode.call(base64utf8,string64);
};
/*

View File

@@ -37,6 +37,7 @@ Compute the internal state of the widget
CreateTiddlerWidget.prototype.execute = function() {
this.actionBaseTitle = this.getAttribute("$basetitle");
this.actionSaveTitle = this.getAttribute("$savetitle");
this.actionSaveDraftTitle = this.getAttribute("$savedrafttitle");
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
};
@@ -73,6 +74,9 @@ CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
if(this.actionSaveTitle) {
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
}
if(this.actionSaveDraftTitle) {
this.wiki.setTextReference(this.actionSaveDraftTitle,this.wiki.generateDraftTitle(title),this.getVariable("currentTiddler"));
}
return true; // Action was invoked
};

View File

@@ -59,7 +59,7 @@ DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
tiddler = this.wiki.getTiddler(self.actionTiddler),
removeFields = {},
hasChanged = false;
if(this.actionField) {
if(this.actionField && tiddler) {
removeFields[this.actionField] = undefined;
if(this.actionField in tiddler.fields) {
hasChanged = true;

View File

@@ -156,6 +156,9 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
if(this.checkboxActions) {
this.invokeActionString(this.checkboxActions,this,event);
}
if(this.checkboxCheckActions && checked) {
this.invokeActionString(this.checkboxCheckActions,this,event);
}
if(this.checkboxUncheckActions && !checked) {
this.invokeActionString(this.checkboxUncheckActions,this,event);
}
@@ -167,6 +170,7 @@ Compute the internal state of the widget
CheckboxWidget.prototype.execute = function() {
// Get the parameters from the attributes
this.checkboxActions = this.getAttribute("actions");
this.checkboxCheckActions = this.getAttribute("checkactions");
this.checkboxUncheckActions = this.getAttribute("uncheckactions");
this.checkboxTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.checkboxTag = this.getAttribute("tag");

View File

@@ -42,7 +42,8 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
{name: "dragover", handlerObject: this, handlerMethod: "handleDragOverEvent"},
{name: "dragleave", handlerObject: this, handlerMethod: "handleDragLeaveEvent"},
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"},
{name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"}
{name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"},
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
]);
domNode.addEventListener("click",function (event) {
},false);
@@ -103,6 +104,10 @@ DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
this.leaveDrag(event);
};
DropZoneWidget.prototype.handleDragEndEvent = function(event) {
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
};
DropZoneWidget.prototype.handleDropEvent = function(event) {
var self = this,
readFileCallback = function(tiddlerFieldsArray) {

View File

@@ -14,7 +14,8 @@ Edit-bitmap widget
// Default image sizes
var DEFAULT_IMAGE_WIDTH = 600,
DEFAULT_IMAGE_HEIGHT = 370;
DEFAULT_IMAGE_HEIGHT = 370,
DEFAULT_IMAGE_TYPE = "image/png";
// Configuration tiddlers
var LINE_WIDTH_TITLE = "$:/config/BitmapEditor/LineWidth",
@@ -154,7 +155,13 @@ EditBitmapWidget.prototype.loadCanvas = function() {
self.refreshToolbar();
};
// Get the current bitmap into an image object
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
if(tiddler && tiddler.fields.type && tiddler.fields.text) {
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
} else {
currImage.width = DEFAULT_IMAGE_WIDTH;
currImage.height = DEFAULT_IMAGE_HEIGHT;
currImage.onerror();
}
};
EditBitmapWidget.prototype.initCanvas = function(canvas,width,height,image) {
@@ -319,18 +326,16 @@ EditBitmapWidget.prototype.strokeEnd = function() {
};
EditBitmapWidget.prototype.saveChanges = function() {
var tiddler = this.wiki.getTiddler(this.editTitle);
if(tiddler) {
// data URIs look like "data:<type>;base64,<text>"
var dataURL = this.canvasDomNode.toDataURL(tiddler.fields.type),
posColon = dataURL.indexOf(":"),
posSemiColon = dataURL.indexOf(";"),
posComma = dataURL.indexOf(","),
type = dataURL.substring(posColon+1,posSemiColon),
text = dataURL.substring(posComma+1);
var update = {type: type, text: text};
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getModificationFields(),tiddler,update,this.wiki.getCreationFields()));
}
var tiddler = this.wiki.getTiddler(this.editTitle) || new $tw.Tiddler({title: this.editTitle,type: DEFAULT_IMAGE_TYPE});
// data URIs look like "data:<type>;base64,<text>"
var dataURL = this.canvasDomNode.toDataURL(tiddler.fields.type),
posColon = dataURL.indexOf(":"),
posSemiColon = dataURL.indexOf(";"),
posComma = dataURL.indexOf(","),
type = dataURL.substring(posColon+1,posSemiColon),
text = dataURL.substring(posComma+1);
var update = {type: type, text: text};
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getModificationFields(),tiddler,update,this.wiki.getCreationFields()));
};
exports["edit-bitmap"] = EditBitmapWidget;

View File

@@ -57,6 +57,10 @@ EditShortcutWidget.prototype.render = function(parent,nextSibling) {
// Link into the DOM
parent.insertBefore(this.inputNode,nextSibling);
this.domNodes.push(this.inputNode);
// Focus the input Node if focus === "yes" or focus === "true"
if(this.shortcutFocus === "yes" || this.shortcutFocus === "true") {
this.focus();
}
};
/*
@@ -72,6 +76,7 @@ EditShortcutWidget.prototype.execute = function() {
this.shortcutStyle = this.getAttribute("style");
this.shortcutTooltip = this.getAttribute("tooltip");
this.shortcutAriaLabel = this.getAttribute("aria-label");
this.shortcutFocus = this.getAttribute("focus");
};
/*
@@ -118,12 +123,22 @@ EditShortcutWidget.prototype.handleKeydownEvent = function(event) {
}
};
/*
focus the input node
*/
EditShortcutWidget.prototype.focus = function() {
if(this.inputNode.focus && this.inputNode.select) {
this.inputNode.focus();
this.inputNode.select();
}
};
/*
Selectively refreshes the widget if needed. Returns true if the widget needed re-rendering
*/
EditShortcutWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.placeholder || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.style || changedAttributes.tooltip || changedAttributes["aria-label"]) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.placeholder || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.style || changedAttributes.tooltip || changedAttributes["aria-label"] || changedAttributes.focus) {
this.refreshSelf();
return true;
} else if(changedTiddlers[this.shortcutTiddler]) {

View File

@@ -46,6 +46,7 @@ EditWidget.prototype.execute = function() {
this.editIndex = this.getAttribute("index");
this.editClass = this.getAttribute("class");
this.editPlaceholder = this.getAttribute("placeholder");
this.editTabIndex = this.getAttribute("tabindex");
// Choose the appropriate edit widget
this.editorType = this.getEditorType();
// Make the child widgets
@@ -56,7 +57,8 @@ EditWidget.prototype.execute = function() {
field: {type: "string", value: this.editField},
index: {type: "string", value: this.editIndex},
"class": {type: "string", value: this.editClass},
"placeholder": {type: "string", value: this.editPlaceholder}
"placeholder": {type: "string", value: this.editPlaceholder},
"tabindex": {type: "string", value: this.editTabIndex}
},
children: this.parseTreeNode.children
}]);
@@ -90,11 +92,11 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
EditWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Refresh if an attribute has changed, or the type associated with the target tiddler has changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tabindex || (changedTiddlers[this.editTitle] && this.getEditorType() !== this.editorType)) {
this.refreshSelf();
return true;
} else {
return this.refreshChildren(changedTiddlers);
return this.refreshChildren(changedTiddlers);
}
};

View File

@@ -73,13 +73,13 @@ Compute the internal state of the widget
KeyboardWidget.prototype.execute = function() {
var self = this;
// Get attributes
this.actions = this.getAttribute("actions");
this.message = this.getAttribute("message");
this.param = this.getAttribute("param");
this.key = this.getAttribute("key");
this.tag = this.getAttribute("tag");
this.actions = this.getAttribute("actions","");
this.message = this.getAttribute("message","");
this.param = this.getAttribute("param","");
this.key = this.getAttribute("key","");
this.tag = this.getAttribute("tag","");
this.keyInfoArray = $tw.keyboardManager.parseKeyDescriptors(this.key);
this["class"] = this.getAttribute("class");
this["class"] = this.getAttribute("class","");
if(this.key.substr(0,2) === "((" && this.key.substr(-2,2) === "))") {
this.shortcutTiddlers = [];
var name = this.key.substring(2,this.key.length -2);

View File

@@ -183,7 +183,14 @@ LinkWidget.prototype.execute = function() {
this.isShadow = this.wiki.isShadowTiddler(this.to);
this.hideMissingLinks = (this.getVariable("tv-show-missing-links") || "yes") === "no";
// Make the child widgets
this.makeChildWidgets();
var templateTree;
if(this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
templateTree = this.parseTreeNode.children;
} else {
// Default template is a link to the title
templateTree = [{type: "text", text: this.to}];
}
this.makeChildWidgets(templateTree);
};
/*

View File

@@ -84,39 +84,50 @@ NavigatorWidget.prototype.getStoryList = function() {
};
NavigatorWidget.prototype.saveStoryList = function(storyList) {
var storyTiddler = this.wiki.getTiddler(this.storyTitle);
this.wiki.addTiddler(new $tw.Tiddler(
{title: this.storyTitle},
storyTiddler,
{list: storyList}
));
if(this.storyTitle) {
var storyTiddler = this.wiki.getTiddler(this.storyTitle);
this.wiki.addTiddler(new $tw.Tiddler(
{title: this.storyTitle},
storyTiddler,
{list: storyList}
));
}
};
NavigatorWidget.prototype.removeTitleFromStory = function(storyList,title) {
var p = storyList.indexOf(title);
while(p !== -1) {
storyList.splice(p,1);
p = storyList.indexOf(title);
if(storyList) {
var p = storyList.indexOf(title);
while(p !== -1) {
storyList.splice(p,1);
p = storyList.indexOf(title);
}
}
};
NavigatorWidget.prototype.replaceFirstTitleInStory = function(storyList,oldTitle,newTitle) {
var pos = storyList.indexOf(oldTitle);
if(pos !== -1) {
storyList[pos] = newTitle;
do {
pos = storyList.indexOf(oldTitle,pos + 1);
if(pos !== -1) {
storyList.splice(pos,1);
}
} while(pos !== -1);
} else {
storyList.splice(0,0,newTitle);
if(storyList) {
var pos = storyList.indexOf(oldTitle);
if(pos !== -1) {
storyList[pos] = newTitle;
do {
pos = storyList.indexOf(oldTitle,pos + 1);
if(pos !== -1) {
storyList.splice(pos,1);
}
} while(pos !== -1);
} else {
storyList.splice(0,0,newTitle);
}
}
};
NavigatorWidget.prototype.addToStory = function(title,fromTitle) {
this.wiki.addToStory(title,fromTitle,this.storyTitle,{openLinkFromInsideRiver: this.getAttribute("openLinkFromInsideRiver","top"),openLinkFromOutsideRiver: this.getAttribute("openLinkFromOutsideRiver","top")});
if(this.storyTitle) {
this.wiki.addToStory(title,fromTitle,this.storyTitle,{
openLinkFromInsideRiver: this.getAttribute("openLinkFromInsideRiver","top"),
openLinkFromOutsideRiver: this.getAttribute("openLinkFromOutsideRiver","top")
});
}
};
/*
@@ -279,15 +290,7 @@ NavigatorWidget.prototype.makeDraftTiddler = function(targetTitle) {
Generate a title for the draft of a given tiddler
*/
NavigatorWidget.prototype.generateDraftTitle = function(title) {
var c = 0,
draftTitle,
username = this.wiki.getTiddlerText("$:/status/UserName"),
attribution = username ? " by " + username : "";
do {
draftTitle = "Draft " + (c ? (c + 1) + " " : "") + "of '" + title + "'" + attribution;
c++;
} while(this.wiki.tiddlerExists(draftTitle));
return draftTitle;
return this.wiki.generateDraftTitle(title);
};
// Take a tiddler out of edit mode, saving the changes
@@ -466,14 +469,14 @@ NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
},this.wiki.getModificationFields());
this.wiki.addTiddler(draftTiddler);
// Update the story to insert the new draft at the top and remove any existing tiddler
if(storyList.indexOf(draftTitle) === -1) {
if(storyList && storyList.indexOf(draftTitle) === -1) {
var slot = storyList.indexOf(event.navigateFromTitle);
if(slot === -1) {
slot = this.getAttribute("openLinkFromOutsideRiver","top") === "bottom" ? storyList.length - 1 : slot;
}
storyList.splice(slot + 1,0,draftTitle);
}
if(storyList.indexOf(title) !== -1) {
if(storyList && storyList.indexOf(title) !== -1) {
storyList.splice(storyList.indexOf(title),1);
}
this.saveStoryList(storyList);
@@ -529,7 +532,7 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
var storyList = this.getStoryList(),
history = [];
// Add it to the story
if(storyList.indexOf(IMPORT_TITLE) === -1) {
if(storyList && storyList.indexOf(IMPORT_TITLE) === -1) {
storyList.unshift(IMPORT_TITLE);
}
// And to history
@@ -590,7 +593,7 @@ NavigatorWidget.prototype.handleFoldOtherTiddlersEvent = function(event) {
NavigatorWidget.prototype.handleFoldAllTiddlersEvent = function(event) {
var self = this,
paramObject = event.paramObject || {},
prefix = paramObject.foldedStatePrefix;
prefix = paramObject.foldedStatePrefix || "$:/state/folded/";
$tw.utils.each(this.getStoryList(),function(title) {
self.wiki.setText(prefix + title,"text",null,"hide");
});
@@ -606,7 +609,6 @@ NavigatorWidget.prototype.handleUnfoldAllTiddlersEvent = function(event) {
};
NavigatorWidget.prototype.handleRenameTiddlerEvent = function(event) {
event = $tw.hooks.invokeHook("th-renaming-tiddler", event);
var paramObject = event.paramObject || {},
from = paramObject.from || event.tiddlerTitle,
to = paramObject.to;

View File

@@ -56,32 +56,39 @@ RevealWidget.prototype.render = function(parent,nextSibling) {
RevealWidget.prototype.positionPopup = function(domNode) {
domNode.style.position = "absolute";
domNode.style.zIndex = "1000";
var left,top;
switch(this.position) {
case "left":
domNode.style.left = Math.max(0, this.popup.left - domNode.offsetWidth) + "px";
domNode.style.top = this.popup.top + "px";
left = this.popup.left - domNode.offsetWidth;
top = this.popup.top;
break;
case "above":
domNode.style.left = this.popup.left + "px";
domNode.style.top = Math.max(0, this.popup.top - domNode.offsetHeight) + "px";
left = this.popup.left;
top = this.popup.top - domNode.offsetHeight;
break;
case "aboveright":
domNode.style.left = (this.popup.left + this.popup.width) + "px";
domNode.style.top = Math.max(0, this.popup.top + this.popup.height - domNode.offsetHeight) + "px";
left = this.popup.left + this.popup.width;
top = this.popup.top + this.popup.height - domNode.offsetHeight;
break;
case "right":
domNode.style.left = (this.popup.left + this.popup.width) + "px";
domNode.style.top = this.popup.top + "px";
left = this.popup.left + this.popup.width;
top = this.popup.top;
break;
case "belowleft":
domNode.style.left = Math.max(0, this.popup.left + this.popup.width - domNode.offsetWidth) + "px";
domNode.style.top = (this.popup.top + this.popup.height) + "px";
left = this.popup.left + this.popup.width - domNode.offsetWidth;
top = this.popup.top + this.popup.height;
break;
default: // Below
domNode.style.left = this.popup.left + "px";
domNode.style.top = (this.popup.top + this.popup.height) + "px";
left = this.popup.left;
top = this.popup.top + this.popup.height;
break;
}
if(!this.positionAllowNegative) {
left = Math.max(0,left);
top = Math.max(0,top);
}
domNode.style.left = left + "px";
domNode.style.top = top + "px";
};
/*
@@ -94,6 +101,7 @@ RevealWidget.prototype.execute = function() {
this.type = this.getAttribute("type");
this.text = this.getAttribute("text");
this.position = this.getAttribute("position");
this.positionAllowNegative = this.getAttribute("positionAllowNegative") === "yes";
this["class"] = this.getAttribute("class","");
this.style = this.getAttribute("style","");
this["default"] = this.getAttribute("default","");
@@ -118,10 +126,22 @@ Read the state tiddler
*/
RevealWidget.prototype.readState = function() {
// Read the information from the state tiddler
var state = this.stateTitle ? (this.stateField ? this.wiki.getTiddler(this.stateTitle).getFieldString(this.stateField) :
(this.stateIndex ? this.wiki.extractTiddlerDataItem(this.stateTitle,this.stateIndex) :
this.wiki.getTiddlerText(this.stateTitle))) || this["default"] || this.getVariable("currentTiddler") :
(this.stateTiddlerTitle ? this.wiki.getTextReference(this.state,this["default"],this.getVariable("currentTiddler")) : this["default"]);
var state,
defaultState = this["default"];
if(this.stateTitle) {
var stateTitleTiddler = this.wiki.getTiddler(this.stateTitle);
if(this.stateField) {
state = stateTitleTiddler ? stateTitleTiddler.getFieldString(this.stateField) || defaultState : defaultState;
} else if(this.stateIndex) {
state = stateTitleTiddler ? this.wiki.extractTiddlerDataItem(this.stateTitle,this.stateIndex) || defaultState : defaultState;
} else if(stateTitleTiddler) {
state = this.wiki.getTiddlerText(this.stateTitle) || defaultState;
} else {
state = defaultState;
}
} else {
state = this.stateTiddlerTitle ? this.wiki.getTextReference(this.state,this["default"],this.getVariable("currentTiddler")) : this["default"];
}
if(state === null) {
state = this["default"];
}
@@ -130,10 +150,10 @@ RevealWidget.prototype.readState = function() {
this.readPopupState(state);
break;
case "match":
this.isOpen = !!(this.compareStateText(state) == 0);
this.isOpen = this.text === state;
break;
case "nomatch":
this.isOpen = !(this.compareStateText(state) == 0);
this.isOpen = this.text !== state;
break;
case "lt":
this.isOpen = !!(this.compareStateText(state) < 0);
@@ -179,13 +199,13 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
RevealWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) {
if(changedAttributes.state || changedAttributes.type || changedAttributes.text || changedAttributes.position || changedAttributes.positionAllowNegative || changedAttributes["default"] || changedAttributes.animate || changedAttributes.stateTitle || changedAttributes.stateField || changedAttributes.stateIndex) {
this.refreshSelf();
return true;
} else {
var currentlyOpen = this.isOpen;
this.readState();
if(this.isOpen !== currentlyOpen || (this.stateTiddlerTitle && changedTiddlers[this.stateTiddlerTitle])) {
if(this.isOpen !== currentlyOpen) {
if(this.retain === "yes") {
this.updateState();
} else {

View File

@@ -145,6 +145,7 @@ SelectWidget.prototype.execute = function() {
this.selectDefault = this.getAttribute("default");
this.selectMultiple = this.getAttribute("multiple", false);
this.selectSize = this.getAttribute("size");
this.selectTooltip = this.getAttribute("tooltip");
// Make the child widgets
var selectNode = {
type: "element",
@@ -160,6 +161,9 @@ SelectWidget.prototype.execute = function() {
if(this.selectSize) {
$tw.utils.addAttributeToParseTreeNode(selectNode,"size",this.selectSize);
}
if(this.selectTooltip) {
$tw.utils.addAttributeToParseTreeNode(selectNode,"title",this.selectTooltip);
}
this.makeChildWidgets([selectNode]);
};
@@ -169,7 +173,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
SelectWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// If we're using a different tiddler/field/index then completely refresh ourselves
if(changedAttributes.selectTitle || changedAttributes.selectField || changedAttributes.selectIndex) {
if(changedAttributes.selectTitle || changedAttributes.selectField || changedAttributes.selectIndex || changedAttributes.selectTooltip) {
this.refreshSelf();
return true;
// If the target tiddler value has changed, just update setting and refresh the children

View File

@@ -22,15 +22,17 @@ Options include:
document: optional document object to use instead of global document
*/
var Widget = function(parseTreeNode,options) {
if(arguments.length > 0) {
this.initialise(parseTreeNode,options);
}
this.initialise(parseTreeNode,options);
};
/*
Initialise widget properties. These steps are pulled out of the constructor so that we can reuse them in subclasses
*/
Widget.prototype.initialise = function(parseTreeNode,options) {
// Bail if parseTreeNode is undefined, meaning that the widget constructor was called without any arguments so that it can be subclassed
if(parseTreeNode === undefined) {
return;
}
options = options || {};
// Save widget info
this.parseTreeNode = parseTreeNode;
@@ -46,7 +48,21 @@ Widget.prototype.initialise = function(parseTreeNode,options) {
this.eventListeners = {};
// Hashmap of the widget classes
if(!this.widgetClasses) {
// Get widget classes
Widget.prototype.widgetClasses = $tw.modules.applyMethods("widget");
// Process any subclasses
$tw.modules.forEachModuleOfType("widget-subclass",function(title,module) {
if(module.baseClass) {
var baseClass = Widget.prototype.widgetClasses[module.baseClass];
if(!baseClass) {
throw "Module '" + title + "' is attemping to extend a non-existent base class '" + module.baseClass + "'";
}
var subClass = module.constructor;
subClass.prototype = new baseClass();
$tw.utils.extend(subClass.prototype,module.prototype);
Widget.prototype.widgetClasses[module.name || module.baseClass] = subClass;
}
});
}
};
@@ -369,9 +385,10 @@ Widget.prototype.previousSibling = function() {
Render the children of this widget into the DOM
*/
Widget.prototype.renderChildren = function(parent,nextSibling) {
$tw.utils.each(this.children,function(childWidget) {
childWidget.render(parent,nextSibling);
});
var children = this.children;
for(var i = 0; i < children.length; i++) {
children[i].render(parent,nextSibling);
};
};
/*
@@ -439,11 +456,11 @@ Widget.prototype.refreshSelf = function() {
Refresh all the children of a widget
*/
Widget.prototype.refreshChildren = function(changedTiddlers) {
var self = this,
var children = this.children,
refreshed = false;
$tw.utils.each(this.children,function(childWidget) {
refreshed = childWidget.refresh(changedTiddlers) || refreshed;
});
for (var i = 0; i < children.length; i++) {
refreshed = children[i].refresh(changedTiddlers) || refreshed;
}
return refreshed;
};

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