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

Compare commits

..

406 Commits

Author SHA1 Message Date
Jermolene
384e5b7b63 Version number update for 5.1.14 2017-04-26 17:03:35 +01:00
Jermolene
5e317161f6 Update readmes 2017-04-26 17:03:01 +01:00
Jermolene
39e8a83c4c Prepare for release of 5.1.14 2017-04-26 17:02:06 +01:00
Jermolene
7890440569 Improve organization for the 5.1.14 release notes 2017-04-26 16:26:33 +01:00
Jermolene
02331365f0 Update plugin library location 2017-04-26 14:35:24 +01:00
Jermolene
48fe208f0c Update release note 2017-04-26 14:35:16 +01:00
Jermolene
a613ffb6a3 Update contributor list in 5.1.14 release note 2017-04-26 14:35:03 +01:00
Jermolene
c0f7f18f0a Update KaTeX to v0.7.1 2017-04-26 14:34:17 +01:00
Jermolene
e18b6bf5c4 Docs typo 2017-04-24 16:27:10 +01:00
Jermolene
31523a1e7b Add empty link to prerelease tiddler
Thanks @twMat
2017-04-24 16:26:56 +01:00
Jermolene
4b780899a5 Move SJCL license file into core plugin
It was added as a separate system tiddler, but that means updating a
lot of filters to add and exclude it as appropriate (as we do with
$:/library/sjcl.js itself)
2017-04-23 09:53:18 +01:00
Jermolene
04f402b974 Fix drag and drop issue on iOS 2017-04-21 16:27:44 +01:00
Jermolene
aa2f240936 Update to latest version of ios-drag-drop.js 2017-04-21 08:22:58 +01:00
twMat
d99e0c9f97 Edit getindex Operator.tid op-purpose (#2837)
Other `op-` fields should probably also be added.
2017-04-20 16:20:40 +01:00
Jermolene
2a1fb964d5 Reformatting "wikilabs" resource link title 2017-04-19 15:56:41 +01:00
Mario Pietsch
5050829e63 add wikilabs resource link tiddler (#2834) 2017-04-19 15:54:37 +01:00
Jermolene
6c4c1a984b Make help panel scrollbars be optional 2017-04-19 13:26:22 +01:00
Jermolene
53181d2ab8 Missed parenthesis
Thanks @twMat
2017-04-19 13:25:31 +01:00
Mario Pietsch
f22547fa3a german text updates (#2830) 2017-04-18 21:01:58 +01:00
Jermolene
3693b4786d Dutch translation update
Thanks @gernert
2017-04-18 20:58:34 +01:00
Jermolene
cd16573f20 Rephrase the Google Analytics plugin pages 2017-04-18 18:48:17 +01:00
Jermolene
0aaebe9757 Revert #2814
As per the discussion on the ticket, we’ll revisit this after 5.1.14
2017-04-18 08:15:25 +01:00
Jermolene
379e780e80 Release note update 2017-04-17 18:46:02 +01:00
Jermolene
0a2c3d0c3c Add quote to HelloThere 2017-04-17 17:54:17 +01:00
Jermolene
202ffd9c51 Add big block quote style 2017-04-17 17:53:19 +01:00
Jermolene
2e0c119d5b Add Tiddler.getFieldStrings() method 2017-04-17 17:04:15 +01:00
Jermolene
f03feb69a9 Add elementTag parameter to list-tagged-draggable macro 2017-04-17 16:51:12 +01:00
Jermolene
40a61ff2e7 The last batch of drag and drop docs 2017-04-06 10:15:22 +01:00
Bram Chen
b9a8c3c01d Update chinese translations (#2810)
* Add chinese translations of hint for drag and drop to Toolbars/*/Hint in control panel

* Add chinese translations for Basics/NewJournal/Text/Prompt
2017-04-05 11:23:07 +01:00
Jermolene
c25a44756b Add new journal text to control panel
Making #2821 a bit more accessible
2017-04-04 18:16:37 +01:00
Jermolene
83497c13d9 Fix whitespace and missing closing tag issues in #2821 2017-04-04 18:15:49 +01:00
Richard Decal
ec0fa2f932 Added ability to change text template of NewJournal (#2821)
* adding custom text field to new-journal

* fixed spacing

* signing the CLA
2017-04-04 18:06:49 +01:00
Jermolene
773ef6adfb Docs update 2017-04-02 17:51:45 +01:00
Jermolene
b1e0fa4a34 More drag and drop docs 2017-04-02 17:51:24 +01:00
Jermolene
aa1a8cf2eb Docs typo 2017-03-29 10:19:49 +01:00
Jermolene
8802015f1a Docs updates
Starting to document the new drag and drop stuff
2017-03-29 10:19:42 +01:00
Jermolene
50268d9231 Killer typo 2017-03-29 09:22:51 +01:00
Jermolene
b37178dda1 Fix download saver for Safari 10.1
Safari now finally supports the ‘download’ attribute for the anchor
tag, meaning that the download saver works properly.
2017-03-29 09:21:49 +01:00
Jermolene
1e106a8f3d Better handling of dropeffect 2017-03-28 15:09:36 +01:00
Jermolene
f3cab3753e Don't set draggable property for links 2017-03-28 13:05:00 +01:00
Jermolene
303f255fcd Avoid wikifying system tiddlers
Fixes #2814
2017-03-27 10:00:31 +01:00
Jermolene
af45d509eb Adjust capitalisation of X-UA-Compatible meta tag
The docs suggest that the capitalised form is correct
2017-03-27 10:00:05 +01:00
Jermolene
d3fe4f600a Partially fix drag and drop on IE11
These changes allow drag and drop to work with one issue: <a> links are
not draggable; draggable divs, spans, buttons etc. seem to work fine.
There’s some issue with IE11 that I don’t understand.

For testing, you can force links to become spans by changing line 64 of
$:/core/modules/widgets/link.js to:

	var domNode = this.document.createElement("span");
2017-03-27 09:59:40 +01:00
Jermolene
0276b69244 Remove double quotes from copyright message
Needed because we transclude the copyright message into a head meta
tag. IE11 was complaining; other browsers didn’t seem to mind.
2017-03-27 09:57:17 +01:00
Jermolene
4891732481 Adjust listops widget to only modify tiddler if tags have changed
We do this so that we don’t accidentally modify shadow tiddlers when we
drag them to reorder them within their tag parent. Otherwise, moving a
toolbar button like $:/core/ui/Buttons/permaview in the control panel
will override the shadow tiddler.
2017-03-24 09:57:22 +00:00
Jermolene
d9ed01b621 Fix: removing other tags during drag and drop 2017-03-24 09:55:42 +00:00
Jermolene
0493208a23 mobiledragdrop: attempt to fix scrolling issues on ios
See https://github.com/timruffles/ios-html5-drag-drop-shim/issues/77
2017-03-23 21:16:01 +00:00
Jermolene
0efed8335d mobiledragdrop: Enable "holdToDrag"
Hopefully, this will make links clickable again, and reduce accidental
dragging while scrolling.
2017-03-23 21:15:33 +00:00
Jermolene
1f860bd04e Fix problem with dragging links 2017-03-23 17:52:15 +00:00
Jermolene
8744d77f88 Add mobiledragdrop shim plugin
This seems to work quite well for me - cc @xcazin
2017-03-23 17:03:35 +00:00
Jermolene
24f29ac605 Add support for wikified raw markup tiddlers 2017-03-23 17:02:37 +00:00
Jermolene
b1ed77d6b8 Switch drag image to use draggable DOM node
We’ll still support dragging pills, but dragging the DOM node image
seems to look better in most situations.
2017-03-23 17:02:26 +00:00
Jermolene
8f1114960a Refactor draggable stuff for easier reuse
And in the process, make the button widget draggable.

Unfortunately, Firefox has a bug that prevents buttons from being
dragged (see https://bugzilla.mozilla.org/show_bug.cgi?id=568313 and
https://bugzilla.mozilla.org/show_bug.cgi?id=646823). So we have to use
the “tag” attribute to make it use a different element.
2017-03-23 14:23:33 +00:00
Jermolene
3a00d2eea3 Allow drag and drop in toolbar layout in control panel 2017-03-20 22:29:03 +00:00
Jermolene
5ed7ade44f Add some handy drag-and-drop macros
And refactor the tag template to use one of them
2017-03-20 22:11:06 +00:00
Jermolene
bea33efd63 Fix problem with dragging text snippets 2017-03-20 22:03:28 +00:00
Jermolene
f4656b0f25 Add support dragging to the bottom of a list 2017-03-20 22:02:55 +00:00
Jermolene
9bad99d14e Draggable: properly stringify tiddler titles
Thanks @twMat
2017-03-20 22:01:51 +00:00
Jermolene
3197f9a639 Add select all/none checkbox to $:/Import
Prompted by this discussion:
https://groups.google.com/d/topic/tiddlywiki/MYBWCxOc_gM/discussion
2017-03-20 22:00:14 +00:00
Jermolene
eba1c3c160 Improve support for drag and drop
Documentation TBD
2017-03-19 19:33:56 +00:00
Jermolene
c2391c5250 Action-deletefield should only update tiddler modified/created if it is changed 2017-03-19 19:30:52 +00:00
Jermolene
5b3bb1974c Move coding docs to the /dev wiki 2017-03-19 13:53:21 +00:00
Jermolene
39cdaeb34d Fix problem with tracking dragenter/leave events in Firefox
Fixes #686 (hopefully!)
2017-03-17 14:54:30 +00:00
Jermolene
d778bc9a21 Add link to Tinka 2017-03-17 14:20:44 +00:00
Jermolene
fe5670663d Add plugins to TOC 2017-03-17 14:20:36 +00:00
Jermolene
8804278e6e Add OpenOffice docx and pptx file types 2017-03-17 14:20:17 +00:00
Jermolene
b9fbe12118 More defensive deepFreeze()
IE11 chokes on Object.freeze(undefined)
2017-03-17 14:20:04 +00:00
Jermolene
779e62a30f Add support for JSON files containing a single tiddler
At the moment, we support JSON files containing an array of tiddlers.
With this change the core will import files containing a single
tiddler. Also adding templates for saving individual tiddlers in JSON
format
2017-03-17 14:19:43 +00:00
gernert
d65fd771e7 Update ColourPalettes.tid (#2806) 2017-03-17 13:54:32 +00:00
Jermolene
73e1724fdf Extend $tw.utils.httpRequest() to cope with binary data
The problem was that `this.responseText` crashes for non-text data. We
fix it by letting the client specify which property should be returned.

@ericshulman does this work for you?
2017-03-17 13:41:17 +00:00
Jermolene
595072b2bc Update browser support for importing via paste 2017-03-17 13:36:28 +00:00
Jermolene
66d5e2650e Fix problem with dragger image in Chrome
Fixes #2800
2017-03-12 18:07:59 +00:00
tejjyid
bb81f00161 Update cla-individual.md (#2792)
For documentation purposes only...
2017-03-06 08:58:23 +00:00
twMat
5dbc1b7163 Doc typo correction (#2791) 2017-03-05 20:25:24 +00:00
Jermolene
28b861451b Yet more tweaks to the highlight.js integration
Now we check that the selected language is supported before we invoke
highlight.js; left to its own devices, it crashes…
2017-03-02 09:17:48 +00:00
Jermolene
796e59e0dc Google Analytics plugin: Remove unneeded version number
By omitting the version number the core will apply the current core
version number to the plugin.
2017-02-28 10:23:02 +00:00
Jermolene
e30330d4be Introduce Twitter plugin for embedding tweets etc. 2017-02-28 10:23:02 +00:00
Jermolene
52a414959c wiki.extractTiddlerDataItem() should use caching 2017-02-28 10:23:02 +00:00
Jermolene
b9a835b879 Fix bug with wiki.getTiddlerDataCached()
We need to process the default data outside of the cache function to
ensure that we don’t cache the defaults
2017-02-28 10:23:02 +00:00
Tobias Beer
6343c39bd6 Docs: improve description of remove operator (#2735)
see https://github.com/Jermolene/TiddlyWiki5/issues/2731#issuecomment-275200159
2017-02-27 16:40:48 +00:00
twMat
35b327e336 Mat finally, and somewhat shameful, signing the CLA (#2723)
All previous contribs from me are included in the signing of the agreement.
2017-02-27 16:39:55 +00:00
jrgetsin
63b3d88604 Typo: Update TiddlyWiki.tid (#2566)
for "bought" put "brought"
looked like a typo to me
2017-02-27 16:38:57 +00:00
gernert
a71e27386f Update SystemTags.tid (#2508)
* Update SystemTags.tid

* Update SystemTags.tid

@Jermolene
Hope I did it correct now ;-)
2017-02-27 16:38:13 +00:00
gernert
9a67a90a30 Update Using Stylesheets.tid (#2786) 2017-02-27 15:54:15 +00:00
Roma
d53d6e7921 Added community tiddler for ViM syntax file. (#2544) 2017-02-26 16:48:07 +00:00
Jermolene
b90600580f Filesystemadaptor: Fix bug with JSON tiddlers
Fixes #2783
2017-02-24 15:36:22 +00:00
Jermolene
d0594e4a45 Rejiggle the license to try to make GitHub recognise it 2017-02-24 13:52:39 +00:00
twMat
b5360db375 Clarified intro statment for TiddlerWidget (#2770)
Ref [discussion](https://groups.google.com/d/msg/tiddlywiki/S-DliskYksE/55c6_CssCgAJ).
2017-02-23 17:02:49 +00:00
Sylvain Comte
da0c244a51 created a "resource" card for leaflet maps plugin (#2734) 2017-02-23 17:01:41 +00:00
Jermolene
ad1c2a6571 Fix problem with 'has' operator
Fixes problem introduced in 6085936475
2017-02-23 14:27:43 +00:00
Marxsal
617ec82a22 Update documentation to reflect actual way timeline macro currently works. (#2781) 2017-02-23 10:59:40 +00:00
Jermolene
7c2d519d4f Update release note 2017-02-23 08:20:43 +00:00
Bram Chen
f246b93a38 Add chinese translations for the "close plugin library" button (#2779) 2017-02-22 15:55:44 +00:00
Jermolene
31a803626f Add GettingStarted "online" tab
Fixes #2780
2017-02-22 15:34:50 +00:00
Tobias Beer
88a65f038e Add a "close plugin library" button (#2072)
* provides a "close plugin library" button

* starting from #1718 by @inmysocks
* possibly fixes all of #1718, #1597,  and #2067

* corrected code comment

* add back title

No idea why I overlooked this beforehand.

Next time I will not suggest such changes that have little to do with
the PR, but rather just comment the code.

* ah, sorry, "fixed" wrong spot

now

```
<$action-sendmessage $message="tm-load-plugin-from-library"
url={{!!url}} title={{$(assetInfo)$!!original-title}}/>
```

...should be back at the right spot.

* mhhh... still fixing the mess

load, unload, puh... let's see if I got it now

* added unloadIFrame and minor syntax fixes
2017-02-22 12:15:26 +00:00
Tobias Beer
6085936475 Introduce "field" suffix for "has" filter operator (#2066)
* has:field — tested & documented

allows to test whether a field exists

* fixed inverted condition

* added from version to docs
2017-02-22 12:13:59 +00:00
Jermolene
cd2bc88658 Add "enlist" operator
Fixes #2767
2017-02-21 15:17:47 +00:00
Jermolene
b1ecf81b0c Tentative improvements to highlight plugin problems
We now use highlight.js in raw HTML mode on the server, rather than
trying to use it with the fakedom. This causes problems with fakedoms
inability to get textContent for a node that has been created by
assigning innerHTML. So we extend the fakedom to allow the original
text content to be saved.

See #2778 for discussion.
2017-02-21 13:09:32 +00:00
Jermolene
eee18aab40 Docs: Fix typo 2017-02-21 08:47:00 +00:00
Jermolene
9fc2086b71 Optimise sameday filter
I used this test:

console.time();for(var t=0; t<200; t++)
{$tw.wiki.filterTiddlers("[all[tiddlers+shadows]sameday[20170210]]");};c
onsole.timeEnd()

Before this patch, I got speeds of approx 190ms, versus 140ms
afterwards.

Note that the ability to add a cache property like this is only
possible because tiddler objects are immutable.
2017-02-21 08:31:05 +00:00
Thomas Elmiger
8307f7c3ca Tiny optimisation for Naming of System Tiddlers.tid (#2773)
* Replacement icon stopwatch on

As discussed in issue #2690

* Replacement icon stopwatch off

As discussed in issue #2690

* Added missing tag "Resources" (Community Resource)

* Tried to make a sentence clearer

CamelCase words are NOT joined with hyphens (copy-paste error?). 
Copied "directly" from the line below to make the meaning even clearer.
2017-02-21 08:28:53 +00:00
Jermolene
b26e138503 Tweaks for #2774 2017-02-19 20:50:52 +00:00
twMat
16da00fe3e Clarify EditTextWidget behaviour and tag attribute (#2774) 2017-02-19 20:48:32 +00:00
Bram Chen
7086c41b6c Update chinese translations for help command (#2775)
* enhanced rendertiddler command
* the new fetch command
2017-02-19 20:46:25 +00:00
Xavier Cazin
6a172363da fr-FR for new fetch command and modified rendertiddler (#2777)
* fr-FR translation of additional error strings

* a slightly better fr-FR translation for the Site Subtitle

* fr-FR translation for the "print page" button

* fr-FR translation for Tiddler Info Panel-related strings

* fr-FR translation for Timestamp activation strings

* fr-FR translation for TiddlerManager related strings

* fr-FR translation for an additional string related to system tiddlers

* add group-sort fields to fr-FR Types

* fixes to the fr-FR Tiddler Manager translations

* fixes fr-FR translation for timestamp-related strings

* fr-FR translation of the tiddler renaming strings

* fr-FR translation of what is the StoryList filter

* fr-FR translations for new saver-related settings

* fr-FR translations around the new fetch command

* fr-FR translation for modified rendertiddler command
2017-02-19 18:27:22 +00:00
Jermolene
75b501f681 Optimise $tw.utils.parseStringArray()
On my machine, the following test performed on the prerelease improves
from 40ms to 8ms with this patch:

```
var a =
$tw.utils.stringifyList($tw.wiki.allTitles());console.time();$tw.utils.p
arseStringArray(a);console.timeEnd()
```
2017-02-19 18:08:15 +00:00
Jermolene
daf703b67f Add support for th-navigating event 2017-02-19 15:47:37 +00:00
Jermolene
0d0ece6377 Add new "fetch" command
Like the load command except retrieves the file over HTTP/HTTPS.

Allows experimentation with server-side twederation

This is a cleaned up version of code that I wrote last year at TWEUM
2016 @inmysocks @pmario @twMat @xcazin
2017-02-18 13:33:41 +00:00
Jermolene
74b0da065e Add logging functions to commander 2017-02-18 13:30:04 +00:00
Jermolene
6f93ce6ea7 Enhance rendertiddler command with support for additional variable
Passing an arbitrary variable allows us to e.g. reuse the export
filters as shown in the example
2017-02-18 13:17:44 +00:00
Jermolene
91b341e8e0 Better error trapping for WebDAV saver
Without these checks we get a startup crash when using TiddlyWiki in
client-server configuration.
2017-02-18 12:12:29 +00:00
Jermolene
f0ff1f993e Fix problem with textarea background colour
Fixes #2772
2017-02-17 17:39:01 +00:00
Bram Chen
d0c20435cd Add chinese translations for Error/EditConflict (#2771) 2017-02-17 17:11:30 +00:00
FND
6505e6f448 WebDAV file overwrite protection (#2614)
* putSaver: detect edit conflicts to prevent clobbering, if possible

if the server supplies an ETag, we send it back when saving, allowing
the server to detect edit conflicts and respond with 412 (cf.
https://www.w3.org/1999/04/Editing/)

caveats:
* this only kicks in after the first save, as we don't have access to
  the ETag when first loading the document
* there's no recovery mechanism (e.g. resetting `this.etag` in order to
  force clobbering), other than manually reloading the document

* putSaver: retrieve ETag upon initialization for clobbering protection

this addresses one of the caveats from the previous commit
(2d75cb83af) - while theoretically prone
to a race condition, it seems unlikely that saving will be triggered
before the server responds

* putSaver: simplify URI extraction

this simplifies the approach introduced in
f51f6bf774, with the purpose of removing
the fragment identifier

* putSaver: localize error message

* putSaver: switch to built-in HTTP helper

in the process, fixed ETag assignment in `#save` method (was
`this.etag`, now `self.etag`) as well as a syntax error due to a missing
closing brace

* putSaver: consolidate URI handling
2017-02-17 12:26:15 +00:00
twMat
a6b538b308 Clarify use of RawMarkup tag (#2768)
Anyone attempting to use this tag will need information about required reload of TW for activation.
2017-02-15 08:56:49 +00:00
Jermolene
467bf17dd8 GoogleAnalytics Plugin: Make sure we don't crash if the config tiddlers don't exist 2017-02-13 11:39:39 +00:00
Jermolene
95f565878e Savetrail: Fix conditionality of hook-based saving 2017-02-13 09:00:34 +00:00
Jermolene
d6f5b3cacd Filesystemadaptor: Fix problem with unknown file extensions 2017-02-12 15:35:04 +00:00
Jermolene
d5b04c2688 Fix problem with loading metafiles
This issue was introduced in 1b41b44684.

Fixes problem raised by @pmario in
https://github.com/Jermolene/TiddlyWiki5/commit/3708f6c8e4f4bf2ea1cb10b0
fa685888485f788a#commitcomment-20848240
2017-02-12 12:14:04 +00:00
Jermolene
7b251df989 Filesystemadaptor: Fix problem with creation of unneeded directories
@pmario this fixes the problem reported in
https://github.com/Jermolene/TiddlyWiki5/commit/3708f6c8e4f4bf2ea1cb10b0
fa685888485f788a#commitcomment-20847981
2017-02-12 11:15:23 +00:00
Jermolene
a51f62bc40 Docs: Move beaker browser file 2017-02-12 11:14:21 +00:00
Jermolene
6397ce8997 Docs: move a couple of files to the correct dir 2017-02-12 11:14:05 +00:00
Jermolene
de9bb2fa40 Feature TiddlyMap in the HelloThere thumbnails 2017-02-12 11:13:43 +00:00
Jermolene
b5482d8dba Remove extraneous console.log
I’ve leaving the one at line 91 because it might be useful for field
debugging…
2017-02-11 12:59:18 +00:00
Jermolene
3708f6c8e4 Major refactoring of filesystemadaptor
The code here had got a bit broken by some PRs that I should have
checked more carefully. I’ve done a major refactoring which will
hopefully make it easier to understand, and fixes a number of problems:

* Problem with eg .md tiddlers not being deleted correctly
* Problem with Windows path separators not being usable within
$:/config/FileSystemPaths on Windows
* Problem with filename clashes not being detected correctly when
saving to a different directory via $:/config/FileSystemPaths
* Enables slashes within tiddler titles to be mapped into folders
* Enables plain text files like .md and .css to be saved with .meta
files instead of as .tid files (see #2558)
* No longer replaces spaces with underscores

As this is such a major update, I’d be grateful if Node.js users could
give it a careful run through — in particular, you’ll need to try
creating new tiddlers of various types and ensure that the expected
files are created.
2017-02-11 12:56:42 +00:00
Jermolene
1961db6732 Register alternate mime type for Markdown files
macOS considers them to be `text/markdown`, which meant that dragging
an .md file ended up with the wrong content type
2017-02-11 12:48:41 +00:00
Jermolene
36c0af0fd4 Docs: Fix typo in example filter 2017-02-11 12:47:56 +00:00
Jermolene
9e08aed8ad Update release note 2017-02-10 12:45:26 +00:00
Jermolene
075d7d76df SaveTrail: Update readme 2017-02-10 07:33:38 +00:00
Jermolene
3d8249dc7a Savetrails: Download before and after files for destructive modifications 2017-02-09 15:45:39 +00:00
Jermolene
97e995e0c7 Add wiki.checkTiddlerText() convenience method 2017-02-09 15:43:28 +00:00
Jermolene
2397f0aa6f Add several new hooks for UI actions 2017-02-09 15:42:55 +00:00
Jermolene
6b2ab90721 Update hook mechanism so that multiple parameters can be passed 2017-02-09 15:42:21 +00:00
Jermolene
73ded6a82a Add new "count" filter operator
See discussion here:
https://groups.google.com/d/msgid/tiddlywiki/fe51b7f5-5369-493b-82e5-94c
18e863fe0%40googlegroups.com?utm_medium=email&utm_source=footer
2017-02-08 20:11:44 +00:00
Jermolene
9bc523fdef Fix bug in renameTiddler
This operation isn’t used by the core, but is used by the TextSlicer
plugin
2017-02-08 20:04:36 +00:00
Jermolene
f4a015f120 Upgrade to latest version of xmldom 2017-02-07 18:20:30 +00:00
Jermolene
d9fd722e50 Text-slicer: Improve image support
Previously we only worked with base64 data URI images; now we work with
relative URLs as well.
2017-02-07 11:05:08 +00:00
Jermolene
112a8d95c5 Docs: Switch "Mailing List" to "Forum"
Fixes #2761
2017-02-07 11:03:39 +00:00
Jermolene
ef1c47c3aa Fix accidental wikilinking 2017-02-05 19:58:58 +00:00
Jermolene
6282fe43af Docs capitalisation consistency
Thanks @twMat
2017-02-05 13:34:37 +00:00
Jermolene
db056a84a5 Remove obsolete code 2017-02-04 18:14:20 +00:00
Jermolene
a14b8a94df Fix JSON format for bc61f7eebf
Otherwise the JSON files cannot be imported back into TiddlyWiki
2017-02-04 18:08:47 +00:00
twMat
e20682dcfd Update title to "How to Add a New Tab to the Sidebar" (#2754)
Only title modified, from lowercase to uppercase letters.
2017-02-04 18:06:17 +00:00
Jermolene
bc61f7eebf Introduce savetrail plugin
See the readme:

“This plugin causes TiddlyWiki to continuously save the contents of
each tiddler that is changed as a JSON file. Configured correctly, the
browser will download the files silently in the background, and they
can be used as a backup in case of accidental data loss.”

Inspired by @telmiger’s comment (3) here:
https://github.com/Jermolene/TiddlyWiki5/issues/2741#issuecomment-276128
871
2017-02-04 17:37:31 +00:00
Jermolene
6c65aa2a6d Make the syncer more configurable, including names for sync adaptors
@danielo515 you may want to add a name to your sync adaptor 😄
2017-02-04 17:25:30 +00:00
Jermolene
ced9f315a1 Rename variable for clarity
It’s called an iterator in filter.js
2017-02-04 17:24:25 +00:00
Jermolene
1563f207b3 Tweaks to #2753
@twMat I felt that the “see below” part was a bit clumsy, as it jumps
quite a long way down, past three embedded videos.
2017-02-04 16:22:25 +00:00
twMat
9a01e9ab71 Update doc on how to submit PR's. (#2753)
Added note to clarify difference between submitting doc improvements and code improvements.
2017-02-04 16:18:48 +00:00
Bram Chen
3527379468 Update chinese translations for "saving" related settings (#2751) 2017-02-03 18:13:04 +00:00
Xavier Cazin
abb9f262c3 fr-FR for saver-related settings and the predefined StoryList filter (#2742)
* fr-FR translation of additional error strings

* a slightly better fr-FR translation for the Site Subtitle

* fr-FR translation for the "print page" button

* fr-FR translation for Tiddler Info Panel-related strings

* fr-FR translation for Timestamp activation strings

* fr-FR translation for TiddlerManager related strings

* fr-FR translation for an additional string related to system tiddlers

* add group-sort fields to fr-FR Types

* fixes to the fr-FR Tiddler Manager translations

* fixes fr-FR translation for timestamp-related strings

* fr-FR translation of the tiddler renaming strings

* fr-FR translation of what is the StoryList filter

* fr-FR translations for new saver-related settings
2017-01-30 21:37:45 +00:00
Jermolene
b5059c612a Adds support for autosave with the download saver
Also does some reorganisation of control panel to move “saving” related
settings together, and expose a UI for savers to plug into.

Fixes #2741
2017-01-30 18:19:28 +00:00
Jermolene
56b6781715 Fixes to license visibility
Credits to @cdent - is 2012 right, or did your work there carry on into
2013?

Addresses part of #2378
2017-01-29 21:11:30 +00:00
Jermolene
4bf626d741 As noted by @twMat over on the [mailing
list](https://groups.google.com/d/msgid/tiddlywikidev/8571ba0d-da8e-449a
-bad2-a21e3f2587aa%40googlegroups.com), GitHub has stopped recognising
TiddlyWiki’s license file — see
https://help.github.com/articles/adding-a-license-to-a-repository/.
This commit is intended to fix that
2017-01-27 22:10:18 +00:00
Duarte Ramos
8dc971a11e Pt pt translation improvements (#2719)
* Update "Open" Tab Sidebar Caption

Fix wrong translation for the "Open" tab in the page sidebar tabs

* Update SideBar.multids

* Wrong date format

Remove suffixes from dates, we don't really use any in Portuguese, and the way they were presented was currently wrong
2017-01-19 12:37:55 -07:00
dedioste
f914f0a6a2 Fix Date format for date display date in "recent" tabs (#2717)
Moved from GG MM AAAA to DD MM YYYY to ensure that the date is correctly displayed in the "Recent" tab
2017-01-19 09:00:58 -07:00
dedioste
0b14a0c24e CLA Signature for @dedioste (#2718) 2017-01-19 09:00:14 -07:00
twMat
3e40403d11 VarsWidget doc - erroneous example (#2714) 2017-01-17 08:20:06 -07:00
Tobias Beer
1b339e17bc Add "tag" attribute to keyboard widget (#2593)
* allows to define the tag for keyboard widget

* added from 5.1.14 to docs
2017-01-13 11:17:19 -07:00
Marxsal
2b90d0ab96 Doc: Community Resources: TiddlyServer (#2708) 2017-01-13 11:00:06 -07:00
Thomas Elmiger
d632e47ffe Added missing tag "Resources" (Community Resource) (#2707)
* Replacement icon stopwatch on

As discussed in issue #2690

* Replacement icon stopwatch off

As discussed in issue #2690

* Added missing tag "Resources" (Community Resource)
2017-01-13 10:59:38 -07:00
Jermolene
0e37e0cd78 Fix typo 2017-01-13 08:17:31 -07:00
Jeremy Ruston
190d4881bf Remove accented character from filename
@Marxsal just a fyi there are a lot of problems on some platform combinations with accented characters in filenames.
2017-01-13 08:17:03 -07:00
Saul D Beniquez
c3833d0232 Update cla-individual.md (#2704)
For [PR69](https://github.com/Jermolene/TiddlyWiki5/pull/2691)
2017-01-10 18:41:25 +00:00
Rizwan
ac3b67b819 Signing the CLA, Riz (#2705) 2017-01-10 18:18:16 +00:00
Jermolene
dbcda815fa Add tight-heavier theme that combines "tight" and "heavier" 2017-01-09 12:46:20 +00:00
Jermolene
74bdbb9be8 Readme updates 2017-01-09 12:46:20 +00:00
Marxsal
b152d0a727 Doc: How to concatenate text and variables (#2676)
* How to concatenate text and variables

* Adding warnings around anti-example code
2017-01-09 12:39:50 +00:00
Marxsal
00669e87da Docs: Community Resources: Noteself,Slides and Stories, TKN (#2685)
* Docs: Community Resources: Noteself,Slides and Stories, TKN

* Doc: Community Resource: Cardo

* Tweaks to community resources

* removing unnecessary new lines

* Removed spacing around question marks.

* Noteself. Removing one more space. Picked a bad day not to wear glasses.
2017-01-09 12:32:56 +00:00
Tobias Beer
d4db283d61 Refresh simple editor when empty text, e.g. hitting ENTER (#2702)
fixes #2592, missing bit of deleting the field for adding a new tag in
edit-mode

also fix for:
https://groups.google.com/forum/?fromgroups=#!topic/tiddlywiki/L6Z7gSvBWjw
2017-01-09 10:31:40 +00:00
Daniel Rodríguez Rivero
2f21cbc971 Updated tabs macro documentation (#2697)
Adding how to deal with transclusions inside the tabs itself. It is not weird that you want use tabs on a set of tiddlers that transclude other tiddlers using their own title. If you don't understand well the consequences of of what the sentence `currentTiddler variable is not affected...` this can be quite frustrating.
2017-01-04 21:40:11 +00:00
Marxsal
18280249f4 Doc: How to turn off camel case (#2687)
* Doc: How to turn off camel case

* Changed title. Added tag.
2017-01-03 18:07:48 +00:00
Jermolene
da6149cdde Include word "unique" in description of "each Operator"
Fixes #2689
2017-01-03 18:01:56 +00:00
Sylvain Comte
c16f96626e Update to latest version of google analytics code (#2671)
* trying to implement new googleanalytics tracker

* trying to put new google tracker. Not working...

* more dev options for testing

still don"t understand wants goes wrong

* New version. Seems to work

* achieved update for new tests
brought back tiddlywiki.com settings value
created a settings tab to make it easier

* adding settings to plugin

add a settings tab to plugin to make it easier to use and see which GA account is in use

* fixes bug with GA_ACCOUNT and GA_DOMAIN tiddlers containing newlines at their end, preventing plugins to work

* soft rebase on jermolene's master

* revert to oldest version of GA_account and GA_domain tiddlers - had been overwritten by ones with a new line at the end

* Integrates some @tobibeer comments

* googleanalytics.js : removed "rebranding", var declaration and console log. Did not manage to get a non-minified version of Google script. But as far as I can see, jermolene's original plugin did same way
* plugin.info : placed "readme" first
* readme : back to previous "legacy" version. No more mention to temporary fork. Added mention and link to google official code.

* signed CLA
2017-01-03 15:43:05 +00:00
Jermolene
56131e4563 It's 2017!
🥂🍾
c.f. 665d6657bb
2017-01-03 13:31:22 +00:00
Jermolene
f9b4f747a1 Updates to Danish and Dutch translations
Thanks @gernert
2017-01-02 17:45:58 +00:00
Thomas Elmiger
79ae3f8cb7 Replacement icon for timestamp on/off (#2692)
* Replacement icon stopwatch on

As discussed in issue #2690

* Replacement icon stopwatch off

As discussed in issue #2690
2017-01-02 17:38:32 +00:00
Bram Chen
c60fd4c0c6 Add chinese translations for exporting story list (#2683) 2016-12-31 13:22:12 +00:00
Marxsal
a37137d426 DOC: How to embed PDFs and other documents (#2678)
* How to embed PDFs and other documents

* Adding notes about external linking and other details
2016-12-31 13:21:32 +00:00
Jermolene
a2b465ee75 Docs: Tweaks for title conventions for resources 2016-12-31 13:20:54 +00:00
Marxsal
241f901d85 New references for Community resources. (#2677)
* New references for Community resources.

This batch includes Filter Examples by Tobias Beerand and
Gospel Bubbles by David Gifford

* Four more community resources added --
How Does Twederation Work
Ghostwriter Theme
Moments Theme
Lucky Sushi Online SHop

* Two more: Hacks by Thomas Elmiger. Forum on Reddit by Riz
2016-12-31 13:18:48 +00:00
Jermolene
7a6cbb1629 Tweaks to checkbox widget docs 2016-12-30 17:49:35 +00:00
Marxsal
94d460ef20 CheckboxWidget actions documentation (#2673)
* Add example of how to use action parameter in Checkbox Widget

* Doc: CheckboxWidget actions
2016-12-30 17:46:48 +00:00
Marxsal
5b5b25dd16 Docs: Add how-tos on putting list into table format (#2672)
* Document method(s) to format the output of a list in tabular format.

* Added  2nd CSS method for formatting as Table

* Three methods of putting lists into table form.

* Removed "probably" comment
2016-12-30 17:45:44 +00:00
Jermolene
0c2734f181 Tweak wording of exporting story list 2016-12-30 17:43:35 +00:00
Jermolene
60c6f039e4 Update link to tobibeer's tips 2016-12-30 17:42:34 +00:00
Jermolene
0e83fad837 Remove link to TW5Mall
The site has been retired by the author.
2016-12-30 17:42:34 +00:00
Marxsal
b1a5afbf15 Add an entry to the filter drop down for exporting the current story (minus advanced search) (#2670) 2016-12-30 17:42:23 +00:00
Xavier Cazin
28b7493c3c Updates to fr-FR translations (#2645)
* fr-FR translation of additional error strings

* a slightly better fr-FR translation for the Site Subtitle

* fr-FR translation for the "print page" button

* fr-FR translation for Tiddler Info Panel-related strings

* fr-FR translation for Timestamp activation strings

* fr-FR translation for TiddlerManager related strings

* fr-FR translation for an additional string related to system tiddlers

* add group-sort fields to fr-FR Types

* fixes to the fr-FR Tiddler Manager translations

* fixes fr-FR translation for timestamp-related strings

* fr-FR translation of the tiddler renaming strings
2016-12-30 17:41:05 +00:00
Jermolene
ab1b1f2cde Fix problem with beaker saver and default index pages
As discussed on the mailing list, we need to check for a URL that is
missing the default `/index.html`

https://groups.google.com/d/msg/tiddlywikidev/n6yUdu2zHWo/m32R2BuIDgAJ
2016-12-29 16:45:47 +00:00
Jermolene
eac449e8ff Release note updates 2016-12-29 12:44:42 +00:00
Jermolene
f495df6386 Tone down the colours of the "from-version" macro 2016-12-29 12:44:36 +00:00
Jermolene
2945c9abc1 Add information about Beaker Browser support 2016-12-29 12:44:12 +00:00
Jermolene
bbcc367e5a Add link to google groups search at mail-archive.com 2016-12-29 09:13:28 +00:00
Jermolene
0383b98555 Add support for other movie content types 2016-12-23 08:34:07 +00:00
Jermolene
f143164cbe Correct the name of the video parser 2016-12-22 22:07:28 +00:00
Jermolene
a1a4bf0f9d Refactoring the slicer engine for easier reuse 2016-12-22 17:46:42 +00:00
Jermolene
ba9d6187af Rename the dat saver to Beaker
It’s actually specific to the API provided by the Beaker browser, and
not a generic Dat saver
2016-12-22 08:15:16 +00:00
Jermolene
cec5522b72 Fix up the version number of the plugin library 2016-12-21 15:07:48 +00:00
Jermolene
a20da9f530 Add preliminary Dat file saver
See https://datproject.org/ and https://beakerbrowser.com/
2016-12-21 12:09:08 +00:00
Jermolene
daad0ec142 xlsx-utils: Automatically trim cell values 2016-12-21 12:09:08 +00:00
Marxsal
ed1a7e73cd Update instructions on using a PHP server, directing to a live website. (#2669)
Adding note about increasing maximum upload size.
2016-12-19 22:54:24 +00:00
Bram Chen
352d7d664c Chinese translation updates (#2666)
Typo
2016-12-19 12:22:39 +00:00
Jermolene
74107b9b8a New thumbnail for 5.1.14 2016-12-19 12:21:47 +00:00
Marxsal
7d1e3f4c35 Add docs for making a custom New Journal button (#2664)
Includes change to 'Creating journal tiddlers' to link up to new Instructional tiddler.
2016-12-19 11:27:50 +00:00
Tobias Beer
15c7d24eaa Allows adding a new tag name by typing enter (#2592)
* allows to add a new tagname hitting enter

see: https://groups.google.com/forum/#!topic/tiddlywiki/wqQ8jPYG-X4

* revert changes to vanilla/base

* added "Special Keys" to KeyboardShortcuts

* added info to Creating and editing tiddlers

did not add current version of <<.from-version "5.1.14">>  because it
would interrupt the flow. When changed from a noisy "New in 5.1.14" to
"(new in 5.1.14)" we might add the version info here

* revert setText & added inline styles to vanilla base

* remove fieldmangler

* commit initial edittemplate tags to merge master

* ok, now really revert to initial edittemplate tags

* move add tag via enter into tag-picker macro(s)
2016-12-18 20:43:26 +00:00
Mario Pietsch
e1053bf014 Toc recursion protection (#2650)
* add recursion protection first take

* fix problem with selectable expand

* ust path for toc-state variable instead of tag

* reactivate disabled macro call.
2016-12-17 15:29:03 +00:00
Arlen22
66a13cb915 TiddlyFox saver canSave() should always return true (#2626)
Whether saving is allowed should be determined by the parent side of the TiddlyFox, as this plugin can be used in many places.
2016-12-17 15:27:25 +00:00
Arlen22
1530b3e2d8 Put request handler on SimpleServer.prototype (#2627)
The request handler may be used by ExpressJS apps directly and can do most of the heavy lifting without any modification. Note that the self variable must be assignee using `[Function].bind(null,SimpleServer instance)`.
2016-12-17 15:06:10 +00:00
Jermolene
a2fe101848 Updated text reference docs 2016-12-17 12:25:43 +00:00
Nuno Mota
50d25e24f9 pt-PT translation update (#2654)
* pt-PT translation update

* Remove extra white-space

* Signing the CLA
2016-12-17 12:18:12 +00:00
Tobias Beer
e5b432a86b Allows checkbox widget to worth with indexes within data tiddlers (#2103) 2016-12-17 11:59:59 +00:00
Tobias Beer
d6d3aab36a Allow radio widget to work with indexes in a data tiddler (#2104)
* allow radio widget to set an index in a data tiddler

* updated RadioWidget docs, with same demo macro as for CheckboxWidget
in #2103
* removed docs in widget code (seems the wrong place)

* added from version to docs

* revert doc maros to master

* using wikitext-example-without-html and .tip macro now

* fix quotes
2016-12-17 11:51:24 +00:00
Jermolene
424b8a1f68 Move QR code view toolbar button 2016-12-17 11:44:24 +00:00
Matt Lauber
9c3a6976f0 #2312 Prevent move filter from wrapping (#2658)
given a list `A B C D` if I run `A B C D +[move:-1 [A]]` I get `B C A D`.  However, if I were to do `A B C D +[move:1[D]]` it doesn't wrap around, and I get `A B C D`.  This fixes that such that `A B C D +[move:-1 [A]]` gives 'A B C D`
2016-12-16 17:58:45 +00:00
Marxsal
52d32fe3fd Howto1 (#2659)
* Create One weird trick to change the sort order of sub-branches in a TOC macro

* Update and rename One weird trick to change the sort order of sub-branches in a TOC macro to How to change the sort order of sub-branches in a TOC macro

* Added .tid to file name

* Delete How to change the sort order of ...

The correct version is the one with the .tid file extension
2016-12-16 17:47:08 +00:00
Marxsal
2319c9269e Create How to widen tiddlers (aka story river) (#2651) 2016-12-16 17:40:05 +00:00
Marxsal
a393705cef Clarifying Tiddlywiki node.js launch instructions. (#2662) 2016-12-16 17:39:20 +00:00
Marxsal
4d3d7de3b5 Add example of using a text reference with a field in RevealWidget (#2660)
* Adding example of how to use a field's text references to control the RevealWidget.

* Attempting to add field "jeremy".
2016-12-16 17:38:29 +00:00
Jermolene
4a45e9d2dc Improve text reference documentation 2016-12-16 17:36:11 +00:00
Jermolene
28591965b1 Yet more refactoring of the tag macro vs template
This change re-instates the existing behaviour whereby omitting the
parameter to the “tag” macro will default to the current tiddler
2016-12-16 17:25:06 +00:00
Jeremy Ruston
7a71a87ed0 Merge pull request #2644 from BramChen/zh
Update chinese translations
2016-12-16 07:41:31 +00:00
Bram Chen
3c005a153f Add chinese translations for "Title/Exists/Prompt" and "Title/Relink/Prompt" 2016-12-16 10:24:09 +08:00
Bram Chen
24ccb215b2 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-12-16 09:52:47 +08:00
Jermolene
b4dc730575 Fix xlsx-utils startup module name
We were using the same name as one of the core startup modules.
2016-12-15 17:13:32 +00:00
Jermolene
e8bb897e26 Add support for relinking when renaming tiddlers
When renaming an existing tiddler, the edit template now shows a
checkbox that determines whether or not to relink references to the
tiddler in the list or tags fields of other tiddlers.
2016-12-15 17:13:32 +00:00
Jermolene
1bba9dc315 Reuse $tw.loadTiddlersFromPath() in --load command
Thus allowing things like tiddlywiki.files to be used with the —load
command
2016-12-15 17:13:32 +00:00
Jermolene
ad9769451d Add filename-uri-decoded support for tiddlywiki.files 2016-12-15 17:13:32 +00:00
Jermolene
74def9e080 Separate the PDF parser from the image parser
It was a bit of a hack, and made it harder to customise PDF presentation
2016-12-15 17:13:32 +00:00
Jermolene
25b2e846ce Update to Stanford JavaScript Library v1.0.6
And add their license file
2016-12-15 17:13:32 +00:00
Jeremy Ruston
fbd689368e Merge pull request #2643 from pmario/de-DE
add new tag manager texts
2016-12-01 10:51:19 +00:00
Mario Pietsch
db00c699f4 fix some typos, pointed out by Helmut. thx 2016-12-01 11:35:54 +01:00
Bram Chen
2fedd8dcd3 Add chinese translations for tiddler manager 2016-11-30 10:35:58 +08:00
Mario Pietsch
f32d05ae4b add new tag manager stuff 2016-11-29 18:42:58 +01:00
Jeremy Ruston
487dab57e6 Merge pull request #2201 from tobibeer/filter-operators-overview
updates to overall operators docs
2016-11-29 17:24:23 +00:00
Jeremy Ruston
ee486b2863 Merge pull request #2623 from BramChen/zh
Update chinese translations
2016-11-29 17:23:19 +00:00
Jeremy Ruston
b3a8780044 Merge pull request #2631 from pmario/de-DE
german language update
2016-11-29 17:23:07 +00:00
Jeremy Ruston
7736e6e4e4 Merge pull request #2641 from pmario/fix-2634
second-try / fix for 2634 week calculation
2016-11-29 17:22:23 +00:00
Mario Pietsch
b43b89f44a fix for 2634 problems with week calculation 2016-11-29 17:31:54 +01:00
Jermolene
0c6b2311ae Update release note 2016-11-29 10:29:39 +00:00
Jermolene
12ecb1fd08 Fix multids formatting 2016-11-29 10:29:32 +00:00
Bram Chen
b29c9cf829 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-29 17:44:22 +08:00
Jermolene
16bb65d17f Introduce tiddler manager 2016-11-29 08:36:07 +00:00
Jermolene
2f2ddf6c0e Update docs for tag macros 2016-11-28 21:31:09 +00:00
Jermolene
f07e0f981a Refactor tag template into an underlying macro
By refactoring the innards of the tag template into global macros, we
make it easier to re-use elements of the tag template
2016-11-28 19:17:25 +00:00
Jermolene
9a38642141 Add new "order" filter operator 2016-11-28 19:16:08 +00:00
Jermolene
a3dc3b4b98 Add new [all[tags]] filter operator 2016-11-28 19:04:04 +00:00
Jermolene
c02c3a06e0 Sort the edit content type dropdown groups more sensibly
Now we put the developer stuff at the bottom instead of the top…
2016-11-28 14:01:09 +00:00
Jermolene
cf28eeb2a1 Fix problem with checkbox widget and empty strings
If the value of `tiddler.fields[this.checkboxField]` was an empty
string then it would incorrectly fall back to the value of
`this.checkboxDefault`.
2016-11-28 13:45:41 +00:00
Jermolene
b759d82f4c @pmario's fix for #2635
This got reverted due to my git inabilities
2016-11-28 13:43:43 +00:00
Jermolene
c65d08240b Add strict mode to tag operator 2016-11-28 13:42:30 +00:00
Jermolene
c460cc03a4 Change "is" filter with blank operand to pass through arguments 2016-11-28 13:42:06 +00:00
Bram Chen
b2260c9d7e Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-28 21:11:20 +08:00
Jeremy Ruston
4e0aea288d Merge pull request #2638 from Jermolene/revert-2637-tagger
I accidentally performed a merge commit, which lost the individual commit comments, so we'll revert it and then merge it properly
2016-11-28 10:41:52 +00:00
Jeremy Ruston
a9b54d6fce Revert "Add provisional version of new tagger manager" 2016-11-28 10:40:55 +00:00
Jeremy Ruston
a85d034015 Merge pull request #2637: Introduce tiddler manager
Introduce tiddler manager
2016-11-28 10:28:12 +00:00
Jermolene
96708ecf65 Manager styling tweaks
* Make expand/collapse state be global across all tiddlers
* Remove “Show raw text” option, now that we’ve got the two expandable
areas for raw and wikified text
* Hide raw text by default
* Accentuate currently open tiddler
2016-11-28 10:01:30 +00:00
Bram Chen
940aafe2e0 Add chinese translations for timestamps on/off button 2016-11-28 13:37:11 +08:00
Bram Chen
ca179cc904 Add chinese translations of "sticky" mode for tiddler info panel 2016-11-28 13:19:10 +08:00
Bram Chen
58e12139de Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-28 11:53:24 +08:00
Jermolene
f67777161d Make manager sections be expandable 2016-11-27 23:04:54 +00:00
Jermolene
251619189e Add indentation to the manager 2016-11-27 22:35:04 +00:00
Jermolene
117bf0a0de Refactor the sidebar items into separate tiddlers
With some better styling too
2016-11-27 22:34:46 +00:00
Jermolene
e5af022bd3 Add image-picker-dropdown macro
Still need to add a way to select system images (like in the image
dropdown in tag manager)
2016-11-27 22:34:19 +00:00
Mario Pietsch
766bc7acee Fix for #2634 problem with week calculations (#2635) 2016-11-27 17:33:19 +00:00
Jermolene
b00c1c7290 Add select box for displaying tags vs. tiddlers 2016-11-27 14:52:39 +00:00
Jermolene
8e033eb0d4 Add new "all[tags]" filter operator 2016-11-27 14:52:04 +00:00
Jermolene
0b4669621a Return all tiddlers when "is" filter operand is missing 2016-11-27 14:51:51 +00:00
Jermolene
1a2ec12831 Fix problem with checkbox widget and empty strings
If the value of `tiddler.fields[this.checkboxField]` was an empty
string then it would incorrectly fall back to the value of
`this.checkboxDefault`.
2016-11-27 14:51:23 +00:00
Jermolene
9418538104 Separate the tag manager and tagger into separate tiddlers
As discussed in Hangout-101: https://www.youtube.com/watch?v=nXwCm794O6M
2016-11-27 13:53:42 +00:00
Bram Chen
14293d1b6b Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-27 09:19:10 +08:00
Jermolene
e98d324e66 Add provisional version of new tagger manager
For discussion
2016-11-26 12:48:47 +00:00
Jermolene
3bceb98119 Add support for actions attribute to CheckboxWidget 2016-11-26 08:21:58 +00:00
Jermolene
d1121787c0 Add new button to temporarily suspend timestamps
Useful when you want to make an edit but preserve the modification
date/time.
2016-11-23 18:20:31 +00:00
Jermolene
b3273bcbda Add "sticky" mode for tiddler info panel
A new option in control panel to cause the info panel to stay open
until it is explicitly closed
2016-11-23 18:17:54 +00:00
Jermolene
b86d142408 Revert accidental default to the "Heavier" theme 2016-11-23 18:15:17 +00:00
Jermolene
5bf238fc86 Use slightly bolder text for tag pills 2016-11-23 18:14:49 +00:00
Jermolene
0e57ce4090 Vanilla theme: ensure cursor is a pointer for invisible buttons 2016-11-23 18:14:25 +00:00
Jermolene
3c715c5e0d Extend require() to try appending index.js as well as .js
Better Common/JS compatibility
2016-11-23 18:13:26 +00:00
Jermolene
c8f7573a23 Make fakedom more resilient to non-string data 2016-11-22 20:24:59 +00:00
Jermolene
0f85ca3478 Add icon to "New in version" docs macro 2016-11-21 12:50:16 +00:00
Mario Pietsch
997029a78f fix typo 2016-11-16 01:24:39 +01:00
Bram Chen
3a70ddb235 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-15 08:10:23 +08:00
Jermolene
903cdc09cc Improve checking for missing titles 2016-11-14 15:37:55 +00:00
Jermolene
a485eb8588 Two improvements to xlsx-utils plugin
Add support for skipping an entire tiddler if a particular column is
blank

Add support for reading a row by column, making each of the columns
into a fieldname.

Also significantly refactored the code to break up the main, monolithic
function.
2016-11-14 15:23:15 +00:00
Jermolene
f7d81a00c2 Make "Heavier" theme heavier 2016-11-14 15:14:47 +00:00
Jermolene
632e062749 Add epub file type 2016-11-14 15:14:33 +00:00
Jermolene
b8cbc07c54 Add support for uri decoded components in tiddlywiki.files files 2016-11-14 15:14:25 +00:00
Bram Chen
8ed91f2f90 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-06 09:41:40 +08:00
Jermolene
fc483abfc8 xlsx-utils control panel: put new entities at the top of their respective lists 2016-11-05 08:35:56 +00:00
Bram Chen
62adfba68c Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-11-04 10:04:08 +08:00
Jermolene
0d0764b6ce Tweaks to "Heavier" theme 2016-11-03 22:27:14 +00:00
Jermolene
975d5346fb Introduce "Heavier" theme, with thicker fonts
Partly prompted by this piece:

https://backchannel.com/how-the-web-became-unreadable-a781ddc711b6
2016-11-03 19:11:24 +00:00
Xavier Cazin
87fbd07728 Updated fr-FR localised strings (#2632)
* fr-FR translation of additional error strings

* Better consistancy in fr-FR translations for Buttons.multids

* Fixes to fr-FR translation of Control Panel strings

* Updates to fr-FR strings in EditTemplate.multids

* fixes to fr-FR strings in Fields.multids

* added fr-FR translation of TypedTiddlers in Filters.multids

* fix fr-FR string in GettingStarted.tid

* fix fr-FR string in Import.multids

* fixes to fr-FR strings in Misc.multids

* add fr-FR translated strings in Search.multids

* fixes to fr-FR strings in Sidebars.multids

* fixes in fr-FR translated strings of the Theme Tweaks settings

* fixes fr-FR translated strings of TiddlerInfo

* fixes and additions to fr-FR translations of ModuleTypes.multids strings

* add missing fr-FR translation in PaletteColours.multids

* fixes and additions to the fr-FR-translated Help for commands

* fixes to the fr-FR-translated strings in the Download Modal

* add an fr-FR translation to the Macro Definition snippet
2016-11-01 17:55:05 +00:00
Mario Pietsch
d204688f35 de-DE text update 2016-10-27 18:03:14 +02:00
Mario Pietsch
dd8f660c4e new german text elements 2016-10-27 17:30:00 +02:00
Bram Chen
5c8844a51a Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-10-27 19:37:41 +08:00
Jermolene
8d35178bc4 Undo 664225f6fd and 56640b90bb
See the discussion at #2628
2016-10-26 21:41:41 +01:00
Bram Chen
52f02717a8 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-10-26 08:47:45 +08:00
Jermolene
56640b90bb Fix issue with tabs macro introduced by fix for #2628
I’m fixing this now to show how the tabs macro can be changed to
accommodate the change, but we may yet decide to reverse out the change
in order to maintain backwards compatibility.

One problem with changes like this is that there’s no easy way to find
out where it impacts the core UI. The tabs macro is now fixed, but
perhaps there’s more obscure things that are still broken in the core.

If we do opt to reverse the change to preserve backwards compatibility,
we could add a way to explicitly trigger the new behaviour. For
example, a new attribute `updateState=“yes”`.

Yet another alternative is to make completely new alternative to the
list widget with revised semantics, that authors can opt-in to. For
example `<$loop>`. (There was another issue we discussed a year or two
ago about adding support for an index variable which may be a candidate
for fixing at the same time).
2016-10-25 22:30:02 +01:00
Jermolene
664225f6fd Ensure list widget item title is used in getStateQualifier
Resolves a longstanding problem where the same state qualifier is
generated for every member of a list.

Fixes #2628
2016-10-25 15:34:20 +01:00
Bram Chen
5685724774 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-10-24 08:44:20 +08:00
Jermolene
cedb953f83 Missed off previous commit (54d0cb2021) 2016-10-23 23:27:35 +01:00
Jermolene
54d0cb2021 Fix background colour of import specification selector 2016-10-23 22:59:58 +01:00
Jermolene
5a361bdadc Fix content type for JSZip plugin license file 2016-10-23 22:50:14 +01:00
Jermolene
8de4583d6c Add first pass at XLSX Utilities plugin
Thanks to @stevesunypoly for help with preparing the demo spreadsheet
2016-10-23 22:49:59 +01:00
Jermolene
e9470169d8 Update full edition with recent plugins 2016-10-23 21:22:16 +01:00
Tobias Beer
9c50a223b8 Merge remote-tracking branch 'Jermolene/master' into filter-operators-overview 2016-10-22 10:17:44 +02:00
Bram Chen
fb07992fa8 Merge branch 'master' of https://github.com/Jermolene/TiddlyWiki5 into zh 2016-10-22 10:14:14 +08:00
Jermolene
7108e0d861 Add support for filtered attributes to HTML elements and widgets
Fixes #2624
2016-10-21 11:27:07 +01:00
Jermolene
c72a0b7a67 Add action-createtiddler widget
Basically the same as sending a tm-new-tiddler message except that the
newly created tiddler is not added to the story.
2016-10-21 11:26:26 +01:00
Bram Chen
3259b80114 Add chinese translations for print page button 2016-10-20 20:27:27 +08:00
Jermolene
cd5366087c Improve QR code plugin docs 2016-10-20 09:45:04 +01:00
Jermolene
0b76c327c2 Add page print button
cc @silvyn
2016-10-20 09:44:52 +01:00
Jermolene
6dc90718f0 Update tw5.com Tiddler Info/Sources to use links
Prompted by @sukima
2016-10-19 22:06:15 +01:00
Jermolene
a292a2be44 Add copy to clipboard icon 2016-10-19 14:57:19 +01:00
Jermolene
c415af13f1 bibtex plugin updates 2016-10-19 10:21:50 +01:00
Bram Chen
030c51b1f8 Update Chinese translations (#2619)
* Add chinese transaltions of descriptions for missing module types

* Update chinese transaltions of Parsing/Hint

* Add chinese transaltions for Search/TooShort
2016-10-19 10:03:28 +01:00
Jermolene
7f11c151f0 First pass at bibtex importer 2016-10-18 18:00:01 +01:00
Jermolene
5ec7250621 QR code plugin clean ups 2016-10-18 17:59:52 +01:00
Jermolene
28a25be5f7 Marginally improved qrcode icon 2016-10-18 16:39:27 +01:00
Jermolene
8e02bde938 Refinements to 87fa7f972c 2016-10-18 16:39:18 +01:00
Jermolene
5aba7292e7 Fix typo 2016-10-18 16:02:17 +01:00
Jermolene
52cef1394c Fix typo in 1b41b44684 2016-10-18 13:33:54 +01:00
Jermolene
7b535b8f31 Release note update for 5.1.14 2016-10-18 13:26:24 +01:00
Jermolene
22c1b04ee7 Added first version of QR code generator plugin 2016-10-18 09:23:47 +01:00
Jermolene
7a6d7e2a15 Refactor user interface for plugin tiddlers
* Refactored control panel “Plugins” tab to make the elements more
reusable
* Refactored the display of plugin tiddlers to use the same format as
the control panel (as suggested, I think by @danielo515), adding the
shadow tiddler listing as an overridable extension tab
* Added a new tab in the “More” sidebar providing quick access to all
installed plugins
2016-10-18 09:23:19 +01:00
Jermolene
87fa7f972c Ensure global macros are available in modals and notifications 2016-10-18 09:18:56 +01:00
Jermolene
b4b77d1681 Add new filter operators for various string encoding/decodings 2016-10-18 09:18:32 +01:00
Jermolene
b35544bf49 Extend set widget to support returning a single result from a filter
This solves the problem with extraneous double square brackets when
using the filtered set widget.
2016-10-18 09:16:47 +01:00
Jermolene
d9f301f755 Add 'formattedtext' output type to Wikify widget 2016-10-18 09:13:52 +01:00
Jermolene
2f590a365e Expose document location via $:/info/url/* info tiddlers 2016-10-18 09:12:55 +01:00
Jermolene
8fbcfaa79b Make the editor preview scrollable in fixed height mode
Fixes #2616
2016-10-18 08:46:48 +01:00
Jermolene
accd4a1b65 Fix regexp performance problem introduced in c7b31b0242
This fixes a problem introduced in
c7b31b0242.

The changes by @tobibeer inadvertently made the regular expression
evaluation significantly more expensive because of lookahead. The is
less elegant but reverts the performance problem.
2016-10-17 19:08:01 +01:00
Jermolene
537cfcbf79 Addendum to #2610
* Ensure we don’t try to read tiddlers from `.meta` files
* Improve docs
2016-10-15 18:06:17 +01:00
Jermolene
1b41b44684 Improve support for bulk loading tiddlers under Node.js
Fixes #2610
2016-10-15 16:23:17 +01:00
FND
d7b6917638 Clarify WebDAV documentation (#2613) 2016-10-15 14:19:19 +01:00
Jermolene
892a1f560e Trap JSON syntax errors during import
Fixes #2609
2016-10-13 14:16:55 +01:00
Jermolene
da298f037d Remove extraneous console.log()
Fixing f97c1226aa
2016-10-12 15:50:43 +01:00
Jermolene
f97c1226aa Prevent HTML parser from mis-recognising email addresses
Email addresses such as `<jeremy@example.com>` were being erroneously
parsed as HTML tags.

Fixes #2604
2016-10-12 13:17:53 +01:00
Jermolene
989cee5059 Suppress search results if search string is too short
Fixes #2603
2016-10-11 09:27:26 +01:00
Jermolene
e724bc6120 Extend docs template for operators to allow for "from-version" field 2016-10-11 09:26:50 +01:00
Jermolene
ffcbcbfa82 Add new 'minlength' operator
Fixes #1493
2016-10-11 09:26:20 +01:00
Devin Weaver
f1090d749e Fix str.length strEndsWith bug (#2572)
This was some how missed in dev testing I guess. @buggyj suggested this.

Should fix #2571
2016-10-08 14:06:30 +01:00
Tobias Beer
b9299309cc Fixes #2076 single line macros shouldn't need terminating line break 2016-10-08 13:44:30 +01:00
Tobias Beer
bf253a603b Removed unused vars + some whitespace (#2106) 2016-10-08 13:32:14 +01:00
Tobias Beer
f575389d89 Update wikiparserrules operator for no operand (#2193)
* return all wikiparserrules w/o operand

* simpler layout & code / updated instruction details

Also wanted to link each rule to the official docs using a dictionary at
`$:/language/Docs/ParserRules/`. However, without #2194 this is not
doable.
2016-10-08 13:04:11 +01:00
Jermolene
994432e28e Merge branch 'Serj-Aleks-patch-1' 2016-10-08 12:27:35 +01:00
Jermolene
6079563ff8 Merge branch 'patch-1' of https://github.com/Serj-Aleks/TiddlyWiki5 into Serj-Aleks-patch-1 2016-10-08 12:27:09 +01:00
Jermolene
ff6b0bd5dc Merge branch 'zakrec-patch-9' 2016-10-08 12:24:44 +01:00
Jermolene
23060f92f0 Merge branch 'patch-9' of https://github.com/zakrec/TiddlyWiki5 into zakrec-patch-9 2016-10-08 12:24:17 +01:00
Tobias Beer
d038e0bc1b Filter titles in new fieldname popup by entered string (#2585) 2016-10-08 12:18:19 +01:00
Tobias Beer
3486acaec6 Remove old titles from story on save (#2587)
fix for #2381
2016-10-08 12:17:27 +01:00
Jermolene
be574b713e Fixes #2588 2016-10-08 12:10:07 +01:00
Tobias Beer
808587f1c1 Fixes #2311 allows ctrl-enter to add tag and field (#2590)
fixes #2311

demo: http://2311.tiddlyspot.com
2016-10-08 11:53:20 +01:00
Tobias Beer
c7b31b0242 allows textPrimitives.anyLetter in syslink (#2596)
* allows textPrimitives.anyLetter in syslink

now only supports anyletter as per request by @jermolene
2016-10-08 11:51:07 +01:00
Jermolene
641eeaf611 Refresh action widgets before invoking them
Fixes #2599, at least partially.
2016-10-08 10:19:09 +01:00
Jermolene
c4e13bc94a Add icon and message handler for print button
I’m inclined to think it’s not worth adding a corresponding page
control button because it’ll require a lot of tiddlers for the
translation etc.
2016-10-08 10:10:54 +01:00
Jermolene
ee66d1a1af Add a documentation macro for marking version numbers
By signalling features that are new in 5.1.14 we can include
documentation updates for the new version when we build updates to
5.1.13
2016-10-08 10:05:34 +01:00
Jermolene
e4f3d56bdc Correct reference to missing variable 2016-10-06 14:50:54 +01:00
Jermolene
20daaae7e8 Make $tw.utils.stringifyList() resilient to null values in the array 2016-09-30 18:28:12 +01:00
Jermolene
b867b7487e Fix tw2-plugin-check warning so that more than one plugin is displayed 2016-09-30 18:27:45 +01:00
Jermolene
4be5f0abe8 Switch highlight plugin under Node.js to use DOM rather than raw HTML
Hi @welford I wondered if you could kindly review this commit, since
you authored the original code? Before this commit, I was running into
a crash when running `prerelease-bld.sh` from
`build.jermolene.github.io`, caused by using raw HTML for the
highlighted block. Switching to the fake dom seems to fix things, but
I’d like a second pair of eyes.
2016-09-28 11:34:15 +01:00
Jermolene
292d653880 Fix typo affecting created/creator fields when deleting field
Fixes #2579
2016-09-28 11:18:58 +01:00
Jermolene
d86e4043c2 Some sample .ENEX files for testing 2016-09-26 12:32:57 +01:00
Daniel Rodríguez Rivero
0409151801 Update How to customise the password prompt.tid (#2580)
A minor typo corrected. Minor but a link broker!
2016-09-22 13:14:58 +02:00
nameanyone
e1cc285151 Align the right edge of the preview (#2583)
Currently it's 3px off to the left compared to the above element.
2016-09-22 12:37:22 +02:00
Jermolene
ffc0899f52 Move the copyright.md file to the root of the repo
Hopefully GitHub might start to recognise TiddlyWiki’s license
2016-09-14 08:30:23 +01:00
Jermolene
2d9aa12aa8 Increase size of icons in Advanced Search/Filter
An easy one.

Fixes #2464
2016-09-13 19:26:37 +01:00
Jermolene
fc898ae64a Fix broken macro in "Release 5.1.9"
This local `<<colour-picker>>` macro was overwritten by the new core
macro of the same name

Fixes #2573
2016-09-07 11:12:30 +01:00
Daniel Rodríguez Rivero
975bc30079 Update PluginMechanism.tid (#2574)
Added link to sematic versioning
2016-09-06 14:53:38 +01:00
Jermolene
06b7de415c Ensure cancel button in login prompt doesn't also submit form
Fixes #2561
2016-08-29 19:13:25 +01:00
Jermolene
3ad8cf59bd Add column count CSS macro
Still needs prefixing for Firefox
2016-08-27 14:24:07 +01:00
Jermolene
5f0a1dd967 Revision of 03db25cf38
We should only fallback to the classic storyview if a storyview was
specified; if none was specified then we shouldn’t use a storyview.
2016-08-27 14:24:07 +01:00
Steve Schneider
0788145cb5 CLA signature for @stevesunypoly (#2557) 2016-08-26 18:13:26 +01:00
Jermolene
03db25cf38 Fallback to "classic" if specified storyview not found
Fixes #2555
2016-08-26 11:34:43 +01:00
Jermolene
4d74f52202 Remove extraneous text
Copy/paste whoops.
2016-08-20 17:11:54 +01:00
Jermolene
05b32728bc Allow browser-based file reading to use deserializers for binary files 2016-08-20 17:09:22 +01:00
Jermolene
3a2ea9b98b Register .xlsx filetype 2016-08-20 17:08:44 +01:00
Jermolene
da1905b789 Revise default for Buffer in the browser
Back in 7d12d89a0a we added support for
Node.js global `Buffer` object, explicitly exposing it to the module
loader sandbox. The value `{}` was used in the browser, but is now
causing problems with libraries that perform feature detection.
2016-08-20 17:08:24 +01:00
Daniel Rodríguez Rivero
845e8294cd Update How to customise the password prompt.tid (#2543)
Fixed small typo on the use of a template.
2016-08-20 15:46:50 +01:00
Jermolene
f079b31334 Fix further issue with highlight.js brush handling 2016-08-18 10:32:21 +01:00
Jermolene
ee9d19d299 Fix problem with highlight plugin language brushes
TiddlyWiki passes the MIME type of the tiddler to highlight.js as the
"language brush", but it turns out that highlight.js doesn't actually
understand MIME types. This commit introduces a configuration mapping
between common MIME types and highlight.js language brushes

Fixes #2535
2016-08-18 09:07:06 +01:00
Jermolene
ffae85140f Fix state cleanup for excise toolbar button
We were deleting the wrong tiddler
2016-08-18 08:59:09 +01:00
Jermolene
ba2f831d8c Fix parsing of multids files
The old code required a space after the colon separating the title
fragment from the text, and didn’t trim the strings. The new code is
more tolerant, by not requiring the space, and trimming the strings.
2016-08-18 08:58:54 +01:00
Jermolene
7bc7f643b6 Remove extraneous console.log 2016-08-16 15:48:25 +01:00
Jermolene
18dd8d4433 Fix problem with lazy loading under Node.js
Fixes #2514
2016-08-16 15:48:14 +01:00
Jermolene
118b2ffe2f Fix lazy.sh to serve the edition *tw5.com-server*
As per the existing documentation:
http://tiddlywiki.com/#Scripts%20for%20TiddlyWiki%20on%20Node.js
2016-08-16 15:46:53 +01:00
Jermolene
4be6efdb4e Fix JSON typo 2016-08-16 15:45:17 +01:00
Jermolene
e20bce5450 Add experimental support for RTL languages
This commit permits language plugins to carry the field
“text-direction” with the value “rtl” to trigger right-to-left layout
of the entire page. We also adjust the sidebar layout to work in RTL
mode.

There are still a number of problems to be addressed:

* Brackets and other punctuation incorrectly placed within en-GB UI text
* System tiddler titles are rendered semi-back-to-front (eg
`languages/ca-ES/:$`)

Starting to address #1845 and the discussion in #2523.
2016-08-15 19:47:26 +01:00
nameanyone
12e3e8b489 Fix a link to GroupedTiddlers (#2537) 2016-08-15 18:42:26 +01:00
HC
b7c416d340 @hchaase CLA signature.md (#2534)
sry for the delay.. forgot to sign
2016-08-11 14:59:03 +01:00
Jermolene
8b60dbb81d Ensure page background colour takes shows through transparent background images
Fixes #2529
2016-08-09 09:36:17 +01:00
Przemek Wesołek
9bd002e41d Change the order of static content generation. (#2528)
Prevents the `--rendertiddlers` removing the `static.css` file rendered earlier,
similar to https://github.com/Jermolene/TiddlyWiki5/pull/1207
and https://github.com/Jermolene/TiddlyWiki5/issues/703.
2016-08-08 11:16:48 +01:00
DoronTzur
10d5aecf3f @DoronTzur CLA signature (#2526) 2016-08-08 09:43:25 +01:00
Jermolene
4eed18496f Extend editor link button to create external links and missing links
Fixes #2521
2016-08-07 10:18:53 +01:00
Jermolene
959a7ac485 Add icon for foldbar visibility control
Fixes #2525
2016-08-07 10:16:44 +01:00
Jermolene
8f6abf534f Add descriptions for missing module types 2016-08-06 21:38:17 +01:00
Jermolene
b96377099a Add Hebrew translation
Many thanks to @DoronTzur
2016-08-06 15:56:25 +01:00
Jermolene
486b326ea9 Update for building 5.1.14-prerelease 2016-08-06 15:03:13 +01:00
Jermolene
7326a3a4cc Only call isReady() for sync adaptors that support it
Fixes #2522
2016-08-06 14:45:33 +01:00
Jermolene
08cfa88249 Fix problem with unsafe use of String.prototype.replace()
We were using `String.prototype.replace()` without addressing the
wrinkle that dollar signs in the replacement string have special
handling. This caused problems in situations where the replacement
string is derived from user input and contains dollar signs.

Fixes #2517
2016-08-06 14:45:33 +01:00
Przemek Wesołek
82694e1426 @jest CLA signature (#2524) 2016-08-06 14:38:01 +01:00
Sergey A. Shishkin
570c1b20f0 Update cla-individual.md 2016-07-28 18:08:59 +02:00
Jermolene
1da8a32837 Retrospectively update release node for 5.1.13 2016-07-25 11:11:28 +01:00
zakrec
8ec8c5103e Update cla-individual.md
Signing the CLA
2016-02-21 07:56:08 +01:00
Tobias Beer
a5d380006e updates to overall operators docs
* info on default input being `all[tiddlers]`
* clearer column layout
* removed fiddly done button
2016-01-10 10:13:23 +01:00
674 changed files with 28352 additions and 2368 deletions

View File

@@ -5,7 +5,7 @@
# Optional parameter is the username for signing edits
node ./tiddlywiki.js \
editions/server \
editions/tw5.com-server \
--verbose \
--server 8080 $:/core/save/lazy-images text/plain text/html $1 $2\
|| exit 1

View File

@@ -251,29 +251,35 @@ $tw.utils.parseDate = function(value) {
// Stringify an array of tiddler titles into a list string
$tw.utils.stringifyList = function(value) {
var result = [];
for(var t=0; t<value.length; t++) {
if(value[t].indexOf(" ") !== -1) {
result.push("[[" + value[t] + "]]");
} else {
result.push(value[t]);
if($tw.utils.isArray(value)) {
var result = [];
for(var t=0; t<value.length; t++) {
var entry = value[t] || "";
if(entry.indexOf(" ") !== -1) {
result.push("[[" + entry + "]]");
} else {
result.push(entry);
}
}
return result.join(" ");
} else {
return value || "";
}
return result.join(" ");
};
// Parse a string array from a bracketted list. For example "OneTiddler [[Another Tiddler]] LastOne"
$tw.utils.parseStringArray = function(value) {
if(typeof value === "string") {
var memberRegExp = /(?:^|[^\S\xA0])(?:\[\[(.*?)\]\])(?=[^\S\xA0]|$)|([\S\xA0]+)/mg,
results = [],
results = [], names = {},
match;
do {
match = memberRegExp.exec(value);
if(match) {
var item = match[1] || match[2];
if(item !== undefined && results.indexOf(item) === -1) {
if(item !== undefined && !$tw.utils.hop(names,item)) {
results.push(item);
names[item] = true;
}
}
} while(match);
@@ -514,6 +520,9 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
if(options.canCancel) {
children.push(dm("button",{
text: $tw.language.getString("Encryption/Cancel"),
attributes: {
type: "button"
},
eventListeners: [{
name: "click",
handlerFunction: function(event) {
@@ -635,9 +644,25 @@ $tw.utils.Crypto = function() {
Execute the module named 'moduleName'. The name can optionally be relative to the module named 'moduleRoot'
*/
$tw.modules.execute = function(moduleName,moduleRoot) {
var name = moduleName[0] === "." ? $tw.utils.resolvePath(moduleName,moduleRoot) : moduleName,
moduleInfo = $tw.modules.titles[name] || $tw.modules.titles[name + ".js"] || $tw.modules.titles[moduleName] || $tw.modules.titles[moduleName + ".js"] ,
tiddler = $tw.wiki.getTiddler(name) || $tw.wiki.getTiddler(name + ".js") || $tw.wiki.getTiddler(moduleName) || $tw.wiki.getTiddler(moduleName + ".js") ,
var name = moduleName;
if(moduleName.charAt(0) === ".") {
name = $tw.utils.resolvePath(moduleName,moduleRoot)
}
if(!$tw.modules.titles[name]) {
if($tw.modules.titles[name + ".js"]) {
name = name + ".js";
} else if($tw.modules.titles[name + "/index.js"]) {
name = name + "/index.js";
} else if($tw.modules.titles[moduleName]) {
name = moduleName;
} else if($tw.modules.titles[moduleName + ".js"]) {
name = moduleName + ".js";
} else if($tw.modules.titles[moduleName + "/index.js"]) {
name = moduleName + "/index.js";
}
}
var moduleInfo = $tw.modules.titles[name],
tiddler = $tw.wiki.getTiddler(name),
_exports = {},
sandbox = {
module: {exports: _exports},
@@ -648,7 +673,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
clearInterval: clearInterval,
setTimeout: setTimeout,
clearTimeout: clearTimeout,
Buffer: $tw.browser ? {} : Buffer,
Buffer: $tw.browser ? undefined : Buffer,
$tw: $tw,
require: function(title) {
return $tw.modules.execute(title, name);
@@ -802,6 +827,7 @@ taking precedence to the right
*/
$tw.Tiddler = function(/* [fields,] fields */) {
this.fields = Object.create(null);
this.cache = Object.create(null);
for(var c=0; c<arguments.length; c++) {
var arg = arguments[c],
src = (arg instanceof $tw.Tiddler) ? arg.fields : arg;
@@ -902,7 +928,7 @@ $tw.Wiki = function(options) {
// Delete a tiddler
this.deleteTiddler = function(title) {
// Uncomment the following line for detailed logs of all tiddler deletions
// console.log("Deleting",title,tiddler)
// console.log("Deleting",title)
if($tw.utils.hop(tiddlers,title)) {
delete tiddlers[title];
this.clearCache(title);
@@ -1261,15 +1287,15 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/tids","tiddlerdeserializer",{
for(var t=0; t<lines.length; t++) {
var line = lines[t];
if(line.charAt(0) !== "#") {
var colonPos= line.indexOf(": ");
var colonPos= line.indexOf(":");
if(colonPos !== -1) {
var tiddler = $tw.utils.extend(Object.create(null),fields);
tiddler.title = (tiddler.title || "") + line.substr(0,colonPos);
tiddler.title = (tiddler.title || "") + line.substr(0,colonPos).trim();
if(titles.indexOf(tiddler.title) !== -1) {
console.log("Warning: .multids file contains multiple definitions for " + tiddler.title);
}
titles.push(tiddler.title);
tiddler.text = line.substr(colonPos + 2);
tiddler.text = line.substr(colonPos + 2).trim();
tiddlers.push(tiddler);
}
}
@@ -1294,8 +1320,8 @@ $tw.modules.define("$:/boot/tiddlerdeserializer/html","tiddlerdeserializer",{
});
$tw.modules.define("$:/boot/tiddlerdeserializer/json","tiddlerdeserializer",{
"application/json": function(text,fields) {
var tiddlers = JSON.parse(text);
return tiddlers;
var data = JSON.parse(text);
return $tw.utils.isArray(data) ? data : [data];
}
});
@@ -1448,17 +1474,26 @@ $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),
metafile = filepath + ".meta",
metadata;
if(ext !== ".json" && tiddlers.length === 1 && fs.existsSync(metafile)) {
metadata = fs.readFileSync(metafile,"utf8");
if(metadata) {
tiddlers = [$tw.utils.parseFields(metadata,tiddlers[0])];
}
if(ext !== ".json" && tiddlers.length === 1) {
metadata = $tw.loadMetadataForFile(filepath);
tiddlers = [$tw.utils.extend({},tiddlers[0],metadata)];
}
return {filepath: filepath, type: type, tiddlers: tiddlers, hasMetaFile: !!metadata};
};
/*
Load the metadata fields in the .meta file corresponding to a particular file
*/
$tw.loadMetadataForFile = function(filepath) {
var metafilename = filepath + ".meta";
if(fs.existsSync(metafilename)) {
return $tw.utils.parseFields(fs.readFileSync(metafilename,"utf8") || "");
} else {
return null;
}
};
/*
A default set of files for TiddlyWiki to ignore during load.
This matches what NPM ignores, and adds "*.meta" to ignore tiddler
@@ -1478,44 +1513,7 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
var files = fs.readdirSync(filepath);
// Look for a tiddlywiki.files file
if(files.indexOf("tiddlywiki.files") !== -1) {
// If so, process the files it describes
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
// First the tiddlers
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
var type = tidInfo.fields.type || "text/plain",
typeInfo = $tw.config.contentTypeInfo[type],
pathname = path.resolve(filepath,tidInfo.file),
text = fs.readFileSync(pathname,typeInfo ? typeInfo.encoding : "utf8");
if(tidInfo.isTiddlerFile) {
var fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text) || [];
$tw.utils.each(fileTiddlers,function(tiddler) {
$tw.utils.extend(tiddler,tidInfo.fields);
if(tidInfo.prefix) {
tiddler.text = tidInfo.prefix + tiddler.text;
}
if(tidInfo.suffix) {
tiddler.text = tiddler.text + tidInfo.suffix;
}
});
tiddlers.push({tiddlers: fileTiddlers});
} else {
if(tidInfo.prefix) {
text = tidInfo.prefix + text;
}
if(tidInfo.suffix) {
text = text + tidInfo.suffix;
}
tidInfo.fields.text = text;
tiddlers.push({tiddlers: [tidInfo.fields]});
}
});
// Then any recursive directories
$tw.utils.each(filesInfo.directories,function(dirPath) {
var pathname = path.resolve(filepath,dirPath);
if(fs.existsSync(pathname) && fs.statSync(pathname).isDirectory()) {
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(pathname,excludeRegExp));
}
});
Array.prototype.push.apply(tiddlers,$tw.loadTiddlersFromSpecification(filepath,excludeRegExp));
} else {
// If not, read all the files in the directory
$tw.utils.each(files,function(file) {
@@ -1531,6 +1529,106 @@ $tw.loadTiddlersFromPath = function(filepath,excludeRegExp) {
return tiddlers;
};
/*
Load all the tiddlers defined by a `tiddlywiki.files` specification file
filepath: pathname of the directory containing the specification file
*/
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
var tiddlers = [];
// Read the specification
var filesInfo = JSON.parse(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
// Helper to process a file
var processFile = function(filename,isTiddlerFile,fields) {
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
type = (extInfo || {}).type || fields.type || "text/plain",
typeInfo = $tw.config.contentTypeInfo[type] || {},
pathname = path.resolve(filepath,filename),
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
metadata = $tw.loadMetadataForFile(pathname) || {},
fileTiddlers;
if(isTiddlerFile) {
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
} else {
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
}
var combinedFields = $tw.utils.extend({},fields,metadata);
$tw.utils.each(fileTiddlers,function(tiddler) {
$tw.utils.each(combinedFields,function(fieldInfo,name) {
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
tiddler[name] = fieldInfo;
} else {
var value = tiddler[name];
switch(fieldInfo.source) {
case "filename":
value = path.basename(filename);
break;
case "filename-uri-decoded":
value = decodeURIComponent(path.basename(filename));
break;
case "basename":
value = path.basename(filename,path.extname(filename));
break;
case "basename-uri-decoded":
value = decodeURIComponent(path.basename(filename,path.extname(filename)));
break;
case "extname":
value = path.extname(filename);
break;
case "created":
value = new Date(fs.statSync(pathname).birthtime);
break;
case "modified":
value = new Date(fs.statSync(pathname).mtime);
break;
}
if(fieldInfo.prefix) {
value = fieldInfo.prefix + value;
}
if(fieldInfo.suffix) {
value = value + fieldInfo.suffix;
}
tiddler[name] = value;
}
});
});
tiddlers.push({tiddlers: fileTiddlers});
};
// Process the listed tiddlers
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
if(tidInfo.prefix && tidInfo.suffix) {
tidInfo.fields.text = {prefix: tidInfo.prefix,suffix: tidInfo.suffix};
} else if(tidInfo.prefix) {
tidInfo.fields.text = {prefix: tidInfo.prefix};
} else if(tidInfo.suffix) {
tidInfo.fields.text = {suffix: tidInfo.suffix};
}
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
});
// Process any listed directories
$tw.utils.each(filesInfo.directories,function(dirSpec) {
// Read literal directories directly
if(typeof dirSpec === "string") {
var pathname = path.resolve(filepath,dirSpec);
if(fs.existsSync(pathname) && fs.statSync(pathname).isDirectory()) {
tiddlers.push.apply(tiddlers,$tw.loadTiddlersFromPath(pathname,excludeRegExp));
}
} else {
// Process directory specifier
var dirPath = path.resolve(filepath,dirSpec.path),
files = fs.readdirSync(dirPath),
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
metaRegExp = /^.*\.meta$/;
for(var t=0; t<files.length; t++) {
var filename = files[t];
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
processFile(dirPath + path.sep + filename,dirSpec.isTiddlerFile,dirSpec.fields);
}
}
}
});
return tiddlers;
};
/*
Load the tiddlers from a plugin folder, and package them up into a proper JSON plugin tiddler
*/
@@ -1853,8 +1951,14 @@ $tw.boot.startup = function(options) {
$tw.utils.registerFileType("video/mp4","base64",".mp4");
$tw.utils.registerFileType("audio/mp3","base64",".mp3");
$tw.utils.registerFileType("audio/mp4","base64",[".mp4",".m4a"]);
$tw.utils.registerFileType("text/markdown","utf8",[".md",".markdown"],{deserializerType:"text/x-markdown"});
$tw.utils.registerFileType("text/x-markdown","utf8",[".md",".markdown"]);
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
$tw.utils.registerFileType("application/enex+xml","utf8",".enex");
$tw.utils.registerFileType("application/vnd.openxmlformats-officedocument.wordprocessingml.document","base64",".docx");
$tw.utils.registerFileType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","base64",".xlsx");
$tw.utils.registerFileType("application/vnd.openxmlformats-officedocument.presentationml.presentation","base64",".pptx");
$tw.utils.registerFileType("application/x-bibtex","utf8",".bib");
$tw.utils.registerFileType("application/epub+zip","base64",".epub");
// Create the wiki store for the app
$tw.wiki = new $tw.Wiki();
// Install built in tiddler fields modules
@@ -2041,13 +2145,14 @@ $tw.hooks.addHook = function(hookName,definition) {
/*
Invoke the hook by key
*/
$tw.hooks.invokeHook = function(hookName, value) {
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
var args = Array.prototype.slice.call(arguments,1);
if($tw.utils.hop($tw.hooks.names,hookName)) {
for (var i = 0; i < $tw.hooks.names[hookName].length; i++) {
value = $tw.hooks.names[hookName][i](value);
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
}
}
return value;
return args[0];
};
/////////////////////////// Main boot function to decrypt tiddlers and then startup

View File

@@ -1,42 +1,60 @@
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
if(typeof module!="undefined"&&module.exports)module.exports=sjcl;
sjcl.cipher.aes=function(a){this.h[0][0][0]||this.z();var b,c,d,e,f=this.h[0][4],g=this.h[1];b=a.length;var h=1;if(b!==4&&b!==6&&b!==8)throw new sjcl.exception.invalid("invalid aes key size");this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(a%b===0||b===8&&a%b===4){c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255];if(a%b===0){c=c<<8^c>>>24^h<<24;h=h<<1^(h>>7)*283}}d[a]=d[a-b]^c}for(b=0;a;b++,a--){c=d[b&3?a:a-4];e[b]=a<=4||b<4?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^
g[3][f[c&255]]}};
sjcl.cipher.aes.prototype={encrypt:function(a){return this.I(a,0)},decrypt:function(a){return this.I(a,1)},h:[[[],[],[],[],[]],[[],[],[],[],[]]],z:function(){var a=this.h[0],b=this.h[1],c=a[4],d=b[4],e,f,g,h=[],i=[],k,j,l,m;for(e=0;e<0x100;e++)i[(h[e]=e<<1^(e>>7)*283)^e]=e;for(f=g=0;!c[f];f^=k||1,g=i[g]||1){l=g^g<<1^g<<2^g<<3^g<<4;l=l>>8^l&255^99;c[f]=l;d[l]=f;j=h[e=h[k=h[f]]];m=j*0x1010101^e*0x10001^k*0x101^f*0x1010100;j=h[l]*0x101^l*0x1010100;for(e=0;e<4;e++){a[e][f]=j=j<<24^j>>>8;b[e][l]=m=m<<24^m>>>8}}for(e=
0;e<5;e++){a[e]=a[e].slice(0);b[e]=b[e].slice(0)}},I:function(a,b){if(a.length!==4)throw new sjcl.exception.invalid("invalid aes block size");var c=this.a[b],d=a[0]^c[0],e=a[b?3:1]^c[1],f=a[2]^c[2];a=a[b?1:3]^c[3];var g,h,i,k=c.length/4-2,j,l=4,m=[0,0,0,0];g=this.h[b];var n=g[0],o=g[1],p=g[2],q=g[3],r=g[4];for(j=0;j<k;j++){g=n[d>>>24]^o[e>>16&255]^p[f>>8&255]^q[a&255]^c[l];h=n[e>>>24]^o[f>>16&255]^p[a>>8&255]^q[d&255]^c[l+1];i=n[f>>>24]^o[a>>16&255]^p[d>>8&255]^q[e&255]^c[l+2];a=n[a>>>24]^o[d>>16&
255]^p[e>>8&255]^q[f&255]^c[l+3];l+=4;d=g;e=h;f=i}for(j=0;j<4;j++){m[b?3&-j:j]=r[d>>>24]<<24^r[e>>16&255]<<16^r[f>>8&255]<<8^r[a&255]^c[l++];g=d;d=e;e=f;f=a;a=g}return m}};
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===undefined?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(a.length===0||b.length===0)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return d===32?a.concat(b):sjcl.bitArray.P(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;
if(b===0)return 0;return(b-1)*32+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(a.length*32<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;if(c>0&&b)a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1);return a},partial:function(a,b,c){if(a===32)return b;return(c?b|0:b<<32-a)+a*0x10000000000},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return false;var c=0,d;for(d=0;d<a.length;d++)c|=
a[d]^b[d];return c===0},P:function(a,b,c,d){var e;e=0;if(d===undefined)d=[];for(;b>=32;b-=32){d.push(c);c=0}if(b===0)return d.concat(a);for(e=0;e<a.length;e++){d.push(c|a[e]>>>b);c=a[e]<<32-b}e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,b+a>32?c:d.pop(),1));return d},k:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++){if((d&3)===0)e=a[d/4];b+=String.fromCharCode(e>>>24);e<<=8}return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++){d=d<<8|a.charCodeAt(c);if((c&3)===3){b.push(d);d=0}}c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,d*4)}};
sjcl.codec.base64={F:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.F,g=0,h=sjcl.bitArray.bitLength(a);if(c)f=f.substr(0,62)+"-_";for(c=0;d.length*6<h;){d+=f.charAt((g^a[c]>>>e)>>>26);if(e<6){g=a[c]<<6-e;e+=26;c++}else{g<<=6;e-=6}}for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d=0,e=sjcl.codec.base64.F,f=0,g;if(b)e=e.substr(0,62)+"-_";for(b=0;b<a.length;b++){g=e.indexOf(a.charAt(b));
if(g<0)throw new sjcl.exception.invalid("this isn't base64!");if(d>26){d-=26;c.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&c.push(sjcl.bitArray.partial(d&56,f,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.a[0]||this.z();if(a){this.n=a.n.slice(0);this.i=a.i.slice(0);this.e=a.e}else this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.n=this.N.slice(0);this.i=[];this.e=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.i=sjcl.bitArray.concat(this.i,a);b=this.e;a=this.e=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.D(c.splice(0,16));return this},finalize:function(){var a,b=this.i,c=this.n;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.e/
4294967296));for(b.push(this.e|0);b.length;)this.D(b.splice(0,16));this.reset();return c},N:[],a:[],z:function(){function a(e){return(e-Math.floor(e))*0x100000000|0}var b=0,c=2,d;a:for(;b<64;c++){for(d=2;d*d<=c;d++)if(c%d===0)continue a;if(b<8)this.N[b]=a(Math.pow(c,0.5));this.a[b]=a(Math.pow(c,1/3));b++}},D:function(a){var b,c,d=a.slice(0),e=this.n,f=this.a,g=e[0],h=e[1],i=e[2],k=e[3],j=e[4],l=e[5],m=e[6],n=e[7];for(a=0;a<64;a++){if(a<16)b=d[a];else{b=d[a+1&15];c=d[a+14&15];b=d[a&15]=(b>>>7^b>>>18^
b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(j>>>6^j>>>11^j>>>25^j<<26^j<<21^j<<7)+(m^j&(l^m))+f[a];n=m;m=l;l=j;j=k+b|0;k=i;i=h;h=g;g=b+(h&i^k&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+k|0;e[4]=e[4]+j|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}};
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,i=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];if(i<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;f<4&&k>>>8*f;f++);if(f<15-i)f=15-i;c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.H(a,b,c,d,e,f);g=sjcl.mode.ccm.J(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),i=f.clamp(b,h-e),k=f.bitSlice(b,
h-e);h=(h-e)/8;if(g<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;b<4&&h>>>8*b;b++);if(b<15-g)b=15-g;c=f.clamp(c,8*(15-b));i=sjcl.mode.ccm.J(a,i,c,k,e,b);a=sjcl.mode.ccm.H(a,i.data,c,d,e,b);if(!f.equal(i.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");return i.data},H:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,i=h.k;e/=8;if(e%2||e<4||e>16)throw new sjcl.exception.invalid("ccm: invalid tag length");if(d.length>0xffffffff||b.length>0xffffffff)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;if(c<=65279)g=[h.partial(16,c)];else if(c<=0xffffffff)g=h.concat([h.partial(16,65534)],[c]);g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(i(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(i(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,e*8)},J:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.k;var i=b.length,k=h.bitLength(b);c=h.concat([h.partial(8,
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!i)return{tag:d,data:[]};for(g=0;g<i;g+=4){c[3]++;e=a.encrypt(c);b[g]^=e[0];b[g+1]^=e[1];b[g+2]^=e[2];b[g+3]^=e[3]}return{tag:d,data:h.clamp(b,k)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.B,i=sjcl.bitArray,k=i.k,j=[0,0,0,0];c=h(a.encrypt(c));var l,m=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4){l=b.slice(g,g+4);j=k(j,l);m=m.concat(k(c,a.encrypt(k(c,l))));c=h(c)}l=b.slice(g);b=i.bitLength(l);g=a.encrypt(k(c,[0,0,0,b]));l=i.clamp(k(l.concat([0,0,0]),g),b);j=k(j,k(l.concat([0,0,0]),g));j=a.encrypt(k(j,k(c,h(c))));
if(d.length)j=k(j,f?d:sjcl.mode.ocb2.pmac(a,d));return m.concat(i.concat(l,i.clamp(j,e)))},decrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.B,h=sjcl.bitArray,i=h.k,k=[0,0,0,0],j=g(a.encrypt(c)),l,m,n=sjcl.bitArray.bitLength(b)-e,o=[];d=d||[];for(c=0;c+4<n/32;c+=4){l=i(j,a.decrypt(i(j,b.slice(c,c+4))));k=i(k,l);o=o.concat(l);j=g(j)}m=n-c*32;l=a.encrypt(i(j,[0,0,0,m]));l=i(l,h.clamp(b.slice(c),
m).concat([0,0,0]));k=i(k,l);k=a.encrypt(i(k,i(j,g(j))));if(d.length)k=i(k,f?d:sjcl.mode.ocb2.pmac(a,d));if(!h.equal(h.clamp(k,e),h.bitSlice(b,n)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return o.concat(h.clamp(l,m))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.B,e=sjcl.bitArray,f=e.k,g=[0,0,0,0],h=a.encrypt([0,0,0,0]);h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4){h=d(h);g=f(g,a.encrypt(f(h,b.slice(c,c+4))))}b=b.slice(c);if(e.bitLength(b)<128){h=f(h,d(h));b=e.concat(b,[2147483648|0,0,
0,0])}g=f(g,b);return a.encrypt(f(d(f(h,d(h))),g))},B:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^(a[0]>>>31)*135]}};sjcl.misc.hmac=function(a,b){this.M=b=b||sjcl.hash.sha256;var c=[[],[]],d=b.prototype.blockSize/32;this.l=[new b,new b];if(a.length>d)a=b.hash(a);for(b=0;b<d;b++){c[0][b]=a[b]^909522486;c[1][b]=a[b]^1549556828}this.l[0].update(c[0]);this.l[1].update(c[1])};
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a,b){a=(new this.M(this.l[0])).update(a,b).finalize();return(new this.M(this.l[1])).update(a).finalize()};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;if(d<0||c<0)throw sjcl.exception.invalid("invalid params to pbkdf2");if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,i,k=[],j=sjcl.bitArray;for(i=1;32*k.length<(d||1);i++){e=f=a.encrypt(j.concat(b,[i]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}k=k.concat(e)}if(d)k=j.clamp(k,d);return k};
sjcl.random={randomWords:function(a,b){var c=[];b=this.isReady(b);var d;if(b===0)throw new sjcl.exception.notReady("generator isn't seeded");else b&2&&this.U(!(b&1));for(b=0;b<a;b+=4){(b+1)%0x10000===0&&this.L();d=this.w();c.push(d[0],d[1],d[2],d[3])}this.L();return c.slice(0,a)},setDefaultParanoia:function(a){this.t=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.q[c],h=this.isReady(),i=0;d=this.G[c];if(d===undefined)d=this.G[c]=this.R++;if(g===undefined)g=this.q[c]=
0;this.q[c]=(this.q[c]+1)%this.b.length;switch(typeof a){case "number":if(b===undefined)b=1;this.b[g].update([d,this.u++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if(c==="[object Uint32Array]"){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{if(c!=="[object Array]")i=1;for(c=0;c<a.length&&!i;c++)if(typeof a[c]!="number")i=1}if(!i){if(b===undefined)for(c=b=0;c<a.length;c++)for(e=a[c];e>0;){b++;e>>>=1}this.b[g].update([d,this.u++,2,b,f,a.length].concat(a))}break;case "string":if(b===
undefined)b=a.length;this.b[g].update([d,this.u++,3,b,f,a.length]);this.b[g].update(a);break;default:i=1}if(i)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.j[g]+=b;this.f+=b;if(h===0){this.isReady()!==0&&this.K("seeded",Math.max(this.g,this.f));this.K("progress",this.getProgress())}},isReady:function(a){a=this.C[a!==undefined?a:this.t];return this.g&&this.g>=a?this.j[0]>80&&(new Date).valueOf()>this.O?3:1:this.f>=a?2:0},getProgress:function(a){a=
this.C[a?a:this.t];return this.g>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.m){if(window.addEventListener){window.addEventListener("load",this.o,false);window.addEventListener("mousemove",this.p,false)}else if(document.attachEvent){document.attachEvent("onload",this.o);document.attachEvent("onmousemove",this.p)}else throw new sjcl.exception.bug("can't attach event");this.m=true}},stopCollectors:function(){if(this.m){if(window.removeEventListener){window.removeEventListener("load",
this.o,false);window.removeEventListener("mousemove",this.p,false)}else if(window.detachEvent){window.detachEvent("onload",this.o);window.detachEvent("onmousemove",this.p)}this.m=false}},addEventListener:function(a,b){this.r[a][this.Q++]=b},removeEventListener:function(a,b){var c;a=this.r[a];var d=[];for(c in a)a.hasOwnProperty(c)&&a[c]===b&&d.push(c);for(b=0;b<d.length;b++){c=d[b];delete a[c]}},b:[new sjcl.hash.sha256],j:[0],A:0,q:{},u:0,G:{},R:0,g:0,f:0,O:0,a:[0,0,0,0,0,0,0,0],d:[0,0,0,0],s:undefined,
t:6,m:false,r:{progress:{},seeded:{}},Q:0,C:[0,48,64,96,128,192,0x100,384,512,768,1024],w:function(){for(var a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}return this.s.encrypt(this.d)},L:function(){this.a=this.w().concat(this.w());this.s=new sjcl.cipher.aes(this.a)},T:function(a){this.a=sjcl.hash.sha256.hash(this.a.concat(a));this.s=new sjcl.cipher.aes(this.a);for(a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}},U:function(a){var b=[],c=0,d;this.O=b[0]=(new Date).valueOf()+3E4;for(d=
0;d<16;d++)b.push(Math.random()*0x100000000|0);for(d=0;d<this.b.length;d++){b=b.concat(this.b[d].finalize());c+=this.j[d];this.j[d]=0;if(!a&&this.A&1<<d)break}if(this.A>=1<<this.b.length){this.b.push(new sjcl.hash.sha256);this.j.push(0)}this.f-=c;if(c>this.g)this.g=c;this.A++;this.T(b)},p:function(a){sjcl.random.addEntropy([a.x||a.clientX||a.offsetX||0,a.y||a.clientY||a.offsetY||0],2,"mouse")},o:function(){sjcl.random.addEntropy((new Date).valueOf(),2,"loadtime")},K:function(a,b){var c;a=sjcl.random.r[a];
var d=[];for(c in a)a.hasOwnProperty(c)&&d.push(a[c]);for(c=0;c<d.length;c++)d[c](b)}};try{var s=new Uint32Array(32);crypto.getRandomValues(s);sjcl.random.addEntropy(s,1024,"crypto['getRandomValues']")}catch(t){}
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},encrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.c({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.c(f,c);c=f.adata;if(typeof f.salt==="string")f.salt=sjcl.codec.base64.toBits(f.salt);if(typeof f.iv==="string")f.iv=sjcl.codec.base64.toBits(f.iv);if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||typeof a==="string"&&f.iter<=100||f.ts!==64&&f.ts!==96&&f.ts!==128||f.ks!==128&&f.ks!==192&&f.ks!==0x100||f.iv.length<
2||f.iv.length>4)throw new sjcl.exception.invalid("json encrypt: invalid parameters");if(typeof a==="string"){g=sjcl.misc.cachedPbkdf2(a,f);a=g.key.slice(0,f.ks/32);f.salt=g.salt}if(typeof b==="string")b=sjcl.codec.utf8String.toBits(b);if(typeof c==="string")c=sjcl.codec.utf8String.toBits(c);g=new sjcl.cipher[f.cipher](a);e.c(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return e.encode(f)},decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.c(e.c(e.c({},e.defaults),e.decode(b)),
c,true);var f;c=b.adata;if(typeof b.salt==="string")b.salt=sjcl.codec.base64.toBits(b.salt);if(typeof b.iv==="string")b.iv=sjcl.codec.base64.toBits(b.iv);if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||typeof a==="string"&&b.iter<=100||b.ts!==64&&b.ts!==96&&b.ts!==128||b.ks!==128&&b.ks!==192&&b.ks!==0x100||!b.iv||b.iv.length<2||b.iv.length>4)throw new sjcl.exception.invalid("json decrypt: invalid parameters");if(typeof a==="string"){f=sjcl.misc.cachedPbkdf2(a,b);a=f.key.slice(0,b.ks/32);b.salt=f.salt}if(typeof c===
"string")c=sjcl.codec.utf8String.toBits(c);f=new sjcl.cipher[b.cipher](a);c=sjcl.mode[b.mode].decrypt(f,b.ct,b.iv,c,b.ts);e.c(d,b);d.key=a;return sjcl.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+
sjcl.codec.base64.fromBits(a[b],1)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");b[d[2]]=
d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4])}return b},c:function(a,b,c){if(a===undefined)a={};if(b===undefined)return a;var d;for(d in b)if(b.hasOwnProperty(d)){if(c&&a[d]!==undefined&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},W:function(a,b){var c={},d;for(d in a)if(a.hasOwnProperty(d)&&a[d]!==b[d])c[d]=a[d];return c},V:function(a,b){var c={},d;for(d=0;d<b.length;d++)if(a[b[d]]!==undefined)c[b[d]]=
a[b[d]];return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.S={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.S,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===undefined?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
sjcl.cipher.aes=function(a){this.s[0][0][0]||this.O();var b,c,d,e,f=this.s[0][4],g=this.s[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
255]]};
sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},s:[[[],[],[],[],[]],[[],[],[],[],[]]],O:function(){var a=this.s[0],b=this.s[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,n,m,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(m=g^g<<1^g<<2^g<<3^g<<4,m=m>>8^m&255^99,c[f]=m,d[m]=f,n=h[e=h[l=h[f]]],p=0x1010101*n^0x10001*e^0x101*l^0x1010100*f,n=0x101*h[m]^0x1010100*m,e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8;for(e=
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,r=[0,0,0,0];h=a.s[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=
0;4>m;m++)r[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r}
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.$(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.$(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b=b&31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return!1;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
c},$:function(a,b,c,d){var e;e=0;for(void 0===d&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},i:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a=a+"00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
sjcl.codec.base32={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",X:"0123456789ABCDEFGHIJKLMNOPQRSTUV",BITS:32,BASE:5,REMAINING:27,fromBits:function(a,b,c){var d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f="",g=0,h=sjcl.codec.base32.B,k=0,l=sjcl.bitArray.bitLength(a);c&&(h=sjcl.codec.base32.X);for(c=0;f.length*d<l;)f+=h.charAt((k^a[c]>>>g)>>>e),g<d?(k=a[c]<<d-g,g+=e,c++):(k<<=d,g-=d);for(;f.length&7&&!b;)f+="=";return f},toBits:function(a,b){a=a.replace(/\s|=/g,"").toUpperCase();var c=sjcl.codec.base32.BITS,
d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f=[],g,h=0,k=sjcl.codec.base32.B,l=0,n,m="base32";b&&(k=sjcl.codec.base32.X,m="base32hex");for(g=0;g<a.length;g++){n=k.indexOf(a.charAt(g));if(0>n){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+m+"!");}h>e?(h-=e,f.push(l^n>>>h),l=n<<c-h):(h+=d,l^=n<<c-h)}h&56&&f.push(sjcl.bitArray.partial(h&56,l,1));return f}};
sjcl.codec.base32hex={fromBits:function(a,b){return sjcl.codec.base32.fromBits(a,b,1)},toBits:function(a){return sjcl.codec.base32.toBits(a,1)}};
sjcl.codec.base64={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.B,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.B,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++){h=f.indexOf(a.charAt(d));
if(0>h)throw new sjcl.exception.invalid("this isn't base64!");26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.O();a?(this.F=a.F.slice(0),this.A=a.A.slice(0),this.l=a.l):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.F=this.Y.slice(0);this.A=[];this.l=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.A=sjcl.bitArray.concat(this.A,a);b=this.l;a=this.l=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffff<a)throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits");if("undefined"!==typeof Uint32Array){var d=new Uint32Array(c),e=0;for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,d.subarray(16*e,
16*(e+1))),e+=1;c.splice(0,16*e)}else for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,c.splice(0,16));return this},finalize:function(){var a,b=this.A,c=this.F,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.l/0x100000000));for(b.push(this.l|0);b.length;)u(this,b.splice(0,16));this.reset();return c},Y:[],b:[],O:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}for(var b=0,c=2,d,e;64>b;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e=
!1;break}e&&(8>b&&(this.Y[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++)}}};
function u(a,b){var c,d,e,f=a.F,g=a.b,h=f[0],k=f[1],l=f[2],n=f[3],m=f[4],p=f[5],r=f[6],q=f[7];for(c=0;64>c;c++)16>c?d=b[c]:(d=b[c+1&15],e=b[c+14&15],d=b[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+b[c&15]+b[c+9&15]|0),d=d+q+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(r^m&(p^r))+g[c],q=r,r=p,p=m,m=n+d|0,n=l,l=k,k=h,h=d+(k&l^n&(k^l))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;f[0]=f[0]+h|0;f[1]=f[1]+k|0;f[2]=f[2]+l|0;f[3]=f[3]+n|0;f[4]=f[4]+m|0;f[5]=f[5]+p|0;f[6]=f[6]+r|0;f[7]=
f[7]+q|0}
sjcl.mode.ccm={name:"ccm",G:[],listenProgress:function(a){sjcl.mode.ccm.G.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.G.indexOf(a);-1<a&&sjcl.mode.ccm.G.splice(a,1)},fa:function(a){var b=sjcl.mode.ccm.G.slice(),c;for(c=0;c<b.length;c+=1)b[c](a)},encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];if(7>k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,
8*(15-f));b=sjcl.mode.ccm.V(a,b,c,d,e,f);g=sjcl.mode.ccm.C(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.C(a,k,c,l,e,b);a=sjcl.mode.ccm.V(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");
return k.data},na:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.i;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;b<g.length;b+=4)d=a.encrypt(k(d,g.slice(b,b+4).concat([0,0,0])));return d},V:function(a,b,c,d,e,f){var g=sjcl.bitArray,h=g.i;e/=8;if(e%2||4>e||16<e)throw new sjcl.exception.invalid("ccm: invalid tag length");
if(0xffffffff<d.length||0xffffffff<b.length)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");c=sjcl.mode.ccm.na(a,d,c,e,g.bitLength(b)/8,f);for(d=0;d<b.length;d+=4)c=a.encrypt(h(c,b.slice(d,d+4).concat([0,0,0])));return g.clamp(c,8*e)},C:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.i;var k=b.length,l=h.bitLength(b),n=k/50,m=n;c=h.concat([h.partial(8,f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!k)return{tag:d,data:[]};for(g=0;g<k;g+=4)g>n&&(sjcl.mode.ccm.fa(g/
k),n+=m),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,l)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.S,k=sjcl.bitArray,l=k.i,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));
d.length&&(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.S,h=sjcl.bitArray,k=h.i,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,r=sjcl.bitArray.bitLength(b)-e,q=[];d=d||[];for(c=0;c+4<r/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),q=q.concat(m),n=g(n);p=r-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,
0,0]));l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));if(!h.equal(h.clamp(l,e),h.bitSlice(b,r)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return q.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.S,e=sjcl.bitArray,f=e.i,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);
return a.encrypt(f(d(f(h,d(h))),g))},S:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.C(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.C(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},ka:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.i;e=[0,0,
0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},j:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.ka(b,a);return b},C:function(a,b,c,d,e,f){var g,h,k,l,n,m,p,r,q=sjcl.bitArray;m=c.length;p=q.bitLength(c);r=q.bitLength(d);h=q.bitLength(e);
g=b.encrypt([0,0,0,0]);96===h?(e=e.slice(0),e=q.concat(e,[1])):(e=sjcl.mode.gcm.j(g,[0,0,0,0],e),e=sjcl.mode.gcm.j(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.j(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.j(g,h,c));for(l=0;l<m;l+=4)n[3]++,k=b.encrypt(n),c[l]^=k[0],c[l+1]^=k[1],c[l+2]^=k[2],c[l+3]^=k[3];c=q.clamp(c,p);a&&(d=sjcl.mode.gcm.j(g,h,c));a=[Math.floor(r/0x100000000),r&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.j(g,d,a);k=b.encrypt(e);
d[0]^=k[0];d[1]^=k[1];d[2]^=k[2];d[3]^=k[3];return{tag:q.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.W=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.w=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.w[0].update(c[0]);this.w[1].update(c[1]);this.R=new b(this.w[0])};
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){if(this.aa)throw new sjcl.exception.invalid("encrypt on already updated hmac called!");this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.R=new this.W(this.w[0]);this.aa=!1};sjcl.misc.hmac.prototype.update=function(a){this.aa=!0;this.R.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.R.finalize(),a=(new this.W(this.w[1])).update(a).finalize();this.reset();return a};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E4;if(0>d||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++)for(f=a.encrypt(f),h=0;h<f.length;h++)e[h]^=f[h];l=l.concat(e)}d&&(l=n.clamp(l,d));return l};
sjcl.prng=function(a){this.c=[new sjcl.hash.sha256];this.m=[0];this.P=0;this.H={};this.N=0;this.U={};this.Z=this.f=this.o=this.ha=0;this.b=[0,0,0,0,0,0,0,0];this.h=[0,0,0,0];this.L=void 0;this.M=a;this.D=!1;this.K={progress:{},seeded:{}};this.u=this.ga=0;this.I=1;this.J=2;this.ca=0x10000;this.T=[0,48,64,96,128,192,0x100,384,512,768,1024];this.da=3E4;this.ba=80};
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;if(d===this.u)throw new sjcl.exception.notReady("generator isn't seeded");if(d&this.J){d=!(d&this.I);e=[];var f=0,g;this.Z=e[0]=(new Date).valueOf()+this.da;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.c.length&&(e=e.concat(this.c[g].finalize()),f+=this.m[g],this.m[g]=0,d||!(this.P&1<<g));g++);this.P>=1<<this.c.length&&(this.c.push(new sjcl.hash.sha256),this.m.push(0));this.f-=f;f>this.o&&(this.o=
f);this.P++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.L=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.h[d]=this.h[d]+1|0,!this.h[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.ca&&y(this),e=z(this),c.push(e[0],e[1],e[2],e[3]);y(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){if(0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b)throw new sjcl.exception.invalid("Setting paranoia=0 will ruin your security; use it only for testing");this.M=a},addEntropy:function(a,
b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.H[c],h=this.isReady(),k=0;d=this.U[c];void 0===d&&(d=this.U[c]=this.ha++);void 0===g&&(g=this.H[c]=0);this.H[c]=(this.H[c]+1)%this.c.length;switch(typeof a){case "number":void 0===b&&(b=1);this.c[g].update([d,this.N++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else for("[object Array]"!==c&&(k=1),c=0;c<a.length&&!k;c++)"number"!==typeof a[c]&&
(k=1);if(!k){if(void 0===b)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e=e>>>1;this.c[g].update([d,this.N++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.c[g].update([d,this.N++,3,b,f,a.length]);this.c[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.f+=b;h===this.u&&(this.isReady()!==this.u&&A("seeded",Math.max(this.o,this.f)),A("progress",this.getProgress()))},
isReady:function(a){a=this.T[void 0!==a?a:this.M];return this.o&&this.o>=a?this.m[0]>this.ba&&(new Date).valueOf()>this.Z?this.J|this.I:this.I:this.f>=a?this.J|this.u:this.u},getProgress:function(a){a=this.T[a?a:this.M];return this.o>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.D){this.a={loadTimeCollector:B(this,this.ma),mouseCollector:B(this,this.oa),keyboardCollector:B(this,this.la),accelerometerCollector:B(this,this.ea),touchCollector:B(this,this.qa)};if(window.addEventListener)window.addEventListener("load",
this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event");
this.D=!0}},stopCollectors:function(){this.D&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",
this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.D=!1)},addEventListener:function(a,b){this.K[a][this.ga++]=b},removeEventListener:function(a,b){var c,d,e=this.K[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},la:function(){C(this,1)},oa:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&this.addEntropy([b,c],2,"mouse");C(this,0)},qa:function(a){a=
a.touches[0]||a.changedTouches[0];this.addEntropy([a.pageX||a.clientX,a.pageY||a.clientY],1,"touch");C(this,0)},ma:function(){C(this,2)},ea:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&this.addEntropy(b,1,"accelerometer")}a&&this.addEntropy(a,2,"accelerometer");C(this,0)}};
function A(a,b){var c,d=sjcl.random.K[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function C(a,b){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?a.addEntropy(window.performance.now(),b,"loadtime"):a.addEntropy((new Date).valueOf(),b,"loadtime")}function y(a){a.b=z(a).concat(z(a));a.L=new sjcl.cipher.aes(a.b)}function z(a){for(var b=0;4>b&&(a.h[b]=a.h[b]+1|0,!a.h[b]);b++);return a.L.encrypt(a.h)}
function B(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
a:try{var D,E,F,G;if(G="undefined"!==typeof module&&module.exports){var H;try{H=require("crypto")}catch(a){H=null}G=E=H}if(G&&E.randomBytes)D=E.randomBytes(128),D=new Uint32Array((new Uint8Array(D)).buffer),sjcl.random.addEntropy(D,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){F=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(F);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(F);
else break a;sjcl.random.addEntropy(F,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))}
sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ja:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.g({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.g(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
4<f.iv.length)throw new sjcl.exception.invalid("json encrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.g(d,f);d.key=a;f.ct="ccm"===f.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&
b instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.encrypt(g,b,f.iv,c,f.ts):sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,b,c,d){var e=sjcl.json,f=e.ja.apply(e,arguments);return e.encode(f)},ia:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.g(e.g(e.g({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===
typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)throw new sjcl.exception.invalid("json decrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f="ccm"===
b.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&b.ct instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.decrypt(g,b.ct,b.iv,b.tag,f,b.ts):sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.g(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.ia(a,e.decode(b),c,d)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+
b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");
null!=d[3]?b[d[2]]=parseInt(d[3],10):null!=d[4]?b[d[2]]=d[2].match(/^(ct|adata|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):null!=d[5]&&(b[d[2]]="true"===d[5])}return b},g:function(a,b,c){void 0===a&&(a={});if(void 0===b)return a;for(var d in b)if(b.hasOwnProperty(d)){if(c&&void 0!==a[d]&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},sa:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},ra:function(a,
b){var c={},d;for(d=0;d<b.length;d++)void 0!==a[b[d]]&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.pa={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.pa,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=void 0===b.salt?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});

View File

@@ -3,30 +3,31 @@ type: text/plain
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
Copyright © Jeremy Ruston 2004-2007
Copyright © UnaMesa Association 2007-2016
Copyright (c) 2004-2007, Jeremy Ruston
Copyright (c) 2007-2017, UnaMesa Association
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the UnaMesa Association nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,15 @@
title: $:/core/images/copy-clipboard
tags: $:/tags/Image
<svg class="tc-image-copy-clipboard tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
<g fill-rule="evenodd">
<rect x="40" y="40" width="33" height="8" rx="4"></rect>
<rect x="40" y="82" width="17" height="8" rx="4"></rect>
<rect x="40" y="54" width="17" height="8" rx="4"></rect>
<rect x="40" y="96" width="33" height="8" rx="4"></rect>
<rect x="40" y="68" width="12" height="8" rx="4"></rect>
<path d="M40,16 L23.9992458,16 C19.5813843,16 16,19.5907123 16,24 C16,24.0016363 16.0000005,24.0032725 16.0000015,24.0049086 C16.0000005,24.0065441 16,24.0081803 16,24.0098166 L16,119.990183 C16,119.99182 16.0000005,119.993456 16.0000015,119.995092 C16.0000005,119.996727 16,119.998364 16,120 C16,124.409288 19.5813843,128 23.9992458,128 L104.000754,128 C106.205061,128 108.203844,127.105595 109.652065,125.659342 C111.102424,124.21251 112,122.214511 112,120.007595 L112,103.992405 C112,99.5776607 108.418278,96 104,96 C99.5907123,96 96,99.5783218 96,103.992405 L96,112 L32,112 L32,32 L96,32 L96,40.0075946 C96,44.4223393 99.581722,48 104,48 C108.409288,48 112,44.4216782 112,40.0075946 L112,23.9924054 C112,21.7851587 111.104671,19.7871591 109.657101,18.3409203 C108.203844,16.8944047 106.205061,16 104.000754,16 L88,16 C88,11.5907123 84.4151006,8 79.9929031,8 L48.0070969,8 C43.5881712,8 40,11.581722 40,16 Z M44,14.9958262 C44,12.7889923 45.7964248,11 48.0000255,11 L79.9999745,11 C82.2091276,11 84,12.7965212 84,14.9958262 L84,19.0041738 C84,21.2110077 82.2035752,23 79.9999745,23 L48.0000255,23 C45.7908724,23 44,21.2034788 44,19.0041738 L44,14.9958262 Z"></path>
<rect x="62" y="64" width="66" height="16" rx="8"></rect>
<path d="M60.6568542,85.6568542 L76.6568542,69.6568543 L65.3431458,69.6568542 L81.3431458,85.6568542 C84.4673401,88.7810486 89.5326599,88.7810486 92.6568542,85.6568542 C95.7810486,82.5326599 95.7810486,77.4673401 92.6568542,74.3431458 L76.6568542,58.3431458 C73.5326599,55.2189514 68.4673401,55.2189514 65.3431458,58.3431457 L49.3431458,74.3431457 C46.2189514,77.4673401 46.2189514,82.5326599 49.3431457,85.6568542 C52.4673401,88.7810486 57.5326599,88.7810486 60.6568542,85.6568542 L60.6568542,85.6568542 Z" transform="translate(71.000000, 72.000000) rotate(-90.000000) translate(-71.000000, -72.000000) "></path>
</g>
</svg>

9
core/images/list.tid Normal file
View File

@@ -0,0 +1,9 @@
title: $:/core/images/list
tags: $:/tags/Image
<svg class="tc-image-list tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
<g fill-rule="evenodd">
<path d="M0.719999312,185.568543 C2.21955287,181.862817 3.0452019,177.812144 3.0452019,173.568542 C3.0452019,155.891545 -11.2816707,141.568542 -28.9547636,141.568542 L-60.9548326,141.568542 C-78.6344937,141.568542 -92.9547981,155.895431 -92.9547981,173.568542 C-92.9547981,191.24554 -78.6279255,205.568542 -60.9548326,205.568542 L-28.9547636,205.568542 C-27.593228,205.568542 -26.2516158,205.483573 -24.9349335,205.31865 C-31.5207556,201.78951 -36.8809788,196.272192 -40.2126959,189.568542 L-60.9493786,189.568542 C-69.7889277,189.568542 -76.9547981,182.407041 -76.9547981,173.568542 C-76.9547981,164.731986 -69.7994766,157.568542 -60.9493786,157.568542 L-28.9602176,157.568542 C-20.1206685,157.568542 -12.9547981,164.730044 -12.9547981,173.568542 C-12.9547981,176.946528 -14.0004297,180.080016 -15.7866505,182.6623 C-13.6856165,184.473592 -10.949961,185.568542 -7.9585771,185.568542 L0.720002586,185.568542 Z" transform="translate(-44.954798, 173.568542) rotate(-225.000000) translate(44.954798, -173.568542) "></path>
<path d="M87.7480315,128 L23.9992458,128 C19.5813843,128 16,124.409247 16,119.993027 L16,8.00697327 C16,3.58484404 19.5881049,0 23.9992458,0 L104.000754,0 C108.418616,0 112,3.59075293 112,8.00697327 L112,104 L91.2492027,104 C90.2848199,104 89.410573,104.391703 88.7768998,105.025201 C88.1373658,105.661376 87.7480315,106.53563 87.7480315,107.501171 L87.7480315,128 Z M95.7480315,127.879386 L111.627417,112 L95.7480315,112 L95.7480315,127.879386 Z M40,15.5089165 C40,13.5709954 41.5636015,12 43.4998101,12 L98.5001899,12 C100.433082,12 102,13.5614718 102,15.5089165 L102,16.4910835 C102,18.4290046 100.436399,20 98.5001899,20 L43.4998101,20 C41.5669183,20 40,18.4385282 40,16.4910835 L40,15.5089165 Z M32,22 C35.3137085,22 38,19.3137085 38,16 C38,12.6862915 35.3137085,10 32,10 C28.6862915,10 26,12.6862915 26,16 C26,19.3137085 28.6862915,22 32,22 Z M40,31.5089165 C40,29.5709954 41.5636015,28 43.4998101,28 L98.5001899,28 C100.433082,28 102,29.5614718 102,31.5089165 L102,32.4910835 C102,34.4290046 100.436399,36 98.5001899,36 L43.4998101,36 C41.5669183,36 40,34.4385282 40,32.4910835 L40,31.5089165 Z M40,47.5089165 C40,45.5709954 41.5636015,44 43.4998101,44 L98.5001899,44 C100.433082,44 102,45.5614718 102,47.5089165 L102,48.4910835 C102,50.4290046 100.436399,52 98.5001899,52 L43.4998101,52 C41.5669183,52 40,50.4385282 40,48.4910835 L40,47.5089165 Z M40,63.5089165 C40,61.5709954 41.5636015,60 43.4998101,60 L98.5001899,60 C100.433082,60 102,61.5614718 102,63.5089165 L102,64.4910835 C102,66.4290046 100.436399,68 98.5001899,68 L43.4998101,68 C41.5669183,68 40,66.4385282 40,64.4910835 L40,63.5089165 Z M40,79.5089165 C40,77.5709954 41.5636015,76 43.4998101,76 L98.5001899,76 C100.433082,76 102,77.5614718 102,79.5089165 L102,80.4910835 C102,82.4290046 100.436399,84 98.5001899,84 L43.4998101,84 C41.5669183,84 40,82.4385282 40,80.4910835 L40,79.5089165 Z M40,95.5089165 C40,93.5709954 41.5636015,92 43.4998101,92 L98.5001899,92 C100.433082,92 102,93.5614718 102,95.5089165 L102,96.4910835 C102,98.4290046 100.436399,100 98.5001899,100 L43.4998101,100 C41.5669183,100 40,98.4385282 40,96.4910835 L40,95.5089165 Z M40,111.508916 C40,109.570995 41.5680474,108 43.4972017,108 L76.5027983,108 C78.4342495,108 80,109.561472 80,111.508916 L80,112.491084 C80,114.429005 78.4319526,116 76.5027983,116 L43.4972017,116 C41.5657505,116 40,114.438528 40,112.491084 L40,111.508916 Z M32,38 C35.3137085,38 38,35.3137085 38,32 C38,28.6862915 35.3137085,26 32,26 C28.6862915,26 26,28.6862915 26,32 C26,35.3137085 28.6862915,38 32,38 Z M32,54 C35.3137085,54 38,51.3137085 38,48 C38,44.6862915 35.3137085,42 32,42 C28.6862915,42 26,44.6862915 26,48 C26,51.3137085 28.6862915,54 32,54 Z M32,70 C35.3137085,70 38,67.3137085 38,64 C38,60.6862915 35.3137085,58 32,58 C28.6862915,58 26,60.6862915 26,64 C26,67.3137085 28.6862915,70 32,70 Z M32,86 C35.3137085,86 38,83.3137085 38,80 C38,76.6862915 35.3137085,74 32,74 C28.6862915,74 26,76.6862915 26,80 C26,83.3137085 28.6862915,86 32,86 Z M32,102 C35.3137085,102 38,99.3137085 38,96 C38,92.6862915 35.3137085,90 32,90 C28.6862915,90 26,92.6862915 26,96 C26,99.3137085 28.6862915,102 32,102 Z M32,118 C35.3137085,118 38,115.313708 38,112 C38,108.686292 35.3137085,106 32,106 C28.6862915,106 26,108.686292 26,112 C26,115.313708 28.6862915,118 32,118 Z"></path>
</g>
</svg>

View File

@@ -0,0 +1,12 @@
title: $:/core/images/print-button
tags: $:/tags/Image
<svg class="tc-image-print-button tc-image-button" viewBox="0 0 128 128" width="22pt" height="22pt">
<g fill-rule="evenodd">
<path d="M112,71 L112,30.5 L111.96811,30.5 L111.96811,30.5 C111.932942,28.4998414 111.151676,26.510538 109.625176,24.9840387 L86.9982489,2.35711116 C85.3482153,0.707077645 83.1589869,-0.071534047 81,0.0201838424 L81,0 L23.9992458,0 C19.5808867,0 16,3.58213437 16,8.00092105 L16,71 L24,71 L24,8 L81,8 L81,22.4996539 C81,26.9216269 84.5818769,30.5 89.0003461,30.5 L104,30.5 L104,71 L112,71 Z"></path>
<rect x="32" y="36" width="64" height="8" rx="4"></rect>
<rect x="32" y="52" width="64" height="8" rx="4"></rect>
<rect x="32" y="20" width="40" height="8" rx="4"></rect>
<path d="M0,80.0054195 C0,71.1658704 7.15611005,64 16.0008841,64 L111.999116,64 C120.83616,64 128,71.1553215 128,80.0054195 L128,111.99458 C128,120.83413 120.84389,128 111.999116,128 L16.0008841,128 C7.16383982,128 0,120.844679 0,111.99458 L0,80.0054195 Z M104,96 C108.418278,96 112,92.418278 112,88 C112,83.581722 108.418278,80 104,80 C99.581722,80 96,83.581722 96,88 C96,92.418278 99.581722,96 104,96 Z"></path>
</g>
</svg>

View File

@@ -0,0 +1,8 @@
title: $:/core/images/timestamp-off
tags: $:/tags/Image
<svg class="tc-image-timestamp-off tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
<g fill-rule="evenodd">
<path d="M58.25 11C26.08 11 0 37.082 0 69.25s26.08 58.25 58.25 58.25c32.175 0 58.25-26.082 58.25-58.25S90.425 11 58.25 11zm0 100.5C34.914 111.5 16 92.586 16 69.25 16 45.92 34.914 27 58.25 27s42.25 18.92 42.25 42.25c0 23.336-18.914 42.25-42.25 42.25zM49.704 10c-2.762 0-5-2.24-5-5-.004-2.756 2.238-5 5-5H66.69c2.762 0 5.002 2.24 5 5 .006 2.757-2.238 5-5 5H49.705z"/><path d="M58.25 35.88c-18.777 0-33.998 15.224-33.998 33.998 0 18.773 15.22 34.002 33.998 34.002 18.784 0 34.002-15.23 34.002-34.002 0-18.774-15.218-33.998-34.002-33.998zm-3.03 50.123H44.196v-34H55.22v34zm16.976 0H61.17v-34h11.025v34z"/>
</g>
</svg>

View File

@@ -0,0 +1,8 @@
title: $:/core/images/timestamp-on
tags: $:/tags/Image
<svg class="tc-image-timestamp-on tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
<g fill-rule="evenodd">
<path d="M58.25 11C26.08 11 0 37.082 0 69.25s26.08 58.25 58.25 58.25c32.175 0 58.25-26.082 58.25-58.25S90.425 11 58.25 11zm0 100.5C34.914 111.5 16 92.586 16 69.25 16 45.92 34.914 27 58.25 27s42.25 18.92 42.25 42.25c0 23.336-18.914 42.25-42.25 42.25zM49.704 10c-2.762 0-5-2.24-5-5-.004-2.756 2.238-5 5-5H66.69c2.762 0 5.002 2.24 5 5 .006 2.757-2.238 5-5 5H49.705z"/><path d="M13.41 27.178c-2.116 1.775-5.27 1.498-7.045-.613-1.772-2.11-1.498-5.27.616-7.047l9.95-8.348c2.115-1.774 5.27-1.5 7.045.618 1.775 2.108 1.498 5.27-.616 7.043l-9.95 8.348zM102.983 27.178c2.116 1.775 5.27 1.498 7.045-.613 1.772-2.11 1.498-5.27-.616-7.047l-9.95-8.348c-2.114-1.774-5.27-1.5-7.044.618-1.775 2.108-1.498 5.27.616 7.043l9.95 8.348zM65.097 71.072c0 3.826-3.09 6.928-6.897 6.928-3.804.006-6.9-3.102-6.903-6.928 0 0 4.76-39.072 6.903-39.072s6.897 39.072 6.897 39.072z"/>
</g>
</svg>

View File

@@ -54,6 +54,8 @@ Home/Caption: home
Home/Hint: Open the default tiddlers
Language/Caption: language
Language/Hint: Choose the user interface language
Manager/Caption: tiddler manager
Manager/Hint: Open tiddler manager
More/Caption: more
More/Hint: More actions
NewHere/Caption: new here
@@ -76,6 +78,8 @@ Permalink/Caption: permalink
Permalink/Hint: Set browser address bar to a direct link to this tiddler
Permaview/Caption: permaview
Permaview/Hint: Set browser address bar to a direct link to all the tiddlers in this story
Print/Caption: print page
Print/Hint: Print the current page
Refresh/Caption: refresh
Refresh/Hint: Perform a full refresh of the wiki
Save/Caption: ok
@@ -90,6 +94,12 @@ ShowSideBar/Caption: show sidebar
ShowSideBar/Hint: Show sidebar
TagManager/Caption: tag manager
TagManager/Hint: Open tag manager
Timestamp/Caption: timestamps
Timestamp/Hint: Choose whether modifications update timestamps
Timestamp/On/Caption: timestamps are on
Timestamp/On/Hint: Update timestamps when tiddlers are modified
Timestamp/Off/Caption: timestamps are off
Timestamp/Off/Hint: Don't update timestamps when tiddlers are modified
Theme/Caption: theme
Theme/Hint: Choose the display theme
Bold/Caption: bold

View File

@@ -11,6 +11,7 @@ Basics/DefaultTiddlers/Prompt: Default tiddlers:
Basics/DefaultTiddlers/TopHint: Choose which tiddlers are displayed at startup:
Basics/Language/Prompt: Hello! Current language:
Basics/NewJournal/Title/Prompt: Title of new journal tiddlers
Basics/NewJournal/Text/Prompt: Text for new journal tiddlers
Basics/NewJournal/Tags/Prompt: Tags for new journal tiddlers
Basics/OverriddenShadowTiddlers/Prompt: Number of overridden shadow tiddlers:
Basics/ShadowTiddlers/Prompt: Number of shadow tiddlers:
@@ -52,7 +53,7 @@ Palette/HideEditor/Caption: hide editor
Palette/Prompt: Current palette:
Palette/ShowEditor/Caption: show editor
Parsing/Caption: Parsing
Parsing/Hint: Here you can globally disable individual wiki parser rules. Take care as disabling some parser rules can prevent ~TiddlyWiki functioning correctly (you can restore normal operation with [[safe mode|http://tiddlywiki.com/#SafeMode]] )
Parsing/Hint: Here you can globally disable/enable wiki parser rules. For changes to take effect, save and reload your wiki. Disabling certain parser rules can prevent <$text text="TiddlyWiki"/> from functioning correctly. Use [[safe mode|http://tiddlywiki.com/#SafeMode]] to restore normal operation.
Parsing/Block/Caption: Block Parse Rules
Parsing/Inline/Caption: Inline Parse Rules
Parsing/Pragma/Caption: Pragma Parse Rules
@@ -74,16 +75,24 @@ Plugins/NoInfoFound/Hint: No ''"<$text text=<<currentTab>>/>"'' found
Plugins/NoInformation/Hint: No information provided
Plugins/NotInstalled/Hint: This plugin is not currently installed
Plugins/OpenPluginLibrary: open plugin library
Plugins/ClosePluginLibrary: close plugin library
Plugins/Plugins/Caption: Plugins
Plugins/Plugins/Hint: Plugins
Plugins/Reinstall/Caption: reinstall
Plugins/Themes/Caption: Themes
Plugins/Themes/Hint: Theme plugins
Saving/Caption: Saving
Saving/Heading: Saving
Saving/DownloadSaver/AutoSave/Description: Permit automatic saving for the download saver
Saving/DownloadSaver/AutoSave/Hint: Enable Autosave for Download Saver
Saving/DownloadSaver/Caption: Download Saver
Saving/DownloadSaver/Hint: These settings apply to the HTML5-compatible download saver
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/TiddlySpot/Advanced/Heading: Advanced Settings
Saving/TiddlySpot/BackupDir: Backup Directory
Saving/TiddlySpot/Backups: Backups
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
Saving/TiddlySpot/Description: These settings are only used when saving to http://tiddlyspot.com or a compatible remote server
Saving/TiddlySpot/Filename: Upload Filename
Saving/TiddlySpot/Heading: ~TiddlySpot
@@ -95,7 +104,7 @@ Saving/TiddlySpot/UserName: Wiki Name
Settings/AutoSave/Caption: Autosave
Settings/AutoSave/Disabled/Description: Do not save changes automatically
Settings/AutoSave/Enabled/Description: Save changes automatically
Settings/AutoSave/Hint: Automatically save changes during editing
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
Settings/CamelCase/Caption: Camel Case Wiki Links
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
@@ -103,6 +112,10 @@ Settings/Caption: Settings
Settings/EditorToolbar/Caption: Editor Toolbar
Settings/EditorToolbar/Hint: Enable or disable the editor toolbar:
Settings/EditorToolbar/Description: Show editor toolbar
Settings/InfoPanelMode/Caption: Tiddler Info Panel Mode
Settings/InfoPanelMode/Hint: Control when the tiddler info panel closes:
Settings/InfoPanelMode/Popup/Description: Tiddler info panel closes automatically
Settings/InfoPanelMode/Sticky/Description: Tiddler info panel stays open until explicitly closed
Settings/Hint: These settings let you customise the behaviour of TiddlyWiki.
Settings/NavigationAddressBar/Caption: Navigation Address Bar
Settings/NavigationAddressBar/Hint: Behaviour of the browser address bar when navigating to a tiddler:
@@ -149,12 +162,12 @@ TiddlerFields/Caption: Tiddler Fields
TiddlerFields/Hint: This is the full set of TiddlerFields in use in this wiki (including system tiddlers but excluding shadow tiddlers).
Toolbars/Caption: Toolbars
Toolbars/EditToolbar/Caption: Edit Toolbar
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode
Toolbars/EditToolbar/Hint: Choose which buttons are displayed for tiddlers in edit mode. Drag and drop to change the ordering
Toolbars/Hint: Select which toolbar buttons are displayed
Toolbars/PageControls/Caption: Page Toolbar
Toolbars/PageControls/Hint: Choose which buttons are displayed on the main page toolbar
Toolbars/PageControls/Hint: Choose which buttons are displayed on the main page toolbar. Drag and drop to change the ordering
Toolbars/EditorToolbar/Caption: Editor Toolbar
Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor toolbar. Note that some buttons will only appear when editing tiddlers of a certain type
Toolbars/EditorToolbar/Hint: Choose which buttons are displayed in the editor toolbar. Note that some buttons will only appear when editing tiddlers of a certain type. Drag and drop to change the ordering
Toolbars/ViewToolbar/Caption: View Toolbar
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode
Toolbars/ViewToolbar/Hint: Choose which buttons are displayed for tiddlers in view mode. Drag and drop to change the ordering
Tools/Download/Full/Caption: Download full wiki

View File

@@ -1,16 +1,21 @@
title: $:/language/Docs/ModuleTypes/
allfilteroperator: A sub-operator for the ''all'' filter operator.
animation: Animations that may be used with the RevealWidget.
bitmapeditoroperation: A bitmap editor toolbar operation.
command: Commands that can be executed under Node.js.
config: Data to be inserted into `$tw.config`.
filteroperator: Individual filter operator methods.
global: Global data to be inserted into `$tw`.
info: Publishes system information via the [[$:/temp/info-plugin]] pseudo-plugin.
isfilteroperator: Operands for the ''is'' filter operator.
library: Generic module type for general purpose JavaScript modules.
macro: JavaScript macro definitions.
parser: Parsers for different content types.
saver: Savers handle different methods for saving files from the browser.
startup: Startup functions.
storyview: Story views customise the animation and behaviour of list widgets.
texteditoroperation: A text editor toolbar operation.
tiddlerdeserializer: Converts different content types into tiddlers.
tiddlerfield: Defines the behaviour of an individual tiddler field.
tiddlermethod: Adds methods to the `$tw.Tiddler` prototype.

View File

@@ -18,6 +18,8 @@ Tags/Add/Placeholder: tag name
Tags/Dropdown/Caption: tag list
Tags/Dropdown/Hint: Show tag list
Title/BadCharacterWarning: Warning: avoid using any of the characters <<bad-chars>> in tiddler titles
Title/Exists/Prompt: Target tiddler already exists
Title/Relink/Prompt: Update ''<$text text=<<fromTitle>>/>'' to ''<$text text=<<toTitle>>/>'' in the //tags// and //list// fields of other tiddlers
Type/Dropdown/Caption: content type list
Type/Dropdown/Hint: Show content type list
Type/Delete/Caption: delete content type

View File

@@ -11,4 +11,5 @@ SystemTiddlers: System tiddlers
ShadowTiddlers: Shadow tiddlers
OverriddenShadowTiddlers: Overridden shadow tiddlers
SystemTags: System tags
StoryList: Tiddlers in the story river, excluding <$text text="$:/AdvancedSearch"/>
TypedTiddlers: Non wiki-text tiddlers

View File

@@ -0,0 +1,28 @@
title: $:/language/Help/fetch
description: Fetch tiddlers from wiki by URL
Fetch one or more files over HTTP/HTTPS, and import the tiddlers matching a filter, optionally transforming the incoming titles.
```
--fetch file <url> <import-filter> <transform-filter>
--fetch files <url-filter> <import-filter> <transform-filter>
```
With the "file" variant only a single file is fetched and the first parameter is the URL of the file to read.
With the "files" variant, multiple files are fetched and the first parameter is a filter yielding a list of URLs of the files to read. For example, given a set of tiddlers tagged "remote-server" that have a field "url" the filter `[tag[remote-server]get[url]]` will retrieve all the available URLs.
The `<import-filter>` parameter specifies a filter determining which tiddlers are imported. It defaults to `[all[tiddlers]]` if not provided.
The `<transform-filter>` parameter specifies an optional filter that transforms the titles of the imported tiddlers. For example, `[addprefix[$:/myimports/]]` would add the prefix `$:/myimports/` to each title.
Preceding the `--fetch` command with `--verbose` will output progress information during the import.
Note that TiddlyWiki will not fetch an older version of an already loaded plugin.
The following example retrieves all the non-system tiddlers from http://tiddlywiki.com and saves them to a JSON file:
```
tiddlywiki --verbose --fetch file "http://tiddlywiki.com/" "[!is[system]]" "" --rendertiddler "$:/core/templates/exporters/JsonFile" output.json text/plain "" exportFilter "[!is[system]]"
```

View File

@@ -1,12 +1,22 @@
title: $:/language/Help/rendertiddler
description: Render an individual tiddler as a specified ContentType
Render an individual tiddler as a specified ContentType, defaulting to `text/html` and save it to the specified filename. Optionally a template can be specified, in which case the template tiddler is rendered with the "currentTiddler" variable set to the tiddler that is being rendered (the first parameter value).
Render an individual tiddler as a specified ContentType, defaulting to `text/html` and save it to the specified filename.
Optionally the title of a template tiddler can be specified, in which case the template tiddler is rendered with the "currentTiddler" variable set to the tiddler that is being rendered (the first parameter value).
A name and value for an additional variable may optionally also be specified.
```
--rendertiddler <title> <filename> [<type>] [<template>]
--rendertiddler <title> <filename> [<type>] [<template>] [<name>] [<value>]
```
By default, the filename is resolved relative to the `output` subdirectory of the edition directory. The `--output` command can be used to direct output to a different directory.
Any missing directories in the path to the filename are automatically created.
For example, the following command saves all tiddlers matching the filter `[tag[done]]` to a JSON file titled `output.json` by employing the core template `$:/core/templates/exporters/JsonFile`.
```
--rendertiddler "$:/core/templates/exporters/JsonFile" output.json text/plain "" exportFilter "[tag[done]]"
```

View File

@@ -22,6 +22,7 @@ Encryption/RepeatPassword: Repeat password
Encryption/PasswordNoMatch: Passwords do not match
Encryption/SetPassword: Set password
Error/Caption: Error
Error/EditConflict: File changed on server
Error/Filter: Filter error
Error/FilterSyntax: Syntax error in filter expression
Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operator
@@ -36,6 +37,23 @@ InternalJavaScriptError/Hint: Well, this is embarrassing. It is recommended that
InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`)
LazyLoadingWarning: <p>Loading external text from ''<$text text={{!!_canonical_uri}}/>''</p><p>If this message doesn't disappear you may be using a browser that doesn't support external text in this configuration. See http://tiddlywiki.com/#ExternalText</p>
LoginToTiddlySpace: Login to TiddlySpace
Manager/Controls/FilterByTag/None: (none)
Manager/Controls/FilterByTag/Prompt: Filter by tag:
Manager/Controls/Order/Prompt: Reverse order
Manager/Controls/Search/Placeholder: Search
Manager/Controls/Search/Prompt: Search:
Manager/Controls/Show/Option/Tags: tags
Manager/Controls/Show/Option/Tiddlers: tiddlers
Manager/Controls/Show/Prompt: Show:
Manager/Controls/Sort/Prompt: Sort by:
Manager/Item/Colour: Colour
Manager/Item/Fields: Fields
Manager/Item/Icon/None: (none)
Manager/Item/Icon: Icon
Manager/Item/RawText: Raw text
Manager/Item/Tags: Tags
Manager/Item/Tools: Tools
Manager/Item/WikifiedText: Wikified text
MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" - click {{$:/core/images/edit-button}} to create
No: No
OfficialPluginLibrary: Official ~TiddlyWiki Plugin Library
@@ -43,6 +61,7 @@ OfficialPluginLibrary/Hint: The official ~TiddlyWiki plugin library at tiddlywik
PluginReloadWarning: Please save {{$:/core/ui/Buttons/save-wiki}} and reload {{$:/core/ui/Buttons/refresh}} to allow changes to plugins to take effect
RecentChanges/DateFormat: DDth MMM YYYY
SystemTiddler/Tooltip: This is a system tiddler
SystemTiddlers/Include/Prompt: Include system tiddlers
TagManager/Colour/Heading: Colour
TagManager/Count/Heading: Count
TagManager/Icon/Heading: Icon

View File

@@ -1,4 +1,5 @@
title: $:/config/NewJournal/
Title: DDth MMM YYYY
Text:
Tags: Journal

View File

@@ -8,6 +8,7 @@ Matches: //<small><<resultCount>> matches</small>//
Matches/All: All matches:
Matches/Title: Title matches:
Search: Search
Search/TooShort: Search text too short
Shadows/Caption: Shadows
Shadows/Hint: Search for shadow tiddlers
Shadows/Matches: //<small><<resultCount>> matches</small>//

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/application/javascript
description: JavaScript code
name: application/javascript
group: Developer
group-sort: 2

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/application/json
description: JSON data
name: application/json
group: Developer
group-sort: 2

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/application/x-tiddler-dictionary
description: Data dictionary
name: application/x-tiddler-dictionary
group: Developer
group-sort: 2

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/gif
description: GIF image
name: image/gif
group: Image
group-sort: 1

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/jpeg
description: JPEG image
name: image/jpeg
group: Image
group-sort: 1

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/png
description: PNG image
name: image/png
group: Image
group-sort: 1

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/svg+xml
description: Structured Vector Graphics image
name: image/svg+xml
group: Image
group-sort: 1

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/image/x-icon
description: ICO format icon file
name: image/x-icon
group: Image
group-sort: 1

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/css
description: Static stylesheet
name: text/css
group: Developer
group-sort: 2

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/html
description: HTML markup
name: text/html
group: Text
group-sort: 0

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/plain
description: Plain text
name: text/plain
group: Text
group-sort: 0

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/vnd.tiddlywiki
description: TiddlyWiki 5
name: text/vnd.tiddlywiki
group: Text
group-sort: 0

View File

@@ -2,3 +2,4 @@ title: $:/language/Docs/Types/text/x-tiddlywiki
description: TiddlyWiki Classic
name: text/x-tiddlywiki
group: Text
group-sort: 0

View File

@@ -29,6 +29,24 @@ var Commander = function(commandTokens,callback,wiki,streams) {
this.outputPath = path.resolve($tw.boot.wikiPath,$tw.config.wikiOutputSubDir);
};
/*
Log a string if verbose flag is set
*/
Commander.prototype.log = function(str) {
if(this.verbose) {
this.streams.output.write(str + "\n");
}
};
/*
Write a string if verbose flag is set
*/
Commander.prototype.write = function(str) {
if(this.verbose) {
this.streams.output.write(str);
}
};
/*
Add a string of tokens to the command queue
*/

View File

@@ -0,0 +1,145 @@
/*\
title: $:/core/modules/commands/fetch.js
type: application/javascript
module-type: command
Commands to fetch external tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.info = {
name: "fetch",
synchronous: false
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 2) {
return "Missing subcommand and url";
}
var subcommand = this.params[0],
url = this.params[1],
importFilter = this.params[2] || "[all[tiddlers]]",
transformFilter = this.params[3] || "";
switch(subcommand) {
case "file":
return this.fetchFiles({
url: url,
importFilter: importFilter,
transformFilter: transformFilter,
callback: this.callback
});
break;
case "files":
return this.fetchFiles({
urlFilter: url,
importFilter: importFilter,
transformFilter: transformFilter,
callback: this.callback
});
break;
}
return null;
};
Command.prototype.fetchFiles = function(options) {
var self = this;
// Get the list of URLs
var urls;
if(options.url) {
urls = [options.url]
} else if(options.urlFilter) {
urls = $tw.wiki.filterTiddlers(options.urlFilter);
} else {
return "Missing URL";
}
// Process each URL in turn
var next = 0;
var getNextFile = function(err) {
if(err) {
return options.callback(err);
}
if(next < urls.length) {
self.fetchFile(urls[next++],options,getNextFile);
} else {
options.callback(null);
}
};
getNextFile(null);
// Success
return null;
};
Command.prototype.fetchFile = function(url,options,callback) {
var self = this,
lib = url.substr(0,8) === "https://" ? require("https") : require("http");
lib.get(url).on("response",function(response) {
var type = (response.headers["content-type"] || "").split(";")[0],
body = "";
self.commander.write("Reading " + url + ": ");
response.on("data",function(chunk) {
body += chunk;
self.commander.write(".");
});
response.on("end",function() {
self.commander.write("\n");
if(response.statusCode === 200) {
self.processBody(body,type,options);
callback(null);
} else {
callback("Error " + response.statusCode + " retrieving " + url)
}
});
response.on("error",function(e) {
console.log("Error on GET request: " + e);
callback(e);
});
});
return null;
};
Command.prototype.processBody = function(body,type,options) {
// Deserialise the HTML file and put the tiddlers in their own wiki
var self = this,
incomingWiki = new $tw.Wiki(),
tiddlers = this.commander.wiki.deserializeTiddlers(type || "text/html",body,{});
$tw.utils.each(tiddlers,function(tiddler) {
incomingWiki.addTiddler(new $tw.Tiddler(tiddler));
});
// Filter the tiddlers to select the ones we want
var filteredTitles = incomingWiki.filterTiddlers(options.importFilter);
// Import the selected tiddlers
var count = 0;
incomingWiki.each(function(tiddler,title) {
if(filteredTitles.indexOf(title) !== -1) {
var newTiddler;
if(options.transformFilter) {
var transformedTitle = (incomingWiki.filterTiddlers(options.transformFilter,null,self.commander.wiki.makeTiddlerIterator([title])) || [""])[0];
if(transformedTitle) {
self.commander.log("Importing " + title + " as " + transformedTitle)
newTiddler = new $tw.Tiddler(tiddler,{title: transformedTitle});
}
} else {
self.commander.log("Importing " + title)
newTiddler = tiddler;
}
self.commander.wiki.importTiddler(newTiddler);
count++;
}
});
self.commander.log("Imported " + count + " tiddlers")
};
exports.Command = Command;
})();

View File

@@ -30,24 +30,21 @@ Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename";
}
var ext = path.extname(self.params[0]);
fs.readFile(this.params[0],$tw.utils.getTypeEncoding(ext),function(err,data) {
if (err) {
self.callback(err);
} else {
var fields = {title: self.params[0]},
type = path.extname(self.params[0]);
var tiddlers = self.commander.wiki.deserializeTiddlers(type,data,fields);
if(!tiddlers) {
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
} else {
for(var t=0; t<tiddlers.length; t++) {
self.commander.wiki.importTiddler(new $tw.Tiddler(tiddlers[t]));
}
self.callback(null);
}
}
var ext = path.extname(self.params[0]),
stat = fs.statSync(self.params[0]),
tiddlers = $tw.loadTiddlersFromPath(self.params[0]),
count = 0;
$tw.utils.each(tiddlers,function(tiddlerInfo) {
$tw.utils.each(tiddlerInfo.tiddlers,function(tiddler) {
self.commander.wiki.importTiddler(new $tw.Tiddler(tiddler));
count++;
});
});
if(!count) {
self.callback("No tiddlers found in file \"" + self.params[0] + "\"");
} else {
self.callback(null);
}
return null;
};

View File

@@ -34,12 +34,17 @@ Command.prototype.execute = function() {
filename = path.resolve(this.commander.outputPath,this.params[1]),
type = this.params[2] || "text/html",
template = this.params[3],
name = this.params[4],
value = this.params[5],
variables = {};
$tw.utils.createFileDirectories(filename);
if(template) {
variables.currentTiddler = title;
title = template;
}
if(name && value) {
variables[name] = value;
}
fs.writeFile(filename,this.commander.wiki.renderTiddler(type,title,{variables: variables}),"utf8",function(err) {
self.callback(err);
});

View File

@@ -91,57 +91,59 @@ SimpleServer.prototype.checkCredentials = function(request,incomingUsername,inco
}
};
SimpleServer.prototype.listen = function(port,host) {
SimpleServer.prototype.requestHandler = function(request,response) {
// Compose the state object
var self = this;
http.createServer(function(request,response) {
// Compose the state object
var state = {};
state.wiki = self.wiki;
state.server = self;
state.urlInfo = url.parse(request.url);
// Find the route that matches this path
var route = self.findMatchingRoute(request,state);
// Check for the username and password if we've got one
var username = self.get("username"),
password = self.get("password");
if(username && password) {
// Check they match
if(self.checkCredentials(request,username,password) !== "ALLOWED") {
var servername = state.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5";
response.writeHead(401,"Authentication required",{
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to ' + servername + '"'
});
response.end();
return;
}
}
// Return a 404 if we didn't find a route
if(!route) {
response.writeHead(404);
var state = {};
state.wiki = self.wiki;
state.server = self;
state.urlInfo = url.parse(request.url);
// Find the route that matches this path
var route = self.findMatchingRoute(request,state);
// Check for the username and password if we've got one
var username = self.get("username"),
password = self.get("password");
if(username && password) {
// Check they match
if(self.checkCredentials(request,username,password) !== "ALLOWED") {
var servername = state.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5";
response.writeHead(401,"Authentication required",{
"WWW-Authenticate": 'Basic realm="Please provide your username and password to login to ' + servername + '"'
});
response.end();
return;
}
// Set the encoding for the incoming request
// TODO: Presumably this would need tweaking if we supported PUTting binary tiddlers
request.setEncoding("utf8");
// Dispatch the appropriate method
switch(request.method) {
case "GET": // Intentional fall-through
case "DELETE":
}
// Return a 404 if we didn't find a route
if(!route) {
response.writeHead(404);
response.end();
return;
}
// Set the encoding for the incoming request
// TODO: Presumably this would need tweaking if we supported PUTting binary tiddlers
request.setEncoding("utf8");
// Dispatch the appropriate method
switch(request.method) {
case "GET": // Intentional fall-through
case "DELETE":
route.handler(request,response,state);
break;
case "PUT":
var data = "";
request.on("data",function(chunk) {
data += chunk.toString();
});
request.on("end",function() {
state.data = data;
route.handler(request,response,state);
break;
case "PUT":
var data = "";
request.on("data",function(chunk) {
data += chunk.toString();
});
request.on("end",function() {
state.data = data;
route.handler(request,response,state);
});
break;
}
}).listen(port,host);
});
break;
}
};
SimpleServer.prototype.listen = function(port,host) {
http.createServer(this.requestHandler.bind(this)).listen(port,host);
};
var Command = function(params,commander,callback) {

View File

@@ -72,19 +72,28 @@ exports["application/x-tiddler-html-div"] = function(text,fields) {
};
exports["application/json"] = function(text,fields) {
var incoming = JSON.parse(text),
var incoming,
results = [];
if($tw.utils.isArray(incoming)) {
for(var t=0; t<incoming.length; t++) {
var incomingFields = incoming[t],
fields = {};
for(var f in incomingFields) {
if(typeof incomingFields[f] === "string") {
fields[f] = incomingFields[f];
}
try {
incoming = JSON.parse(text);
} catch(e) {
incoming = [{
title: "JSON error: " + e,
text: ""
}]
}
if(!$tw.utils.isArray(incoming)) {
incoming = [incoming];
}
for(var t=0; t<incoming.length; t++) {
var incomingFields = incoming[t],
fields = {};
for(var f in incomingFields) {
if(typeof incomingFields[f] === "string") {
fields[f] = incomingFields[f];
}
results.push(fields);
}
results.push(fields);
}
return results;
};

View File

@@ -64,7 +64,7 @@ Set the text of the engine if it doesn't currently have focus
*/
SimpleEngine.prototype.setText = function(text,type) {
if(!this.domNode.isTiddlyWikiFakeDom) {
if(this.domNode.ownerDocument.activeElement !== this.domNode) {
if(this.domNode.ownerDocument.activeElement !== this.domNode || text === "") {
this.domNode.value = text;
}
// Fix the height if needed

View File

@@ -20,7 +20,7 @@ Parses an operation (i.e. a run) within a filter string
Returns the new start position, after the parsed operation
*/
function parseFilterOperation(operators,filterString,p) {
var operator, operand, bracketPos, curlyBracketPos;
var nextBracketPos, operator;
// Skip the starting square bracket
if(filterString.charAt(p++) !== "[") {
throw "Missing [ in filter expression";
@@ -33,14 +33,14 @@ function parseFilterOperation(operators,filterString,p) {
operator.prefix = filterString.charAt(p++);
}
// Get the operator name
var nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
if(nextBracketPos === -1) {
throw "Missing [ in filter expression";
}
nextBracketPos += p;
var bracket = filterString.charAt(nextBracketPos);
operator.operator = filterString.substring(p,nextBracketPos);
// Any suffix?
var colon = operator.operator.indexOf(':');
if(colon > -1) {
@@ -79,7 +79,7 @@ console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand
}
break;
}
if(nextBracketPos === -1) {
throw "Missing closing bracket in filter expression";
}
@@ -87,7 +87,7 @@ console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand
operator.operand = filterString.substring(p,nextBracketPos);
}
p = nextBracketPos + 1;
// Push this operator
operators.push(operator);
} while(filterString.charAt(p) !== "]");

View File

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

View File

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

View File

@@ -0,0 +1,83 @@
/*\
title: $:/core/modules/filters/decodeuricomponent.js
type: application/javascript
module-type: filteroperator
Filter operator for applying decodeURIComponent() to each item.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter functions
*/
exports.decodeuricomponent = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(decodeURIComponent(title));
});
return results;
};
exports.encodeuricomponent = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(encodeURIComponent(title));
});
return results;
};
exports.decodeuri = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(decodeURI(title));
});
return results;
};
exports.encodeuri = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(encodeURI(title));
});
return results;
};
exports.decodehtml = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.htmlDecode(title));
});
return results;
};
exports.encodehtml = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.htmlEncode(title));
});
return results;
};
exports.stringify = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.stringify(title));
});
return results;
};
exports.escaperegexp = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push($tw.utils.escapeRegExp(title));
});
return results;
};
})();

View File

@@ -0,0 +1,33 @@
/*\
title: $:/core/modules/filters/enlist.js
type: application/javascript
module-type: filteroperator
Filter operator returning its operand parsed as a list
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.enlist = function(source,operator,options) {
var list = $tw.utils.parseStringArray(operator.operand);
if(operator.prefix === "!") {
var results = [];
source(function(tiddler,title) {
if(list.indexOf(title) === -1) {
results.push(title);
}
});
return results;
} else {
return list;
}
};
})();

View File

@@ -16,19 +16,37 @@ Filter operator for checking if a tiddler has the specified field
Export our filter function
*/
exports.has = function(source,operator,options) {
var results = [];
if(operator.prefix === "!") {
source(function(tiddler,title) {
if(!tiddler || (tiddler && (!$tw.utils.hop(tiddler.fields,operator.operand) || tiddler.fields[operator.operand] === ""))) {
results.push(title);
}
});
var results = [],
invert = operator.prefix === "!";
if(operator.suffix === "field") {
if(invert) {
source(function(tiddler,title) {
if(!tiddler || (tiddler && (!$tw.utils.hop(tiddler.fields,operator.operand)))) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand)) {
results.push(title);
}
});
}
} else {
source(function(tiddler,title) {
if(tiddler && $tw.utils.hop(tiddler.fields,operator.operand) && !(tiddler.fields[operator.operand] === "" || tiddler.fields[operator.operand].length === 0)) {
results.push(title);
}
});
if(invert) {
source(function(tiddler,title) {
if(!tiddler || !$tw.utils.hop(tiddler.fields,operator.operand) || (tiddler.fields[operator.operand] === "")) {
results.push(title);
}
});
} else {
source(function(tiddler,title) {
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,41 @@
/*\
title: $:/core/modules/filters/insertbefore.js
type: application/javascript
module-type: filteroperator
Insert an item before another item in a list
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Order a list
*/
exports.insertbefore = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {
results.push(title);
});
var target = options.widget && options.widget.getVariable(operator.suffix || "currentTiddler");
if(target !== operator.operand) {
// Remove the entry from the list if it is present
var pos = results.indexOf(operator.operand);
if(pos !== -1) {
results.splice(pos,1);
}
// Insert the entry before the target marker
pos = results.indexOf(target);
if(pos !== -1) {
results.splice(pos,0,operator.operand);
} else {
results.push(operator.operand);
}
}
return results;
};
})();

View File

@@ -28,11 +28,20 @@ Export our filter function
exports.is = function(source,operator,options) {
// Dispatch to the correct isfilteroperator
var isFilterOperators = getIsFilterOperators();
var isFilterOperator = isFilterOperators[operator.operand];
if(isFilterOperator) {
return isFilterOperator(source,operator.prefix,options);
if(operator.operand) {
var isFilterOperator = isFilterOperators[operator.operand];
if(isFilterOperator) {
return isFilterOperator(source,operator.prefix,options);
} else {
return [$tw.language.getString("Error/IsFilterOperator")];
}
} else {
return [$tw.language.getString("Error/IsFilterOperator")];
// Return all tiddlers if the operand is missing
var results = [];
source(function(tiddler,title) {
results.push(title);
});
return results;
}
};

View File

@@ -12,6 +12,23 @@ Filter operators for manipulating the current selection list
/*global $tw: false */
"use strict";
/*
Order a list
*/
exports.order = function(source,operator,options) {
var results = [];
if(operator.operand.toLowerCase() === "reverse") {
source(function(tiddler,title) {
results.unshift(title);
});
} else {
source(function(tiddler,title) {
results.push(title);
});
}
return results;
};
/*
Reverse list
*/

View File

@@ -0,0 +1,29 @@
/*\
title: $:/core/modules/filters/minlength.js
type: application/javascript
module-type: filteroperator
Filter operator for filtering out titles that don't meet the minimum length in the operand
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.minlength = function(source,operator,options) {
var results = [],
minLength = parseInt(operator.operand || "",10) || 0;
source(function(tiddler,title) {
if(title.length >= minLength) {
results.push(title);
}
});
return results;
};
})();

View File

@@ -20,12 +20,9 @@ exports.sameday = function(source,operator,options) {
fieldName = operator.suffix || "modified",
targetDate = (new Date($tw.utils.parseDate(operator.operand))).setHours(0,0,0,0);
// Function to convert a date/time to a date integer
var isSameDay = function(dateField) {
return (new Date(dateField)).setHours(0,0,0,0) === targetDate;
};
source(function(tiddler,title) {
if(tiddler && tiddler.fields[fieldName]) {
if(isSameDay($tw.utils.parseDate(tiddler.fields[fieldName]))) {
if(tiddler) {
if(tiddler.getFieldDay(fieldName) === targetDate) {
results.push(title);
}
}

View File

@@ -17,19 +17,30 @@ Export our filter function
*/
exports.tag = function(source,operator,options) {
var results = [];
if(operator.prefix === "!") {
if((operator.suffix || "").toLowerCase() === "strict" && !operator.operand) {
// New semantics:
// Always return copy of input if operator.operand is missing
source(function(tiddler,title) {
if(tiddler && !tiddler.hasTag(operator.operand)) {
results.push(title);
}
results.push(title);
});
} else {
source(function(tiddler,title) {
if(tiddler && tiddler.hasTag(operator.operand)) {
results.push(title);
}
});
results = options.wiki.sortByList(results,operator.operand);
// Old semantics:
if(operator.prefix === "!") {
// Returns a copy of the input if operator.operand is missing
source(function(tiddler,title) {
if(tiddler && !tiddler.hasTag(operator.operand)) {
results.push(title);
}
});
} else {
// Returns empty results if operator.operand is missing
source(function(tiddler,title) {
if(tiddler && tiddler.hasTag(operator.operand)) {
results.push(title);
}
});
results = options.wiki.sortByList(results,operator.operand);
}
}
return results;
};

View File

@@ -16,10 +16,11 @@ Filter operator for returning the names of the wiki parser rules in this wiki
Export our filter function
*/
exports.wikiparserrules = function(source,operator,options) {
var results = [];
var results = [],
operand = operator.operand;
$tw.utils.each($tw.modules.types.wikirule,function(mod) {
var exp = mod.exports;
if(exp.types[operator.operand]) {
if(!operand || exp.types[operand]) {
results.push(exp.name);
}
});

View File

@@ -84,8 +84,9 @@ Extended filter operators to manipulate the current list.
var results = prepare_results(source),
index = results.indexOf(operator.operand),
count = parseInt(operator.suffix) || 1,
marker = results.splice(index, 1);
return results.slice(0, index + count).concat(marker).concat(results.slice(index + count));
marker = results.splice(index, 1),
offset = (index + count) > 0 ? index + count : 0;
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
};
/*

View File

@@ -18,6 +18,21 @@ exports.getInfoTiddlerFields = function() {
// Basics
infoTiddlerFields.push({title: "$:/info/browser", text: mapBoolean(!!$tw.browser)});
infoTiddlerFields.push({title: "$:/info/node", text: mapBoolean(!!$tw.node)});
// Document location
if($tw.browser) {
var setLocationProperty = function(name,value) {
infoTiddlerFields.push({title: "$:/info/url/" + name, text: value});
},
location = document.location;
setLocationProperty("full", (location.toString()).split("#")[0]);
setLocationProperty("host", location.host);
setLocationProperty("hostname", location.hostname);
setLocationProperty("protocol", location.protocol);
setLocationProperty("port", location.port);
setLocationProperty("pathname", location.pathname);
setLocationProperty("search", location.search);
setLocationProperty("origin", location.origin);
}
return infoTiddlerFields;
};

View File

@@ -0,0 +1,40 @@
/*\
title: $:/core/modules/macros/jsontiddler.js
type: application/javascript
module-type: macro
Macro to output a single tiddler to JSON
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Information about this macro
*/
exports.name = "jsontiddler";
exports.params = [
{name: "title"}
];
/*
Run the macro
*/
exports.run = function(title) {
title = title || this.getVariable("currentTiddler");
var tiddler = !!title && this.wiki.getTiddler(title),
fields = new Object();
if(tiddler) {
for(var field in tiddler.fields) {
fields[field] = tiddler.getFieldString(field);
}
}
return JSON.stringify(fields,null,$tw.config.preferences.jsonSpaces);
};
})();

View File

@@ -21,14 +21,8 @@ var ImageParser = function(type,text,options) {
src;
if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri};
if(type === "application/pdf" || type === ".pdf") {
element.tag = "embed";
}
} else if(text) {
if(type === "application/pdf" || type === ".pdf") {
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
element.tag = "embed";
} else if(type === "image/svg+xml" || type === ".svg") {
if(type === "image/svg+xml" || type === ".svg") {
element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
} else {
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
@@ -42,7 +36,6 @@ exports["image/jpg"] = ImageParser;
exports["image/jpeg"] = ImageParser;
exports["image/png"] = ImageParser;
exports["image/gif"] = ImageParser;
exports["application/pdf"] = ImageParser;
exports["image/x-icon"] = ImageParser;
})();

View File

@@ -218,6 +218,7 @@ exports.parseAttribute = function(source,pos) {
// Define our regexps
var reAttributeName = /([^\/\s>"'=]+)/g,
reUnquotedAttribute = /([^\/\s<>"'=]+)/g,
reFilteredValue = /\{\{\{(.+?)\}\}\}/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
@@ -243,29 +244,37 @@ exports.parseAttribute = function(source,pos) {
node.type = "string";
node.value = stringLiteral.value;
} else {
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = "true";
node.value = unquotedValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
if(macroInvocation) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
node.type = "string";
node.value = "true";
}
}
}
}

View File

@@ -0,0 +1,33 @@
/*\
title: $:/core/modules/parsers/pdfparser.js
type: application/javascript
module-type: parser
The PDF parser embeds a PDF viewer
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var ImageParser = function(type,text,options) {
var element = {
type: "element",
tag: "embed",
attributes: {}
},
src;
if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) {
element.attributes.src = {type: "string", value: "data:application/pdf;base64," + text};
}
this.tree = [element];
};
exports["application/pdf"] = ImageParser;
})();

View File

@@ -12,7 +12,7 @@ The video parser parses a video tiddler into an embeddable HTML element
/*global $tw: false */
"use strict";
var AudioParser = function(type,text,options) {
var VideoParser = function(type,text,options) {
var element = {
type: "element",
tag: "video",
@@ -29,7 +29,8 @@ var AudioParser = function(type,text,options) {
this.tree = [element];
};
exports["video/mp4"] = AudioParser;
exports["video/mp4"] = VideoParser;
exports["video/quicktime"] = VideoParser;
})();

View File

@@ -101,6 +101,10 @@ exports.parseTag = function(source,pos,options) {
node.type = node.tag.substr(1);
}
pos = token.end;
// Check that the tag is terminated by a space, / or >
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === "/") && !(source.charAt(pos) === ">") ) {
return null;
}
// Process attributes
var attribute = $tw.utils.parseAttribute(source,pos);
while(attribute) {

View File

@@ -61,7 +61,7 @@ exports.parse = function() {
reEnd = /(\r?\n\\end[^\S\n\r]*(?:$|\r?\n))/mg;
} else {
// Otherwise, the end of the definition is marked by the end of the line
reEnd = /(\r?\n)/mg;
reEnd = /($|\r?\n)/mg;
// Move past any whitespace
this.parser.pos = $tw.utils.skipWhiteSpace(this.parser.source,this.parser.pos);
}

View File

@@ -18,7 +18,12 @@ exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
this.matchRegExp = /~?\$:\/[a-zA-Z0-9/.\-_]+/mg;
this.matchRegExp = new RegExp(
"~?\\$:\\/[" +
$tw.config.textPrimitives.anyLetter.substr(1,$tw.config.textPrimitives.anyLetter.length - 2) +
"\/._-]+",
"mg"
);
};
exports.parse = function() {

View File

@@ -18,12 +18,14 @@ wiki: wiki store to be used
pluginType: type of plugin to be switched
controllerTitle: title of tiddler used to control switching of this resource
defaultPlugins: array of default plugins to be used if nominated plugin isn't found
onSwitch: callback when plugin is switched (single parameter is array of plugin titles)
*/
function PluginSwitcher(options) {
this.wiki = options.wiki;
this.pluginType = options.pluginType;
this.controllerTitle = options.controllerTitle;
this.defaultPlugins = options.defaultPlugins || [];
this.onSwitch = options.onSwitch;
// Switch to the current plugin
this.switchPlugins();
// Listen for changes to the selected plugin
@@ -64,6 +66,10 @@ PluginSwitcher.prototype.switchPlugins = function() {
var registeredTiddlers = $tw.wiki.registerPluginTiddlers(this.pluginType,plugins);
// Unpack the current theme tiddlers
$tw.wiki.unpackPluginTiddlers();
// Call the switch handler
if(this.onSwitch) {
this.onSwitch(plugins);
}
};
exports.PluginSwitcher = PluginSwitcher;

View File

@@ -37,10 +37,10 @@ function SaverHandler(options) {
// 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
var filteredChanges = self.filterFn.call(self.wiki,function(callback) {
var filteredChanges = self.filterFn.call(self.wiki,function(iterator) {
$tw.utils.each(changes,function(change,title) {
var tiddler = self.wiki.getTiddler(title);
callback(tiddler,title);
iterator(tiddler,title);
});
});
// Adjust the number of changes

View File

@@ -0,0 +1,62 @@
/*\
title: $:/core/modules/savers/beaker.js
type: application/javascript
module-type: saver
Saves files using the Beaker browser's (https://beakerbrowser.com) Dat protocol (https://datproject.org/)
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Set up the saver
*/
var BeakerSaver = function(wiki) {
this.wiki = wiki;
};
BeakerSaver.prototype.save = function(text,method,callback) {
var url = (location.toString()).split("#")[0];
dat.stat(url).then(function(value) {
if(value.type === "directory") {
url = url + "/index.html";
}
dat.writeFile(url,text,"utf8").then(function(value) {
callback(null);
},function(reason) {
callback("Beaker Saver Write Error: " + reason);
});
},function(reason) {
callback("Beaker Saver Stat Error: " + reason);
});
return true;
};
/*
Information about this saver
*/
BeakerSaver.prototype.info = {
name: "beaker",
priority: 3000,
capabilities: ["save", "autosave"]
};
/*
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
return !!window.dat;
};
/*
Create an instance of this saver
*/
exports.create = function(wiki) {
return new BeakerSaver(wiki);
};
})();

View File

@@ -33,8 +33,6 @@ DownloadSaver.prototype.save = function(text,method,callback,options) {
}
// Set up the link
var link = document.createElement("a");
link.setAttribute("target","_blank");
link.setAttribute("rel","noopener noreferrer");
if(Blob !== undefined) {
var blob = new Blob([text], {type: "text/html"});
link.setAttribute("href", URL.createObjectURL(blob));
@@ -55,10 +53,19 @@ Information about this saver
*/
DownloadSaver.prototype.info = {
name: "download",
priority: 100,
capabilities: ["save", "download"]
priority: 100
};
Object.defineProperty(DownloadSaver.prototype.info, "capabilities", {
get: function() {
var capabilities = ["save", "download"];
if(($tw.wiki.getTextReference("$:/config/DownloadSaver/AutoSave") || "").toLowerCase() === "yes") {
capabilities.push("autosave");
}
return capabilities;
}
});
/*
Static method that returns true if this saver is capable of working
*/

View File

@@ -21,36 +21,66 @@ Select the appropriate saver module and set it up
var PutSaver = function(wiki) {
this.wiki = wiki;
var self = this;
var uri = this.uri();
// Async server probe. Until probe finishes, save will fail fast
// See also https://github.com/Jermolene/TiddlyWiki5/issues/2276
var req = new XMLHttpRequest();
req.open("OPTIONS",encodeURI(document.location.protocol + "//" + document.location.hostname + ":" + document.location.port + document.location.pathname));
req.onload = function() {
// Check DAV header http://www.webdav.org/specs/rfc2518.html#rfc.section.9.1
self.serverAcceptsPuts = (this.status === 200 && !!this.getResponseHeader('dav'));
};
req.send();
$tw.utils.httpRequest({
url: uri,
type: "OPTIONS",
callback: function(err, data, xhr) {
// Check DAV header http://www.webdav.org/specs/rfc2518.html#rfc.section.9.1
if(!err) {
self.serverAcceptsPuts = xhr.status === 200 && !!xhr.getResponseHeader("dav");
}
}
});
// Retrieve ETag if available
$tw.utils.httpRequest({
url: uri,
type: "HEAD",
callback: function(err, data, xhr) {
if(!err) {
self.etag = xhr.getResponseHeader("ETag");
}
}
});
};
PutSaver.prototype.save = function(text,method,callback) {
if (!this.serverAcceptsPuts) {
PutSaver.prototype.uri = function() {
return encodeURI(document.location.toString().split("#")[0]);
};
// TODO: in case of edit conflict
// Prompt: Do you want to save over this? Y/N
// Merging would be ideal, and may be possible using future generic merge flow
PutSaver.prototype.save = function(text, method, callback) {
if(!this.serverAcceptsPuts) {
return false;
}
var req = new XMLHttpRequest();
// TODO: store/check ETags if supported by server, to protect against overwrites
// Prompt: Do you want to save over this? Y/N
// Merging would be ideal, and may be possible using future generic merge flow
req.onload = function() {
if (this.status === 200 || this.status === 201) {
callback(null); // success
var self = this;
var headers = { "Content-Type": "text/html;charset=UTF-8" };
if(this.etag) {
headers["If-Match"] = this.etag;
}
$tw.utils.httpRequest({
url: this.uri(),
type: "PUT",
headers: headers,
data: text,
callback: function(err, data, xhr) {
if(err) {
callback(err);
} if(xhr.status === 200 || xhr.status === 201) {
self.etag = xhr.getResponseHeader("ETag");
callback(null); // success
} else if(xhr.status === 412) { // edit conflict
var message = $tw.language.getString("Error/EditConflict");
callback(message);
} else {
callback(xhr.responseText); // fail
}
}
else {
callback(this.responseText); // fail
}
};
req.open("PUT", encodeURI(window.location.href));
req.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
req.send(text);
});
return true;
};

View File

@@ -73,7 +73,7 @@ TiddlyFoxSaver.prototype.info = {
Static method that returns true if this saver is capable of working
*/
exports.canSave = function(wiki) {
return (window.location.protocol === "file:");
return true;
};
/*

View File

@@ -29,16 +29,17 @@ function loadIFrame(url,callback) {
callback(null,iframeInfo);
} else {
// Create the iframe and save it in the list
var iframe = document.createElement("iframe"),
iframeInfo = {
url: url,
status: "loading",
domNode: iframe
};
var iframe = document.createElement("iframe");
iframeInfo = {
url: url,
status: "loading",
domNode: iframe
};
$tw.browserMessaging.iframeInfoMap[url] = iframeInfo;
saveIFrameInfoTiddler(iframeInfo);
// Add the iframe to the DOM and hide it
iframe.style.display = "none";
iframe.setAttribute("library","true");
document.body.appendChild(iframe);
// Set up onload
iframe.onload = function() {
@@ -57,6 +58,18 @@ function loadIFrame(url,callback) {
}
}
/*
Unload library iframe for given url
*/
function unloadIFrame(url){
$tw.utils.each(document.getElementsByTagName('iframe'), function(iframe) {
if(iframe.getAttribute("library") === "true" &&
iframe.getAttribute("src") === url) {
iframe.parentNode.removeChild(iframe);
}
});
}
function saveIFrameInfoTiddler(iframeInfo) {
$tw.wiki.addTiddler(new $tw.Tiddler($tw.wiki.getCreationFields(),{
title: "$:/temp/ServerConnection/" + iframeInfo.url,
@@ -93,6 +106,21 @@ exports.startup = function() {
});
}
});
// Listen for widget messages to control unloading the plugin library
$tw.rootWidget.addEventListener("tm-unload-plugin-library",function(event) {
var paramObject = event.paramObject || {},
url = paramObject.url;
$tw.browserMessaging.iframeInfoMap[url] = undefined;
if(url) {
unloadIFrame(url);
$tw.utils.each(
$tw.wiki.filterTiddlers("[[$:/temp/ServerConnection/" + url + "]] [prefix[$:/temp/RemoteAssetInfo/" + url + "/]]"),
function(title) {
$tw.wiki.deleteTiddler(title);
}
);
}
});
$tw.rootWidget.addEventListener("tm-load-plugin-from-library",function(event) {
var paramObject = event.paramObject || {},
url = paramObject.url,

View File

@@ -63,7 +63,17 @@ exports.startup = function() {
controllerTitle: "$:/language",
defaultPlugins: [
"$:/languages/en-US"
]
],
onSwitch: function(plugins) {
if($tw.browser) {
var pluginTiddler = $tw.wiki.getTiddler(plugins[0]);
if(pluginTiddler) {
document.documentElement.setAttribute("dir",pluginTiddler.getFieldString("text-direction") || "auto");
} else {
document.documentElement.removeAttribute("dir");
}
}
}
});
// Kick off the theme manager
$tw.themeManager = new $tw.PluginSwitcher({

View File

@@ -53,6 +53,10 @@ exports.startup = function() {
$tw.rootWidget.addEventListener("tm-browser-refresh",function(event) {
window.location.reload(true);
});
// Listen for the tm-print message
$tw.rootWidget.addEventListener("tm-print",function(event) {
(event.event.view || window).print();
});
// Listen for the tm-home message
$tw.rootWidget.addEventListener("tm-home",function(event) {
window.location.hash = "";

View File

@@ -49,7 +49,10 @@ exports.startup = function() {
$tw.wiki.removeEventListener("change",refreshHandler);
},false);
// Set up the styles
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{document: $tw.fakeDocument, variables: variables}),
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
document: $tw.fakeDocument,
variables: variables,
importPageMacros: true}),
styleContainer = $tw.fakeDocument.createElement("style");
styleWidgetNode.render(styleContainer,null);
var styleElement = srcDocument.createElement("style");

View File

@@ -12,6 +12,18 @@ The syncer tracks changes to the store. If a syncadaptor is used then individual
/*global $tw: false */
"use strict";
/*
Defaults
*/
Syncer.prototype.titleIsLoggedIn = "$:/status/IsLoggedIn";
Syncer.prototype.titleUserName = "$:/status/UserName";
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
Syncer.prototype.fallbackInterval = 10 * 1000; // Unless the task is older than 10s
Syncer.prototype.pollTimerInterval = 60 * 1000; // Interval for polling for changes from the adaptor
/*
Instantiate the syncer with the following options:
syncadaptor: reference to syncadaptor to be used
@@ -21,8 +33,16 @@ function Syncer(options) {
var self = this;
this.wiki = options.wiki;
this.syncadaptor = options.syncadaptor;
this.titleIsLoggedIn = options.titleIsLoggedIn || this.titleIsLoggedIn;
this.titleUserName = options.titleUserName || this.titleUserName;
this.titleSyncFilter = options.titleSyncFilter || this.titleSyncFilter;
this.titleSavedNotification = options.titleSavedNotification || this.titleSavedNotification;
this.taskTimerInterval = options.taskTimerInterval || this.taskTimerInterval;
this.throttleInterval = options.throttleInterval || this.throttleInterval;
this.fallbackInterval = options.fallbackInterval || this.fallbackInterval;
this.pollTimerInterval = options.pollTimerInterval || this.pollTimerInterval;
// Make a logger
this.logger = new $tw.utils.Logger("syncer" + ($tw.browser ? "-browser" : "") + ($tw.node ? "-server" : ""));
this.logger = new $tw.utils.Logger("syncer" + ($tw.browser ? "-browser" : "") + ($tw.node ? "-server" : "") + (this.syncadaptor.name ? ("-" + this.syncadaptor.name) : ""));
// Compile the dirty tiddler filter
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
// Record information for known tiddlers
@@ -69,19 +89,6 @@ function Syncer(options) {
});
}
/*
Constants
*/
Syncer.prototype.titleIsLoggedIn = "$:/status/IsLoggedIn";
Syncer.prototype.titleUserName = "$:/status/UserName";
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
Syncer.prototype.fallbackInterval = 10 * 1000; // Unless the task is older than 10s
Syncer.prototype.pollTimerInterval = 60 * 1000; // Interval for polling for changes from the adaptor
/*
Read (or re-read) the latest tiddler info from the store
*/
@@ -135,7 +142,7 @@ Syncer.prototype.updateDirtyStatus = function() {
/*
Save an incoming tiddler in the store, and updates the associated tiddlerInfo
*/
Syncer.prototype.storeTiddler = function(tiddlerFields) {
Syncer.prototype.storeTiddler = function(tiddlerFields,hasBeenLazyLoaded) {
// Save the tiddler
var tiddler = new $tw.Tiddler(this.wiki.getTiddler(tiddlerFields.title),tiddlerFields);
this.wiki.addTiddler(tiddler);
@@ -144,7 +151,7 @@ Syncer.prototype.storeTiddler = function(tiddlerFields) {
revision: tiddlerFields.revision,
adaptorInfo: this.syncadaptor.getTiddlerInfo(tiddler),
changeCount: this.wiki.getChangeCount(tiddlerFields.title),
hasBeenLazyLoaded: true
hasBeenLazyLoaded: hasBeenLazyLoaded !== undefined ? hasBeenLazyLoaded : true
};
};
@@ -218,7 +225,7 @@ Syncer.prototype.syncFromServer = function() {
});
} else {
// Load the skinny version of the tiddler
self.storeTiddler(tiddlerFields);
self.storeTiddler(tiddlerFields,false);
}
}
}
@@ -404,7 +411,7 @@ Process the task queue, performing the next task if appropriate
Syncer.prototype.processTaskQueue = function() {
var self = this;
// Only process a task if the sync adaptor is fully initialised and we're not already performing a task. If we are already performing a task then we'll dispatch the next one when it completes
if(this.syncadaptor.isReady() && this.numTasksInProgress() === 0) {
if((!this.syncadaptor.isReady || this.syncadaptor.isReady()) && this.numTasksInProgress() === 0) {
// Choose the next task to perform
var task = this.chooseNextTask();
// Perform the task if we had one
@@ -499,7 +506,7 @@ Syncer.prototype.dispatchTask = function(task,callback) {
}
// Store the tiddler
if(tiddlerFields) {
self.storeTiddler(tiddlerFields);
self.storeTiddler(tiddlerFields,true);
}
// Invoke the callback
callback(null);

View File

@@ -39,6 +39,24 @@ exports.getFieldString = function(field) {
}
};
/*
Get all the fields as a hashmap of strings. Options:
exclude: an array of field names to exclude
*/
exports.getFieldStrings = 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[field] = this.getFieldString(field);
}
}
}
return fields;
};
/*
Get all the fields as a name:value block. Options:
exclude: an array of field names to exclude
@@ -108,4 +126,17 @@ exports.isEqual = function(tiddler,excludeFields) {
return differences.length === 0;
};
exports.getFieldDay = function(field) {
if(this.cache && this.cache.day && $tw.utils.hop(this.cache.day,field) ) {
return this.cache.day[field];
}
var day = "";
if(this.fields[field]) {
day = (new Date($tw.utils.parseDate(this.fields[field]))).setHours(0,0,0,0);
}
this.cache.day = this.cache.day || {};
this.cache.day[field] = day;
return day;
};
})();

View File

@@ -0,0 +1,181 @@
/*\
title: $:/core/modules/utils/dom/dragndrop.js
type: application/javascript
module-type: utils
Browser data transfer utilities, used with the clipboard and drag and drop
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Options:
domNode: dom node to make draggable
dragImageType: "pill" or "dom"
dragTiddlerFn: optional function to retrieve the title of tiddler to drag
dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag
widget: widget to use as the contect for the filter
*/
exports.makeDraggable = function(options) {
var dragImageType = options.dragImageType || "dom",
dragImage,
domNode = options.domNode;
// Make the dom node draggable (not necessary for anchor tags)
if((domNode.tagName || "").toLowerCase() !== "a") {
domNode.setAttribute("draggable","true");
}
// Add event handlers
$tw.utils.addEventListeners(domNode,[
{name: "dragstart", handlerFunction: function(event) {
// Collect the tiddlers being dragged
var dragTiddler = options.dragTiddlerFn && options.dragTiddlerFn(),
dragFilter = options.dragFilterFn && options.dragFilterFn(),
titles = dragTiddler ? [dragTiddler] : [];
if(dragFilter) {
titles.push.apply(titles,options.widget.wiki.filterTiddlers(dragFilter,options.widget));
}
var titleString = $tw.utils.stringifyList(titles);
// Check that we've something to drag
if(titles.length > 0 && event.target === domNode) {
// Mark the drag in progress
$tw.dragInProgress = domNode;
// Set the dragging class on the element being dragged
$tw.utils.addClass(event.target,"tc-dragging");
// Create the drag image elements
dragImage = options.widget.document.createElement("div");
dragImage.className = "tc-tiddler-dragger";
var inner = options.widget.document.createElement("div");
inner.className = "tc-tiddler-dragger-inner";
inner.appendChild(options.widget.document.createTextNode(
titles.length === 1 ?
titles[0] :
titles.length + " tiddlers"
));
dragImage.appendChild(inner);
options.widget.document.body.appendChild(dragImage);
// Set the data transfer properties
var dataTransfer = event.dataTransfer;
// Set up the image
dataTransfer.effectAllowed = "all";
if(dataTransfer.setDragImage) {
if(dragImageType === "pill") {
dataTransfer.setDragImage(dragImage.firstChild,-16,-16);
} else {
var r = domNode.getBoundingClientRect();
dataTransfer.setDragImage(domNode,event.clientX-r.left,event.clientY-r.top);
}
}
// Set up the data transfer
if(dataTransfer.clearData) {
dataTransfer.clearData();
}
var jsonData = [];
if(titles.length > 1) {
titles.forEach(function(title) {
jsonData.push(options.widget.wiki.getTiddlerAsJson(title));
});
jsonData = "[" + jsonData.join(",") + "]";
} else {
jsonData = options.widget.wiki.getTiddlerAsJson(titles[0]);
}
// IE doesn't like these content types
if(!$tw.browser.isIE) {
dataTransfer.setData("text/vnd.tiddler",jsonData);
dataTransfer.setData("text/plain",titleString);
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
}
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
dataTransfer.setData("Text",titleString);
event.stopPropagation();
}
return false;
}},
{name: "dragend", handlerFunction: function(event) {
if(event.target === domNode) {
$tw.dragInProgress = null;
// Remove the dragging class on the element being dragged
$tw.utils.removeClass(event.target,"tc-dragging");
// Delete the drag image element
if(dragImage) {
dragImage.parentNode.removeChild(dragImage);
dragImage = null;
}
}
return false;
}}
]);
};
exports.importDataTransfer = function(dataTransfer,fallbackTitle,callback) {
// Try each provided data type in turn
for(var t=0; t<importDataTypes.length; t++) {
if(!$tw.browser.isIE || importDataTypes[t].IECompatible) {
// Get the data
var dataType = importDataTypes[t];
var data = dataTransfer.getData(dataType.type);
// Import the tiddlers in the data
if(data !== "" && data !== null) {
if($tw.log.IMPORT) {
console.log("Importing data type '" + dataType.type + "', data: '" + data + "'")
}
var tiddlerFields = dataType.toTiddlerFieldsArray(data,fallbackTitle);
callback(tiddlerFields);
return;
}
}
}
};
var importDataTypes = [
{type: "text/vnd.tiddler", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
return parseJSONTiddlers(data,fallbackTitle);
}},
{type: "URL", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
// Check for tiddler data URI
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
if(match) {
return parseJSONTiddlers(match[1],fallbackTitle);
} else {
return [{title: fallbackTitle, text: data}]; // As URL string
}
}},
{type: "text/x-moz-url", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
// Check for tiddler data URI
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
if(match) {
return parseJSONTiddlers(match[1],fallbackTitle);
} else {
return [{title: fallbackTitle, text: data}]; // As URL string
}
}},
{type: "text/html", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
return [{title: fallbackTitle, text: data}];
}},
{type: "text/plain", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
return [{title: fallbackTitle, text: data}];
}},
{type: "Text", IECompatible: true, toTiddlerFieldsArray: function(data,fallbackTitle) {
return [{title: fallbackTitle, text: data}];
}},
{type: "text/uri-list", IECompatible: false, toTiddlerFieldsArray: function(data,fallbackTitle) {
return [{title: fallbackTitle, text: data}];
}}
];
function parseJSONTiddlers(json,fallbackTitle) {
var data = JSON.parse(json);
if(!$tw.utils.isArray(data)) {
data = [data];
}
data.forEach(function(fields) {
fields.title = fields.title || fallbackTitle;
});
return data;
};
})();

View File

@@ -17,10 +17,12 @@ A quick and dirty HTTP function; to be refactored later. Options are:
url: URL to retrieve
type: GET, PUT, POST etc
callback: function invoked with (err,data)
returnProp: string name of the property to return as first argument of callback
*/
exports.httpRequest = function(options) {
var type = options.type || "GET",
headers = options.headers || {accept: "application/json"},
returnProp = options.returnProp || "responseText",
request = new XMLHttpRequest(),
data = "",
f,results;
@@ -41,7 +43,7 @@ exports.httpRequest = function(options) {
if(this.readyState === 4) {
if(this.status === 200 || this.status === 201 || this.status === 204) {
// Success!
options.callback(null,this.responseText,this);
options.callback(null,this[returnProp],this);
return;
}
// Something went wrong

View File

@@ -81,14 +81,16 @@ Modal.prototype.display = function(title,options) {
}}}],
parentWidget: $tw.rootWidget,
document: document,
variables: variables
variables: variables,
importPageMacros: true
});
headerWidgetNode.render(headerTitle,null);
// Render the body of the message
var bodyWidgetNode = this.wiki.makeTranscludeWidget(title,{
parentWidget: $tw.rootWidget,
document: document,
variables: variables
variables: variables,
importPageMacros: true
});
bodyWidgetNode.render(modalBody,null);
// Setup the link if present
@@ -128,7 +130,8 @@ Modal.prototype.display = function(title,options) {
]}],
parentWidget: $tw.rootWidget,
document: document,
variables: variables
variables: variables,
importPageMacros: true
});
footerWidgetNode.render(modalFooterButtons,null);
// Set up the refresh handler

View File

@@ -41,7 +41,11 @@ Notifier.prototype.display = function(title,options) {
// Create the variables
var variables = $tw.utils.extend({currentTiddler: title},options.variables);
// Render the body of the notification
var widgetNode = this.wiki.makeTranscludeWidget(title,{parentWidget: $tw.rootWidget, document: document, variables: variables});
var widgetNode = this.wiki.makeTranscludeWidget(title,{
parentWidget: $tw.rootWidget,
document: document,
variables: variables,
importPageMacros: true});
widgetNode.render(notification,null);
refreshHandler = function(changes) {
widgetNode.refresh(changes,notification,null);

View File

@@ -23,7 +23,7 @@ var bumpSequenceNumber = function(object) {
var TW_TextNode = function(text) {
bumpSequenceNumber(this);
this.textContent = text;
this.textContent = text + "";
};
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
@@ -66,7 +66,7 @@ TW_Element.prototype.setAttribute = function(name,value) {
if(this.isRaw) {
throw "Cannot setAttribute on a raw TW_Element";
}
this.attributes[name] = value;
this.attributes[name] = value + "";
};
TW_Element.prototype.setAttributeNS = function(namespace,name,value) {
@@ -139,7 +139,7 @@ Object.defineProperty(TW_Element.prototype, "className", {
return this.attributes["class"] || "";
},
set: function(value) {
this.attributes["class"] = value;
this.attributes["class"] = value + "";
}
});
@@ -148,7 +148,7 @@ Object.defineProperty(TW_Element.prototype, "value", {
return this.attributes.value || "";
},
set: function(value) {
this.attributes.value = value;
this.attributes.value = value + "";
}
});
@@ -206,13 +206,29 @@ Object.defineProperty(TW_Element.prototype, "innerHTML", {
set: function(value) {
this.isRaw = true;
this.rawHTML = value;
this.rawTextContent = null;
}
});
Object.defineProperty(TW_Element.prototype, "textInnerHTML", {
set: function(value) {
if(this.isRaw) {
this.rawTextContent = value;
} else {
throw "Cannot set textInnerHTML of a non-raw TW_Element";
}
}
});
Object.defineProperty(TW_Element.prototype, "textContent", {
get: function() {
if(this.isRaw) {
throw "Cannot get textContent on a raw TW_Element";
if(this.rawTextContent === null) {
console.log(booboo)
throw "Cannot get textContent on a raw TW_Element";
} else {
return this.rawTextContent;
}
} else {
var b = [];
$tw.utils.each(this.children,function(node) {

View File

@@ -19,6 +19,15 @@ exports.warning = function(text) {
console.log($tw.node ? "\x1b[1;33m" + text + "\x1b[0m" : text);
};
/*
Repeatedly replaces a substring within a string. Like String.prototype.replace, but without any of the default special handling of $ sequences in the replace string
*/
exports.replaceString = function(text,search,replace) {
return text.replace(search,function() {
return replace;
});
};
/*
Repeats a string
*/
@@ -215,11 +224,13 @@ exports.extendDeepCopy = function(object,extendedProperties) {
exports.deepFreeze = function deepFreeze(object) {
var property, key;
Object.freeze(object);
for(key in object) {
property = object[key];
if($tw.utils.hop(object,key) && (typeof property === "object") && !Object.isFrozen(property)) {
deepFreeze(property);
if(object) {
Object.freeze(object);
for(key in object) {
property = object[key];
if($tw.utils.hop(object,key) && (typeof property === "object") && !Object.isFrozen(property)) {
deepFreeze(property);
}
}
}
};
@@ -349,7 +360,8 @@ exports.getWeek = function(date) {
d = 7; // JavaScript Sun=0, ISO Sun=7
}
dt.setTime(dt.getTime() + (4 - d) * 86400000);// shift day to Thurs of same week to calculate weekNo
var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1) + 3600000) / 86400000);
var x = new Date(dt.getFullYear(),0,1);
var n = Math.floor((dt.getTime() - x.getTime()) / 86400000);
return Math.floor(n / 7) + 1;
};
@@ -687,7 +699,6 @@ exports.tagToCssSelector = function(tagName) {
});
};
/*
IE does not have sign function
*/
@@ -709,10 +720,88 @@ exports.strEndsWith = function(str,ending,position) {
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > str.length) {
position = str.length;
}
position -= str.length;
position -= ending.length;
var lastIndex = str.indexOf(ending, position);
return lastIndex !== -1 && lastIndex === position;
}
};
/*
Transliterate string from eg. Cyrillic Russian to Latin
*/
var transliterationPairs = {
"Ё":"YO",
"Й":"I",
"Ц":"TS",
"У":"U",
"К":"K",
"Е":"E",
"Н":"N",
"Г":"G",
"Ш":"SH",
"Щ":"SCH",
"З":"Z",
"Х":"H",
"Ъ":"'",
"ё":"yo",
"й":"i",
"ц":"ts",
"у":"u",
"к":"k",
"е":"e",
"н":"n",
"г":"g",
"ш":"sh",
"щ":"sch",
"з":"z",
"х":"h",
"ъ":"'",
"Ф":"F",
"Ы":"I",
"В":"V",
"А":"a",
"П":"P",
"Р":"R",
"О":"O",
"Л":"L",
"Д":"D",
"Ж":"ZH",
"Э":"E",
"ф":"f",
"ы":"i",
"в":"v",
"а":"a",
"п":"p",
"р":"r",
"о":"o",
"л":"l",
"д":"d",
"ж":"zh",
"э":"e",
"Я":"Ya",
"Ч":"CH",
"С":"S",
"М":"M",
"И":"I",
"Т":"T",
"Ь":"'",
"Б":"B",
"Ю":"YU",
"я":"ya",
"ч":"ch",
"с":"s",
"м":"m",
"и":"i",
"т":"t",
"ь":"'",
"б":"b",
"ю":"yu"
};
exports.transliterate = function(str) {
return str.split("").map(function(char) {
return transliterationPairs[char] || char;
}).join("");
};
})();

View File

@@ -0,0 +1,81 @@
/*\
title: $:/core/modules/widgets/action-createtiddler.js
type: application/javascript
module-type: widget
Action widget to create a new tiddler with a unique name and specified fields.
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var CreateTiddlerWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
CreateTiddlerWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
CreateTiddlerWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes();
this.execute();
};
/*
Compute the internal state of the widget
*/
CreateTiddlerWidget.prototype.execute = function() {
this.actionBaseTitle = this.getAttribute("$basetitle");
this.actionSaveTitle = this.getAttribute("$savetitle");
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
};
/*
Refresh the widget by ensuring our attributes are up to date
*/
CreateTiddlerWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if($tw.utils.count(changedAttributes) > 0) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
/*
Invoke the action associated with this widget
*/
CreateTiddlerWidget.prototype.invokeAction = function(triggeringWidget,event) {
var title = this.wiki.generateNewTitle(this.actionBaseTitle),
fields = {},
creationFields,
modificationFields;
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.charAt(0) !== "$") {
fields[name] = attribute;
}
});
if(this.actionTimestamp) {
creationFields = this.wiki.getCreationFields();
modificationFields = this.wiki.getModificationFields();
}
var tiddler = this.wiki.addTiddler(new $tw.Tiddler(creationFields,fields,modificationFields,{title: title}));
if(this.actionSaveTitle) {
this.wiki.setTextReference(this.actionSaveTitle,title,this.getVariable("currentTiddler"));
}
return true; // Action was invoked
};
exports["action-createtiddler"] = CreateTiddlerWidget;
})();

View File

@@ -57,17 +57,24 @@ Invoke the action associated with this widget
DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
var self = this,
tiddler = this.wiki.getTiddler(self.actionTiddler),
removeFields = {};
removeFields = {},
hasChanged = false;
if(this.actionField) {
removeFields[this.actionField] = undefined;
if(this.actionField in tiddler.fields) {
hasChanged = true;
}
}
if(tiddler) {
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.charAt(0) !== "$" && name !== "title") {
removeFields[name] = undefined;
hasChanged = true;
}
});
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getModificationFields(),tiddler,removeFields,this.wiki.getCreationFields()));
if(hasChanged) {
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),tiddler,removeFields,this.wiki.getModificationFields()));
}
}
return true; // Action was invoked
};

View File

@@ -80,9 +80,13 @@ ActionListopsWidget.prototype.invokeAction = function(triggeringWidget,
.filterTiddlers(subfilter, this)));
}
if(this.filtertags) {
var tagfilter = "[list[" + this.target + "!!tags]] " + this.filtertags;
this.wiki.setText(this.target, "tags", undefined, $tw.utils.stringifyList(
this.wiki.filterTiddlers(tagfilter, this)));
var tiddler = this.wiki.getTiddler(this.target),
oldtags = tiddler ? (tiddler.fields.tags || []).slice(0) : [],
tagfilter = "[list[" + this.target + "!!tags]] " + this.filtertags,
newtags = this.wiki.filterTiddlers(tagfilter,this);
if($tw.utils.stringifyList(oldtags.sort()) !== $tw.utils.stringifyList(newtags.sort())) {
this.wiki.setText(this.target,"tags",undefined,$tw.utils.stringifyList(newtags));
}
}
return true; // Action was invoked
};

View File

@@ -78,7 +78,8 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
param: param,
paramObject: paramObject,
tiddlerTitle: this.getVariable("currentTiddler"),
navigateFromTitle: this.getVariable("storyTiddler")
navigateFromTitle: this.getVariable("storyTiddler"),
event: event
});
return true; // Action was invoked
};

View File

@@ -95,6 +95,15 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
}
return handled;
},false);
// Make it draggable if required
if(this.dragTiddler || this.dragFilter) {
$tw.utils.makeDraggable({
domNode: domNode,
dragTiddlerFn: function() {return self.dragTiddler;},
dragFilterFn: function() {return self.dragFilter;},
widget: this
});
}
// Insert element
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
@@ -131,12 +140,13 @@ ButtonWidget.prototype.navigateTo = function(event) {
navigateFromNode: this,
navigateFromClientRect: { top: bounds.top, left: bounds.left, width: bounds.width, right: bounds.right, bottom: bounds.bottom, height: bounds.height
},
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1)
navigateSuppressNavigation: event.metaKey || event.ctrlKey || (event.button === 1),
event: event
});
};
ButtonWidget.prototype.dispatchMessage = function(event) {
this.dispatchEvent({type: this.message, param: this.param, tiddlerTitle: this.getVariable("currentTiddler")});
this.dispatchEvent({type: this.message, param: this.param, tiddlerTitle: this.getVariable("currentTiddler"), event: event});
};
ButtonWidget.prototype.triggerPopup = function(event) {
@@ -171,6 +181,8 @@ ButtonWidget.prototype.execute = function() {
this.selectedClass = this.getAttribute("selectedClass");
this.defaultSetValue = this.getAttribute("default","");
this.buttonTag = this.getAttribute("tag");
this.dragTiddler = this.getAttribute("dragTiddler");
this.dragFilter = this.getAttribute("dragFilter");
// Make child widgets
this.makeChildWidgets();
};
@@ -180,7 +192,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
ButtonWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes["class"] || changedAttributes.selectedClass || changedAttributes.style || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup])) {
if(changedAttributes.to || changedAttributes.message || changedAttributes.param || changedAttributes.set || changedAttributes.setTo || changedAttributes.popup || changedAttributes.hover || changedAttributes["class"] || changedAttributes.selectedClass || changedAttributes.style || changedAttributes.dragFilter || changedAttributes.dragTiddler || (this.set && changedTiddlers[this.set]) || (this.popup && changedTiddlers[this.popup])) {
this.refreshSelf();
return true;
}

View File

@@ -65,7 +65,21 @@ CheckboxWidget.prototype.getValue = function() {
}
}
if(this.checkboxField) {
var value = tiddler.fields[this.checkboxField] || this.checkboxDefault || "";
var value;
if($tw.utils.hop(tiddler.fields,this.checkboxField)) {
value = tiddler.fields[this.checkboxField] || "";
} else {
value = this.checkboxDefault || "";
}
if(value === this.checkboxChecked) {
return true;
}
if(value === this.checkboxUnchecked) {
return false;
}
}
if(this.checkboxIndex) {
var value = this.wiki.extractTiddlerDataItem(tiddler,this.checkboxIndex,this.checkboxDefault || "");
if(value === this.checkboxChecked) {
return true;
}
@@ -96,7 +110,8 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
newFields = {title: this.checkboxTitle},
hasChanged = false,
tagCheck = false,
hasTag = tiddler && tiddler.hasTag(this.checkboxTag);
hasTag = tiddler && tiddler.hasTag(this.checkboxTag),
value = checked ? this.checkboxChecked : this.checkboxUnchecked;
if(this.checkboxTag && this.checkboxInvertTag === "yes") {
tagCheck = hasTag === checked;
} else {
@@ -118,14 +133,28 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
}
// Set the field if specified
if(this.checkboxField) {
var value = checked ? this.checkboxChecked : this.checkboxUnchecked;
if(!tiddler || tiddler.fields[this.checkboxField] !== value) {
newFields[this.checkboxField] = value;
hasChanged = true;
}
}
// Set the index if specified
if(this.checkboxIndex) {
var indexValue = this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxIndex);
if(!tiddler || indexValue !== value) {
hasChanged = true;
}
}
if(hasChanged) {
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
if(this.checkboxIndex) {
this.wiki.setText(this.checkboxTitle,"",this.checkboxIndex,value);
} else {
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),fallbackFields,tiddler,newFields,this.wiki.getModificationFields()));
}
}
// Trigger actions
if(this.checkboxActions) {
this.invokeActionString(this.checkboxActions,this,event);
}
};
@@ -134,9 +163,11 @@ Compute the internal state of the widget
*/
CheckboxWidget.prototype.execute = function() {
// Get the parameters from the attributes
this.checkboxActions = this.getAttribute("actions");
this.checkboxTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.checkboxTag = this.getAttribute("tag");
this.checkboxField = this.getAttribute("field");
this.checkboxIndex = this.getAttribute("index");
this.checkboxChecked = this.getAttribute("checked");
this.checkboxUnchecked = this.getAttribute("unchecked");
this.checkboxDefault = this.getAttribute("default");
@@ -151,7 +182,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
CheckboxWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"]) {
if(changedAttributes.tiddler || changedAttributes.tag || changedAttributes.invertTag || changedAttributes.field || changedAttributes.index || changedAttributes.checked || changedAttributes.unchecked || changedAttributes["default"] || changedAttributes["class"]) {
this.refreshSelf();
return true;
} else {

View File

@@ -0,0 +1,88 @@
/*\
title: $:/core/modules/widgets/draggable.js
type: application/javascript
module-type: widget
Draggable widget
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var DraggableWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
DraggableWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
DraggableWidget.prototype.render = function(parent,nextSibling) {
var self = this;
// Save the parent dom node
this.parentDomNode = parent;
// Compute our attributes
this.computeAttributes();
// Execute our logic
this.execute();
// Sanitise the specified tag
var tag = this.draggableTag;
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
tag = "div";
}
// Create our element
var domNode = this.document.createElement(tag);
// Assign classes
var classes = ["tc-draggable"];
if(this.draggableClasses) {
classes.push(this.draggableClasses);
}
domNode.setAttribute("class",classes.join(" "));
// Add event handlers
$tw.utils.makeDraggable({
domNode: domNode,
dragTiddlerFn: function() {return self.getAttribute("tiddler");},
dragFilterFn: function() {return self.getAttribute("filter");},
widget: this
});
// Insert the link into the DOM and render any children
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
};
/*
Compute the internal state of the widget
*/
DraggableWidget.prototype.execute = function() {
// Pick up our attributes
this.draggableTag = this.getAttribute("tag","div");
this.draggableClasses = this.getAttribute("class");
// Make the child widgets
this.makeChildWidgets();
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DraggableWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedTiddlers.tag || changedTiddlers["class"]) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
exports.draggable = DraggableWidget;
})();

View File

@@ -0,0 +1,161 @@
/*\
title: $:/core/modules/widgets/droppable.js
type: application/javascript
module-type: widget
Droppable widget
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var DroppableWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
DroppableWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
DroppableWidget.prototype.render = function(parent,nextSibling) {
var self = this;
// Remember parent
this.parentDomNode = parent;
// Compute attributes and execute state
this.computeAttributes();
this.execute();
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.droppableTag && $tw.config.htmlUnsafeElements.indexOf(this.droppableTag) === -1) {
tag = this.droppableTag;
}
// Create element and assign classes
var domNode = this.document.createElement(tag),
classes = (this["class"] || "").split(" ");
classes.push("tc-droppable");
domNode.className = classes.join(" ");
// Add event handlers
$tw.utils.addEventListeners(domNode,[
{name: "dragenter", handlerObject: this, handlerMethod: "handleDragEnterEvent"},
{name: "dragover", handlerObject: this, handlerMethod: "handleDragOverEvent"},
{name: "dragleave", handlerObject: this, handlerMethod: "handleDragLeaveEvent"},
{name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"}
]);
// Insert element
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
// Stack of outstanding enter/leave events
this.currentlyEntered = [];
};
DroppableWidget.prototype.enterDrag = function(event) {
if(this.currentlyEntered.indexOf(event.target) === -1) {
this.currentlyEntered.push(event.target);
}
// If we're entering for the first time we need to apply highlighting
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
};
DroppableWidget.prototype.leaveDrag = function(event) {
var pos = this.currentlyEntered.indexOf(event.target);
if(pos !== -1) {
this.currentlyEntered.splice(pos,1);
}
// Remove highlighting if we're leaving externally. The hacky second condition is to resolve a problem with Firefox whereby there is an erroneous dragenter event if the node being dragged is within the dropzone
if(this.currentlyEntered.length === 0 || (this.currentlyEntered.length === 1 && this.currentlyEntered[0] === $tw.dragInProgress)) {
this.currentlyEntered = [];
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
}
};
DroppableWidget.prototype.handleDragEnterEvent = function(event) {
this.enterDrag(event);
// Tell the browser that we're ready to handle the drop
event.preventDefault();
// Tell the browser not to ripple the drag up to any parent drop handlers
event.stopPropagation();
return false;
};
DroppableWidget.prototype.handleDragOverEvent = function(event) {
// Check for being over a TEXTAREA or INPUT
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) !== -1) {
return false;
}
// Tell the browser that we're still interested in the drop
event.preventDefault();
// Set the drop effect
event.dataTransfer.dropEffect = this.droppableEffect;
return false;
};
DroppableWidget.prototype.handleDragLeaveEvent = function(event) {
this.leaveDrag(event);
return false;
};
DroppableWidget.prototype.handleDropEvent = function(event) {
var self = this;
this.leaveDrag(event);
// Check for being over a TEXTAREA or INPUT
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) !== -1) {
return false;
}
var dataTransfer = event.dataTransfer;
// Remove highlighting
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
// Try to import the various data types we understand
$tw.utils.importDataTransfer(dataTransfer,null,function(fieldsArray) {
fieldsArray.forEach(function(fields) {
self.performActions(fields.title || fields.text,event);
});
});
// Tell the browser that we handled the drop
event.preventDefault();
// Stop the drop ripple up to any parent handlers
event.stopPropagation();
return false;
};
DroppableWidget.prototype.performActions = function(title,event) {
if(this.droppableActions) {
this.invokeActionString(this.droppableActions,this,event,{actionTiddler: title});
}
};
/*
Compute the internal state of the widget
*/
DroppableWidget.prototype.execute = function() {
this.droppableActions = this.getAttribute("actions");
this.droppableEffect = this.getAttribute("effect","copy");
this.droppableTag = this.getAttribute("tag");
this.droppableClass = this.getAttribute("class");
// Make child widgets
this.makeChildWidgets();
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DroppableWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes["class"] || changedAttributes.tag) {
this.refreshSelf();
return true;
}
return this.refreshChildren(changedTiddlers);
};
exports.droppable = DroppableWidget;
})();

View File

@@ -50,32 +50,35 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) {
parent.insertBefore(domNode,nextSibling);
this.renderChildren(domNode,null);
this.domNodes.push(domNode);
// Stack of outstanding enter/leave events
this.currentlyEntered = [];
};
DropZoneWidget.prototype.enterDrag = function() {
// Check for this window being the source of the drag
if($tw.dragInProgress) {
return false;
DropZoneWidget.prototype.enterDrag = function(event) {
if(this.currentlyEntered.indexOf(event.target) === -1) {
this.currentlyEntered.push(event.target);
}
// We count enter/leave events
this.dragEnterCount = (this.dragEnterCount || 0) + 1;
// If we're entering for the first time we need to apply highlighting
if(this.dragEnterCount === 1) {
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
}
$tw.utils.addClass(this.domNodes[0],"tc-dragover");
};
DropZoneWidget.prototype.leaveDrag = function() {
// Reduce the enter count
this.dragEnterCount = (this.dragEnterCount || 0) - 1;
DropZoneWidget.prototype.leaveDrag = function(event) {
var pos = this.currentlyEntered.indexOf(event.target);
if(pos !== -1) {
this.currentlyEntered.splice(pos,1);
}
// Remove highlighting if we're leaving externally
if(this.dragEnterCount <= 0) {
if(this.currentlyEntered.length === 0) {
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
}
};
DropZoneWidget.prototype.handleDragEnterEvent = function(event) {
this.enterDrag();
// Check for this window being the source of the drag
if($tw.dragInProgress) {
return false;
}
this.enterDrag(event);
// Tell the browser that we're ready to handle the drop
event.preventDefault();
// Tell the browser not to ripple the drag up to any parent drop handlers
@@ -97,11 +100,12 @@ DropZoneWidget.prototype.handleDragOverEvent = function(event) {
};
DropZoneWidget.prototype.handleDragLeaveEvent = function(event) {
this.leaveDrag();
this.leaveDrag(event);
};
DropZoneWidget.prototype.handleDropEvent = function(event) {
this.leaveDrag();
var self = this;
this.leaveDrag(event);
// Check for being over a TEXTAREA or INPUT
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) !== -1) {
return false;
@@ -112,17 +116,20 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
}
var self = this,
dataTransfer = event.dataTransfer;
// Reset the enter count
this.dragEnterCount = 0;
// Remove highlighting
$tw.utils.removeClass(this.domNodes[0],"tc-dragover");
// Import any files in the drop
var numFiles = this.wiki.readFiles(dataTransfer.files,function(tiddlerFieldsArray) {
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray)});
});
var numFiles = 0;
if(dataTransfer.files) {
numFiles = this.wiki.readFiles(dataTransfer.files,function(tiddlerFieldsArray) {
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(tiddlerFieldsArray)});
});
}
// Try to import the various data types we understand
if(numFiles === 0) {
this.importData(dataTransfer);
$tw.utils.importDataTransfer(dataTransfer,this.wiki.generateNewTitle("Untitled"),function(fieldsArray) {
self.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify(fieldsArray)});
});
}
// Tell the browser that we handled the drop
event.preventDefault();
@@ -130,77 +137,6 @@ DropZoneWidget.prototype.handleDropEvent = function(event) {
event.stopPropagation();
};
DropZoneWidget.prototype.importData = function(dataTransfer) {
// Try each provided data type in turn
for(var t=0; t<this.importDataTypes.length; t++) {
if(!$tw.browser.isIE || this.importDataTypes[t].IECompatible) {
// Get the data
var dataType = this.importDataTypes[t];
var data = dataTransfer.getData(dataType.type);
// Import the tiddlers in the data
if(data !== "" && data !== null) {
if($tw.log.IMPORT) {
console.log("Importing data type '" + dataType.type + "', data: '" + data + "'")
}
var tiddlerFields = dataType.convertToFields(data);
if(!tiddlerFields.title) {
tiddlerFields.title = this.wiki.generateNewTitle("Untitled");
}
this.dispatchEvent({type: "tm-import-tiddlers", param: JSON.stringify([tiddlerFields])});
return;
}
}
}
};
DropZoneWidget.prototype.importDataTypes = [
{type: "text/vnd.tiddler", IECompatible: false, convertToFields: function(data) {
return JSON.parse(data);
}},
{type: "URL", IECompatible: true, convertToFields: function(data) {
// Check for tiddler data URI
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
if(match) {
return JSON.parse(match[1]);
} else {
return { // As URL string
text: data
};
}
}},
{type: "text/x-moz-url", IECompatible: false, convertToFields: function(data) {
// Check for tiddler data URI
var match = decodeURIComponent(data).match(/^data\:text\/vnd\.tiddler,(.*)/i);
if(match) {
return JSON.parse(match[1]);
} else {
return { // As URL string
text: data
};
}
}},
{type: "text/html", IECompatible: false, convertToFields: function(data) {
return {
text: data
};
}},
{type: "text/plain", IECompatible: false, convertToFields: function(data) {
return {
text: data
};
}},
{type: "Text", IECompatible: true, convertToFields: function(data) {
return {
text: data
};
}},
{type: "text/uri-list", IECompatible: false, convertToFields: function(data) {
return {
text: data
};
}}
];
DropZoneWidget.prototype.handlePasteEvent = function(event) {
// Let the browser handle it if we're in a textarea or input box
if(["TEXTAREA","INPUT"].indexOf(event.target.tagName) == -1) {

View File

@@ -75,9 +75,9 @@ FieldsWidget.prototype.execute = function() {
value = reMatch[1];
}
}
row = row.replace("$name$",fieldName);
row = row.replace("$value$",value);
row = row.replace("$encoded_value$",$tw.utils.htmlEncode(value));
row = $tw.utils.replaceString(row,"$name$",fieldName);
row = $tw.utils.replaceString(row,"$value$",value);
row = $tw.utils.replaceString(row,"$encoded_value$",$tw.utils.htmlEncode(value));
text.push(row);
}
}

View File

@@ -33,8 +33,12 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
// Compute attributes and execute state
this.computeAttributes();
this.execute();
var tag = this.parseTreeNode.isBlock ? "div" : "span";
if(this.tag && $tw.config.htmlUnsafeElements.indexOf(this.tag) === -1) {
tag = this.tag;
}
// Create element
var domNode = this.document.createElement("div");
var domNode = this.document.createElement(tag);
// Assign classes
var classes = (this["class"] || "").split(" ");
classes.push("tc-keyboard");
@@ -72,6 +76,7 @@ KeyboardWidget.prototype.execute = function() {
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");
// Make child widgets
@@ -83,7 +88,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
KeyboardWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes["class"]) {
if(changedAttributes.message || changedAttributes.param || changedAttributes.key || changedAttributes["class"] || changedAttributes.tag) {
this.refreshSelf();
return true;
}

View File

@@ -82,8 +82,8 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
// Set an href
var wikiLinkTemplateMacro = this.getVariable("tv-wikilink-template"),
wikiLinkTemplate = wikiLinkTemplateMacro ? wikiLinkTemplateMacro.trim() : "#$uri_encoded$",
wikiLinkText = wikiLinkTemplate.replace("$uri_encoded$",encodeURIComponent(this.to));
wikiLinkText = wikiLinkText.replace("$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
wikiLinkText = $tw.utils.replaceString(wikiLinkTemplate,"$uri_encoded$",encodeURIComponent(this.to));
wikiLinkText = $tw.utils.replaceString(wikiLinkText,"$uri_doubleencoded$",encodeURIComponent(encodeURIComponent(this.to)));
wikiLinkText = this.getVariable("tv-get-export-link",{params: [{name: "to",value: this.to}],defaultValue: wikiLinkText});
if(tag === "a") {
domNode.setAttribute("href",wikiLinkText);
@@ -111,11 +111,13 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) {
$tw.utils.addEventListeners(domNode,[
{name: "click", handlerObject: this, handlerMethod: "handleClickEvent"},
]);
// Make the link draggable if required
if(this.draggable === "yes") {
$tw.utils.addEventListeners(domNode,[
{name: "dragstart", handlerObject: this, handlerMethod: "handleDragStartEvent"},
{name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"}
]);
$tw.utils.makeDraggable({
domNode: domNode,
dragTiddlerFn: function() {return self.to;},
widget: this
});
}
// Insert the link into the DOM and render any children
parent.insertBefore(domNode,nextSibling);
@@ -142,67 +144,6 @@ LinkWidget.prototype.handleClickEvent = function(event) {
return false;
};
LinkWidget.prototype.handleDragStartEvent = function(event) {
if(event.target === this.domNodes[0]) {
if(this.to) {
$tw.dragInProgress = true;
// Set the dragging class on the element being dragged
$tw.utils.addClass(event.target,"tc-tiddlylink-dragging");
// Create the drag image elements
this.dragImage = this.document.createElement("div");
this.dragImage.className = "tc-tiddler-dragger";
var inner = this.document.createElement("div");
inner.className = "tc-tiddler-dragger-inner";
inner.appendChild(this.document.createTextNode(this.to));
this.dragImage.appendChild(inner);
this.document.body.appendChild(this.dragImage);
// Astoundingly, we need to cover the dragger up: http://www.kryogenix.org/code/browser/custom-drag-image.html
var cover = this.document.createElement("div");
cover.className = "tc-tiddler-dragger-cover";
cover.style.left = (inner.offsetLeft - 16) + "px";
cover.style.top = (inner.offsetTop - 16) + "px";
cover.style.width = (inner.offsetWidth + 32) + "px";
cover.style.height = (inner.offsetHeight + 32) + "px";
this.dragImage.appendChild(cover);
// Set the data transfer properties
var dataTransfer = event.dataTransfer;
// First the image
dataTransfer.effectAllowed = "copy";
if(dataTransfer.setDragImage) {
dataTransfer.setDragImage(this.dragImage.firstChild,-16,-16);
}
// Then the data
dataTransfer.clearData();
var jsonData = this.wiki.getTiddlerAsJson(this.to),
textData = this.wiki.getTiddlerText(this.to,""),
title = (new RegExp("^" + $tw.config.textPrimitives.wikiLink + "$","mg")).exec(this.to) ? this.to : "[[" + this.to + "]]";
// IE doesn't like these content types
if(!$tw.browser.isIE) {
dataTransfer.setData("text/vnd.tiddler",jsonData);
dataTransfer.setData("text/plain",title);
dataTransfer.setData("text/x-moz-url","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
}
dataTransfer.setData("URL","data:text/vnd.tiddler," + encodeURIComponent(jsonData));
dataTransfer.setData("Text",title);
event.stopPropagation();
} else {
event.preventDefault();
}
}
};
LinkWidget.prototype.handleDragEndEvent = function(event) {
if(event.target === this.domNodes[0]) {
$tw.dragInProgress = false;
// Remove the dragging class on the element being dragged
$tw.utils.removeClass(event.target,"tc-tiddlylink-dragging");
// Delete the drag image element
if(this.dragImage) {
this.dragImage.parentNode.removeChild(this.dragImage);
}
}
};
/*
Compute the internal state of the widget
*/

View File

@@ -43,6 +43,9 @@ ListWidget.prototype.render = function(parent,nextSibling) {
this.renderChildren(parent,nextSibling);
// Construct the storyview
var StoryView = this.storyViews[this.storyViewName];
if(this.storyViewName && !StoryView) {
StoryView = this.storyViews["classic"];
}
if(StoryView && !this.document.isTiddlyWikiFakeDom) {
this.storyview = new StoryView(this);
} else {

View File

@@ -73,7 +73,7 @@ NavigatorWidget.prototype.refresh = function(changedTiddlers) {
this.refreshSelf();
return true;
} else {
return this.refreshChildren(changedTiddlers);
return this.refreshChildren(changedTiddlers);
}
};
@@ -174,6 +174,7 @@ NavigatorWidget.prototype.addToHistory = function(title,fromPageRect) {
Handle a tm-navigate event
*/
NavigatorWidget.prototype.handleNavigateEvent = function(event) {
event = $tw.hooks.invokeHook("th-navigating",event);
if(event.navigateTo) {
this.addToStory(event.navigateTo,event.navigateFromTitle);
if(!event.navigateSuppressNavigation) {
@@ -245,6 +246,7 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
tiddler = this.wiki.getTiddler(title),
storyList = this.getStoryList(),
originalTitle = tiddler ? tiddler.fields["draft.of"] : "",
originalTiddler = originalTitle ? this.wiki.getTiddler(originalTitle) : undefined,
confirmationTitle;
if(!tiddler) {
return false;
@@ -268,10 +270,14 @@ NavigatorWidget.prototype.handleDeleteTiddlerEvent = function(event) {
}
// Delete the original tiddler
if(originalTitle) {
if(originalTiddler) {
$tw.hooks.invokeHook("th-deleting-tiddler",originalTiddler);
}
this.wiki.deleteTiddler(originalTitle);
this.removeTitleFromStory(storyList,originalTitle);
}
// Delete this tiddler
// Invoke the hook function and delete this tiddler
$tw.hooks.invokeHook("th-deleting-tiddler",tiddler);
this.wiki.deleteTiddler(title);
// Remove the closed tiddler from the story
this.removeTitleFromStory(storyList,title);
@@ -349,12 +355,21 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) {
},this.wiki.getModificationFields());
newTiddler = $tw.hooks.invokeHook("th-saving-tiddler",newTiddler);
this.wiki.addTiddler(newTiddler);
// If enabled, relink references to renamed tiddler
var shouldRelink = this.getAttribute("relinkOnRename","no").toLowerCase().trim() === "yes";
if(isRename && shouldRelink && this.wiki.tiddlerExists(draftOf)) {
console.log("Relinking '" + draftOf + "' to '" + draftTitle + "'");
this.wiki.relinkTiddler(draftOf,draftTitle);
}
// Remove the draft tiddler
this.wiki.deleteTiddler(title);
// Remove the original tiddler if we're renaming it
if(isRename) {
this.wiki.deleteTiddler(draftOf);
}
// #2381 always remove new title & old
this.removeTitleFromStory(storyList,draftTitle);
this.removeTitleFromStory(storyList,draftOf);
if(!event.paramObject || event.paramObject.suppressNavigation !== "yes") {
// Replace the draft in the story with the original
this.replaceFirstTitleInStory(storyList,title,draftTitle);
@@ -451,7 +466,7 @@ NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
// Merge the tags
var mergedTags = [];
if(existingTiddler && existingTiddler.fields.tags) {
$tw.utils.pushTop(mergedTags,existingTiddler.fields.tags)
$tw.utils.pushTop(mergedTags,existingTiddler.fields.tags);
}
if(additionalFields && additionalFields.tags) {
// Merge tags
@@ -492,7 +507,6 @@ NavigatorWidget.prototype.handleNewTiddlerEvent = function(event) {
// Import JSON tiddlers into a pending import tiddler
NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
var self = this;
// Get the tiddlers
var tiddlers = [];
try {
@@ -544,7 +558,7 @@ NavigatorWidget.prototype.handleImportTiddlersEvent = function(event) {
history.push(IMPORT_TITLE);
// Save the updated story and history
this.saveStoryList(storyList);
this.addToHistory(history);
this.addToHistory(history);
}
return false;
};
@@ -560,7 +574,9 @@ NavigatorWidget.prototype.handlePerformImportEvent = function(event) {
$tw.utils.each(importData.tiddlers,function(tiddlerFields) {
var title = tiddlerFields.title;
if(title && importTiddler && importTiddler.fields["selection-" + title] !== "unchecked") {
self.wiki.addTiddler(new $tw.Tiddler(tiddlerFields));
var tiddler = new $tw.Tiddler(tiddlerFields);
tiddler = $tw.hooks.invokeHook("th-importing-tiddler",tiddler);
self.wiki.addTiddler(tiddler);
importReport.push("# [[" + tiddlerFields.title + "]]");
}
});
@@ -577,8 +593,7 @@ NavigatorWidget.prototype.handlePerformImportEvent = function(event) {
};
NavigatorWidget.prototype.handleFoldTiddlerEvent = function(event) {
var self = this,
paramObject = event.paramObject || {};
var paramObject = event.paramObject || {};
if(paramObject.foldedState) {
var foldedState = this.wiki.getTiddlerText(paramObject.foldedState,"show") === "show" ? "hide" : "show";
this.wiki.setText(paramObject.foldedState,"text",null,foldedState);
@@ -613,8 +628,7 @@ NavigatorWidget.prototype.handleUnfoldAllTiddlersEvent = function(event) {
};
NavigatorWidget.prototype.handleRenameTiddlerEvent = function(event) {
var self = this,
paramObject = event.paramObject || {},
var paramObject = event.paramObject || {},
from = paramObject.from || event.tiddlerTitle,
to = paramObject.to;
$tw.wiki.renameTiddler(from,to);

View File

@@ -3,22 +3,7 @@ title: $:/core/modules/widgets/radio.js
type: application/javascript
module-type: widget
Radio widget
Will set a field to the selected value:
```
<$radio field="myfield" value="check 1">one</$radio>
<$radio field="myfield" value="check 2">two</$radio>
<$radio field="myfield" value="check 3">three</$radio>
```
|Parameter |Description |h
|tiddler |Name of the tiddler in which the field should be set. Defaults to current tiddler |
|field |The name of the field to be set |
|value |The value to set |
|class |Optional class name(s) |
Set a field or index at a given tiddler via radio buttons
\*/
(function(){
@@ -70,12 +55,20 @@ RadioWidget.prototype.render = function(parent,nextSibling) {
};
RadioWidget.prototype.getValue = function() {
var tiddler = this.wiki.getTiddler(this.radioTitle);
return tiddler && tiddler.getFieldString(this.radioField);
var value,
tiddler = this.wiki.getTiddler(this.radioTitle);
if (this.radioIndex) {
value = this.wiki.extractTiddlerDataItem(this.radioTitle,this.radioIndex);
} else {
value = tiddler && tiddler.getFieldString(this.radioField);
}
return value;
};
RadioWidget.prototype.setValue = function() {
if(this.radioField) {
if(this.radioIndex) {
this.wiki.setText(this.radioTitle,"",this.radioIndex,this.radioValue);
} else {
var tiddler = this.wiki.getTiddler(this.radioTitle),
addition = {};
addition[this.radioField] = this.radioValue;
@@ -96,6 +89,7 @@ RadioWidget.prototype.execute = function() {
// Get the parameters from the attributes
this.radioTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.radioField = this.getAttribute("field","text");
this.radioIndex = this.getAttribute("index");
this.radioValue = this.getAttribute("value");
this.radioClass = this.getAttribute("class","");
if(this.radioClass !== "") {
@@ -111,7 +105,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
RadioWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.value || changedAttributes["class"]) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.value || changedAttributes["class"]) {
this.refreshSelf();
return true;
} else {

View File

@@ -40,6 +40,7 @@ SetWidget.prototype.execute = function() {
// Get our parameters
this.setName = this.getAttribute("name","currentTiddler");
this.setFilter = this.getAttribute("filter");
this.setSelect = this.getAttribute("select");
this.setValue = this.getAttribute("value");
this.setEmptyValue = this.getAttribute("emptyValue");
// Set context variable
@@ -56,7 +57,15 @@ SetWidget.prototype.getValue = function() {
if(this.setFilter) {
var results = this.wiki.filterTiddlers(this.setFilter,this);
if(!this.setValue) {
value = $tw.utils.stringifyList(results);
var select;
if(this.setSelect) {
select = parseInt(this.setSelect,10);
}
if(select !== undefined) {
value = results[select] || "";
} else {
value = $tw.utils.stringifyList(results);
}
}
if(results.length === 0 && this.setEmptyValue !== undefined) {
value = this.setEmptyValue;
@@ -72,7 +81,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
SetWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.name || changedAttributes.filter || changedAttributes.value || changedAttributes.emptyValue ||
if(changedAttributes.name || changedAttributes.filter || changedAttributes.select ||changedAttributes.value || changedAttributes.emptyValue ||
(this.setFilter && this.getValue() != this.variables[this.setName].value)) {
this.refreshSelf();
return true;

View File

@@ -125,7 +125,7 @@ Widget.prototype.substituteVariableParameters = function(text,formalParams,actua
// If we've still not got a value, use the default, if any
paramValue = paramValue || paramInfo["default"] || "";
// Replace any instances of this parameter
text = text.replace(new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
text = $tw.utils.replaceString(text,new RegExp("\\$" + $tw.utils.escapeRegExp(paramInfo.name) + "\\$","mg"),paramValue);
}
}
return text;
@@ -222,7 +222,9 @@ Widget.prototype.computeAttributes = function() {
self = this,
value;
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
if(attribute.type === "indirect") {
if(attribute.type === "filtered") {
value = self.wiki.filterTiddlers(attribute.filter,self)[0] || "";
} else if(attribute.type === "indirect") {
value = self.wiki.getTextReference(attribute.textReference,"",self.getVariable("currentTiddler"));
} else if(attribute.type === "macro") {
value = self.getVariable(attribute.value.name,{params: attribute.value.params});
@@ -493,8 +495,11 @@ Widget.prototype.invokeActions = function(triggeringWidget,event) {
for(var t=0; t<this.children.length; t++) {
var child = this.children[t];
// Invoke the child if it is an action widget
if(child.invokeAction && child.invokeAction(triggeringWidget,event)) {
handled = true;
if(child.invokeAction) {
child.refreshSelf();
if(child.invokeAction(triggeringWidget,event)) {
handled = true;
}
}
// Propagate through through the child if it permits it
if(child.allowActionPropagation() && child.invokeActions(triggeringWidget,event)) {
@@ -507,7 +512,7 @@ Widget.prototype.invokeActions = function(triggeringWidget,event) {
/*
Invoke the action widgets defined in a string
*/
Widget.prototype.invokeActionString = function(actions,triggeringWidget,event) {
Widget.prototype.invokeActionString = function(actions,triggeringWidget,event,variables) {
actions = actions || "";
var parser = this.wiki.parseText("text/vnd.tiddlywiki",actions,{
parentWidget: this,
@@ -515,7 +520,8 @@ Widget.prototype.invokeActionString = function(actions,triggeringWidget,event) {
}),
widgetNode = this.wiki.makeWidget(parser,{
parentWidget: this,
document: this.document
document: this.document,
variables: variables
});
var container = this.document.createElement("div");
widgetNode.render(container,null);

View File

@@ -71,6 +71,9 @@ WikifyWidget.prototype.getResult = function() {
case "text":
result = this.wikifyContainer.textContent;
break;
case "formattedtext":
result = this.wikifyContainer.formattedTextContent;
break;
case "html":
result = this.wikifyContainer.innerHTML;
break;

View File

@@ -15,39 +15,69 @@ Bulk tiddler operations such as rename.
/*
Rename a tiddler, and relink any tags or lists that reference it.
*/
exports.renameTiddler = function(fromTitle,toTitle) {
var self = this;
function renameTiddler(fromTitle,toTitle,options) {
fromTitle = (fromTitle || "").trim();
toTitle = (toTitle || "").trim();
options = options || {};
if(fromTitle && toTitle && fromTitle !== toTitle) {
// Rename the tiddler itself
var tiddler = this.getTiddler(fromTitle);
this.addTiddler(new $tw.Tiddler(tiddler,{title: toTitle},this.getModificationFields()));
var oldTiddler = this.getTiddler(fromTitle),
newTiddler = new $tw.Tiddler(oldTiddler,{title: toTitle},this.getModificationFields());
newTiddler = $tw.hooks.invokeHook("th-renaming-tiddler",newTiddler,oldTiddler);
this.addTiddler(newTiddler);
this.deleteTiddler(fromTitle);
// Rename any tags or lists that reference it
this.each(function(tiddler,title) {
var tags = (tiddler.fields.tags || []).slice(0),
list = (tiddler.fields.list || []).slice(0),
isModified = false;
// Rename tags
$tw.utils.each(tags,function (title,index) {
if(title === fromTitle) {
tags[index] = toTitle;
isModified = true;
}
});
// Rename lists
$tw.utils.each(list,function (title,index) {
if(title === fromTitle) {
list[index] = toTitle;
isModified = true;
}
});
if(isModified) {
self.addTiddler(new $tw.Tiddler(tiddler,{tags: tags, list: list},self.getModificationFields()));
}
});
this.relinkTiddler(fromTitle,toTitle,options)
}
}
/*
Relink any tags or lists that reference a given tiddler
*/
function relinkTiddler(fromTitle,toTitle,options) {
var self = this;
fromTitle = (fromTitle || "").trim();
toTitle = (toTitle || "").trim();
options = options || {};
if(fromTitle && toTitle && fromTitle !== toTitle) {
this.each(function(tiddler,title) {
var type = tiddler.fields.type || "";
// Don't touch plugins or JavaScript modules
if(!tiddler.fields["plugin-type"] && type !== "application/javascript") {
var tags = (tiddler.fields.tags || []).slice(0),
list = (tiddler.fields.list || []).slice(0),
isModified = false;
if(!options.dontRenameInTags) {
// Rename tags
$tw.utils.each(tags,function (title,index) {
if(title === fromTitle) {
console.log("Renaming tag '" + tags[index] + "' to '" + toTitle + "' of tiddler '" + tiddler.fields.title + "'");
tags[index] = toTitle;
isModified = true;
}
});
}
if(!options.dontRenameInLists) {
// Rename lists
$tw.utils.each(list,function (title,index) {
if(title === fromTitle) {
console.log("Renaming list item '" + list[index] + "' to '" + toTitle + "' of tiddler '" + tiddler.fields.title + "'");
list[index] = toTitle;
isModified = true;
}
});
}
if(isModified) {
var newTiddler = new $tw.Tiddler(tiddler,{tags: tags, list: list},self.getModificationFields())
newTiddler = $tw.hooks.invokeHook("th-relinking-tiddler",newTiddler,tiddler);
self.addTiddler(newTiddler);
}
}
});
}
};
exports.renameTiddler = renameTiddler;
exports.relinkTiddler = relinkTiddler;
})();

View File

@@ -24,7 +24,8 @@ Adds the following properties to the wiki object:
var widget = require("$:/core/modules/widgets/widget.js");
var USER_NAME_TITLE = "$:/status/UserName";
var USER_NAME_TITLE = "$:/status/UserName",
TIMESTAMP_DISABLE_TITLE = "$:/config/TimestampDisable";
/*
Get the value of a text reference. Text references can have any of these forms:
@@ -231,27 +232,35 @@ exports.importTiddler = function(tiddler) {
Return a hashmap of the fields that should be set when a tiddler is created
*/
exports.getCreationFields = function() {
var fields = {
created: new Date()
},
creator = this.getTiddlerText(USER_NAME_TITLE);
if(creator) {
fields.creator = creator;
if(this.getTiddlerText(TIMESTAMP_DISABLE_TITLE,"").toLowerCase() !== "yes") {
var fields = {
created: new Date()
},
creator = this.getTiddlerText(USER_NAME_TITLE);
if(creator) {
fields.creator = creator;
}
return fields;
} else {
return {};
}
return fields;
};
/*
Return a hashmap of the fields that should be set when a tiddler is modified
*/
exports.getModificationFields = function() {
var fields = Object.create(null),
modifier = this.getTiddlerText(USER_NAME_TITLE);
fields.modified = new Date();
if(modifier) {
fields.modifier = modifier;
if(this.getTiddlerText(TIMESTAMP_DISABLE_TITLE,"").toLowerCase() !== "yes") {
var fields = Object.create(null),
modifier = this.getTiddlerText(USER_NAME_TITLE);
fields.modified = new Date();
if(modifier) {
fields.modifier = modifier;
}
return fields;
} else {
return {};
}
return fields;
};
/*
@@ -328,7 +337,7 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
var result =
isNaN(x) && !isNaN(y) ? (isDescending ? -1 : 1) :
!isNaN(x) && isNaN(y) ? (isDescending ? 1 : -1) :
(isDescending ? y - x : x - y);
(isDescending ? y - x : x - y);
return result;
};
if(sortField !== "title") {
@@ -632,10 +641,10 @@ exports.getTiddlerDataCached = function(titleOrTiddler,defaultData) {
if(tiddler) {
return this.getCacheForTiddler(tiddler.fields.title,"data",function() {
// Return the frozen value
var value = self.getTiddlerData(tiddler.fields.title,defaultData);
var value = self.getTiddlerData(tiddler.fields.title,undefined);
$tw.utils.deepFreeze(value);
return value;
});
}) || defaultData;
} else {
return defaultData;
}
@@ -671,7 +680,7 @@ exports.getTiddlerData = function(titleOrTiddler,defaultData) {
Extract an indexed field from within a data tiddler
*/
exports.extractTiddlerDataItem = function(titleOrTiddler,index,defaultText) {
var data = this.getTiddlerData(titleOrTiddler,Object.create(null)),
var data = this.getTiddlerDataCached(titleOrTiddler,Object.create(null)),
text;
if(data && $tw.utils.hop(data,index)) {
text = data[index];
@@ -904,31 +913,54 @@ options: as for wiki.makeWidget() plus:
options.field: optional field to transclude (defaults to "text")
options.mode: transclusion mode "inline" or "block"
options.children: optional array of children for the transclude widget
options.importVariables: optional importvariables filter string for macros to be included
options.importPageMacros: optional boolean; if true, equivalent to passing "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]" to options.importVariables
*/
exports.makeTranscludeWidget = function(title,options) {
options = options || {};
var parseTree = {tree: [{
var parseTreeDiv = {tree: [{
type: "element",
tag: "div",
children: [{
type: "transclude",
attributes: {
tiddler: {
name: "tiddler",
type: "string",
value: title}},
isBlock: !options.parseAsInline}]}
]};
children: []}]},
parseTreeImportVariables = {
type: "importvariables",
attributes: {
filter: {
name: "filter",
type: "string"
}
},
isBlock: false,
children: []},
parseTreeTransclude = {
type: "transclude",
attributes: {
tiddler: {
name: "tiddler",
type: "string",
value: title}},
isBlock: !options.parseAsInline};
if(options.importVariables || options.importPageMacros) {
if(options.importVariables) {
parseTreeImportVariables.attributes.filter.value = options.importVariables;
} else if(options.importPageMacros) {
parseTreeImportVariables.attributes.filter.value = "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]";
}
parseTreeDiv.tree[0].children.push(parseTreeImportVariables);
parseTreeImportVariables.children.push(parseTreeTransclude);
} else {
parseTreeDiv.tree[0].children.push(parseTreeTransclude);
}
if(options.field) {
parseTree.tree[0].children[0].attributes.field = {type: "string", value: options.field};
parseTreeTransclude.attributes.field = {type: "string", value: options.field};
}
if(options.mode) {
parseTree.tree[0].children[0].attributes.mode = {type: "string", value: options.mode};
parseTreeTransclude.attributes.mode = {type: "string", value: options.mode};
}
if(options.children) {
parseTree.tree[0].children[0].children = options.children;
parseTreeTransclude.children = options.children;
}
return $tw.wiki.makeWidget(parseTree,options);
return $tw.wiki.makeWidget(parseTreeDiv,options);
};
/*
@@ -1074,6 +1106,22 @@ exports.getTiddlerText = function(title,defaultText) {
}
};
/*
Check whether the text of a tiddler matches a given value. By default, the comparison is case insensitive, and any spaces at either end of the tiddler text is trimmed
*/
exports.checkTiddlerText = function(title,targetText,options) {
options = options || {};
var text = this.getTiddlerText(title,"");
if(!options.noTrim) {
text = text.trim();
}
if(!options.caseSensitive) {
text = text.toLowerCase();
targetText = targetText.toLowerCase();
}
return text === targetText;
}
/*
Read an array of browser File objects, invoking callback(tiddlerFieldsArray) once they're all read
*/
@@ -1118,29 +1166,24 @@ exports.readFile = function(file,callback) {
var reader = new FileReader();
// Onload
reader.onload = function(event) {
// Deserialise the file contents
var text = event.target.result,
tiddlerFields = {title: file.name || "Untitled", type: type};
// Are we binary?
if(isBinary) {
// The base64 section starts after the first comma in the data URI
var commaPos = text.indexOf(",");
if(commaPos !== -1) {
tiddlerFields.text = text.substr(commaPos+1);
callback([tiddlerFields]);
text = text.substr(commaPos + 1);
}
}
// Check whether this is an encrypted TiddlyWiki file
var encryptedJson = $tw.utils.extractEncryptedStoreArea(text);
if(encryptedJson) {
// If so, attempt to decrypt it with the current password
$tw.utils.decryptStoreAreaInteractive(encryptedJson,function(tiddlers) {
callback(tiddlers);
});
} else {
// Check whether this is an encrypted TiddlyWiki file
var encryptedJson = $tw.utils.extractEncryptedStoreArea(text);
if(encryptedJson) {
// If so, attempt to decrypt it with the current password
$tw.utils.decryptStoreAreaInteractive(encryptedJson,function(tiddlers) {
callback(tiddlers);
});
} else {
// Otherwise, just try to deserialise any tiddlers in the file
callback(self.deserializeTiddlers(type,text,tiddlerFields));
}
// Otherwise, just try to deserialise any tiddlers in the file
callback(self.deserializeTiddlers(type,text,tiddlerFields));
}
};
// Kick off the read
@@ -1219,3 +1262,4 @@ exports.invokeUpgraders = function(titles,tiddlers) {
};
})();

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