1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-26 12:53:42 +00:00

Compare commits

...

41 Commits

Author SHA1 Message Date
Jeremy Ruston
e82229210e Version number update for 5.3.2 2023-12-13 08:11:32 +00:00
Jeremy Ruston
c13c321a61 Preparing for release of v5.3.2 2023-12-13 08:10:38 +00:00
Jeremy Ruston
0d2aeb8253 Merge branch 'tiddlywiki-com' 2023-12-12 15:48:52 +00:00
Jeremy Ruston
9d94459c5d Syncer: fix object reference
We should be passing the syncer object, not the task object
2023-12-12 15:48:09 +00:00
Jeremy Ruston
5c283f843b Add banner details to the release note 2023-12-12 09:06:38 +00:00
Jeremy Ruston
51862f8128 Update New Release Banner for v5.3.2 2023-12-12 09:04:37 +00:00
Jeremy Ruston
15e53b8cd1 Revert: #7768 Ensure {{}} doesn't cause a recursion error
See https://github.com/Jermolene/TiddlyWiki5/pull/7768#issuecomment-1850578638
2023-12-11 17:56:11 +00:00
Jeremy Ruston
4a9b3009dd Further fix for d1c7f79dd2
The plus sign needs escaping on some regex engines
2023-12-11 15:21:03 +00:00
etardiff
c9be572baf Signing the CLA (#7879) 2023-12-10 10:01:30 +00:00
Robin Munn
4e06c31022 Move list-join example onto single line (#7877)
It's a little less readable this way, but avoids the whitespace issue.
2023-12-07 08:34:07 +00:00
Mateusz Wilczek
5578fa5f94 Improve jsonset operator docs (#7873)
* Update docs of jsonset operator

* Move jsonset examples into a separate tiddler

* Update jsonset operator docs
2023-12-04 15:24:33 +00:00
Saq Imtiaz
2b0675cac5 Docs: fixes typos in conditonal shortcut syntax docs (#7872)
* Docs: Conditional Shortcut Syntax corrections

* Update Conditional Shortcut Syntax.tid

Add a link to Filter Expression tiddler
2023-12-04 08:53:24 +00:00
Jeremy Ruston
155db0f6f8 Improve release note 2023-12-04 08:13:23 +00:00
Jeremy Ruston
4e67aafeb7 Scrollable hotfix: Avoid setTimeout
See #7869
2023-12-02 08:58:35 +00:00
yaisog
e60ddf0b0a Handle switching the bound tiddler (#7868) 2023-11-30 18:26:26 +00:00
Jeremy Ruston
f7359671aa Defer scrollable widget updating bound tiddler for 100ms
See discussion https://talk.tiddlywiki.org/t/5-3-2pre-scroll-binding/8570/3?u=jeremyruston
2023-11-29 18:06:54 +00:00
Jeremy Ruston
c61c34e9df Debounce scrollable widget scroll handler 2023-11-29 14:45:34 +00:00
Jeremy Ruston
6b47cbed32 Scrollable: write bound value if title of bound tiddler changes
Thanks @yaisog
2023-11-29 14:36:58 +00:00
Jeremy Ruston
c282208668 Fix jsonset crash when applied to primitive types
See https://talk.tiddlywiki.org/t/final-checks-before-release-of-v5-3-2/8560/7
2023-11-29 12:06:40 +00:00
Jeremy Ruston
622512c380 Further reduce syncer logging
The rationale is that the deeper logs are only useful for debugging the syncer logic, and are overwhelming for most users
2023-11-29 11:24:54 +00:00
Jeremy Ruston
f56f5dcc56 Fix savetiddlers handling of tiddlers with no text field 2023-11-29 11:23:57 +00:00
Mateusz Wilczek
fc1e9b6c43 Update forum link in update wizard (#7865)
* Update forum link in upgrade wizard

* Update links to forum in es-ES and de-AT editons
2023-11-29 10:06:47 +00:00
Jeremy Ruston
fe17f16675 Fix syncer not exiting when used on CLI
Fixes #7867
2023-11-29 09:31:19 +00:00
Mateusz Wilczek
b08281a20b Improve jsonstringify and stringify operators docs: part 2 (#7748) 2023-11-29 09:01:46 +00:00
Jeremy Ruston
5dc468f1ea Fix release note typo
Apologies again @oflg
2023-11-28 17:43:57 +00:00
Mario Pietsch
c2e61fffe0 German translations (#7864) 2023-11-28 13:49:13 +00:00
Jeremy Ruston
53d493b876 Conditional shortcut docs: highlight use of "condition" variable 2023-11-28 11:51:56 +00:00
Jeremy Ruston
3b84088b27 Syncer: Reduce logging intensity 2023-11-28 11:44:21 +00:00
Jeremy Ruston
a21f45b93a Release note: fix typos 2023-11-28 10:53:38 +00:00
Bram Chen
8f661423f7 Update chinese translations (#7859)
* Update help for CommandsCommand
2023-11-27 22:01:25 +00:00
Maurycy Zarzycki
6bd69cc53f Add changes to PL translation from 233b871fdf (#7862) 2023-11-27 21:53:42 +00:00
Saq Imtiaz
233b871fdf Update help for CommandsCommand to avoid deduplication (#7858) 2023-11-26 17:42:53 +00:00
Robin Munn
64812f5c06 Add join attribute to list widget (#7694)
* Add join attribute to list widget

* Use new join attribute in HTML saving templates

This simplifies the logic involved in saving tiddlers in JSON format
into TW html files, and should also slightly speed up the saving process
depending on how often that list widget gets refreshed.

* Unit tests for list widget's new join attribute

* Add `<$list-join>` widget

Allows specifying complicated join text more easily than an attribute
2023-11-25 09:35:05 +00:00
Jeremy Ruston
22f9df5850 Update release note 2023-11-24 15:11:21 +00:00
Jeremy Ruston
1cb607249e Fix syncer race condition (#7843)
* Initial commit

* Log task choosing

* A tiny bit more logging

* Typo

* Restructure syncer to use a single state machine
2023-11-24 13:02:09 +00:00
Jeremy Ruston
ca41a8db04 Core macros don't allow pragmas in action strings (#7855)
* First commit

* Transclude preferred over macrocall
2023-11-24 10:48:48 +00:00
Marxsal
ad9cb8a0a8 Modify SetWidget to include use to set global variables. (#7608)
* Modify SetWidget to include use to set global variables.

* Make sample variables easier to read.

* Change text to indicate use of pragma whitespace trim.

* Make compliant with 5.3.1 (?) release
2023-11-21 11:55:54 +00:00
Mario Pietsch
1001590326 Macros -- Make "New in 5.3.0" Info More Prominent (#7750)
* Macros -- Make "New in 5.3.0" Info More Prominent

* Add links to new text substitution possibilities
2023-10-30 14:51:06 +00:00
FrittRo
e593f80278 Signing CLA (#7818) 2023-10-26 22:53:09 +01:00
Jeremy Ruston
8617fa39dc Tweak appearance of Chinese community link 2023-10-20 10:20:14 +01:00
Jeremy Ruston
f89b52e521 Docs: Link to format operator from titlelist tiddler 2023-10-19 15:54:16 +01:00
59 changed files with 871 additions and 428 deletions

View File

@@ -10,7 +10,7 @@ Sequentially run the command tokens returned from a filter
Examples
```
--commands "[enlist{$:/build-commands-as-text}]"
--commands "[enlist:raw{$:/build-commands-as-text}]"
```
```

View File

@@ -46,7 +46,7 @@ Command.prototype.execute = function() {
type = tiddler.fields.type || "text/vnd.tiddlywiki",
contentTypeInfo = $tw.config.contentTypeInfo[type] || {encoding: "utf8"},
filename = path.resolve(pathname,$tw.utils.encodeURIComponentExtended(title));
fs.writeFileSync(filename,tiddler.fields.text,contentTypeInfo.encoding);
fs.writeFileSync(filename,tiddler.fields.text || "",contentTypeInfo.encoding);
});
return null;
};

View File

@@ -273,7 +273,10 @@ function setDataItem(data,indexes,value) {
lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
}
current[lastIndex] = value;
// Only set indexes on objects and arrays
if(typeof current === "object") {
current[lastIndex] = value;
}
return data;
}

View File

@@ -81,9 +81,6 @@ exports.parse = function() {
}
return [tiddlerNode];
} else {
// No template or text reference is provided, so we'll use a blank target. Otherwise we'll generate
// a transclude widget that transcludes the current tiddler, often leading to recursion errors
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: ""};
return [transcludeNode];
}
}

View File

@@ -79,9 +79,6 @@ exports.parse = function() {
}
return [tiddlerNode];
} else {
// No template or text reference is provided, so we'll use a blank target. Otherwise we'll generate
// a transclude widget that transcludes the current tiddler, often leading to recursion errors
transcludeNode.attributes["$tiddler"] = {name: "$tiddler", type: "string", value: ""};
return [transcludeNode];
}
}

View File

@@ -24,7 +24,7 @@ Syncer.prototype.titleSyncPollingInterval = "$:/config/SyncPollingInterval";
Syncer.prototype.titleSyncDisableLazyLoading = "$:/config/SyncDisableLazyLoading";
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
Syncer.prototype.titleSyncThrottleInterval = "$:/config/SyncThrottleInterval";
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
Syncer.prototype.taskTimerInterval = 0.25 * 1000; // Interval for sync timer
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
Syncer.prototype.errorRetryInterval = 5 * 1000; // Interval to retry after an error
Syncer.prototype.fallbackInterval = 10 * 1000; // Unless the task is older than 10s
@@ -74,9 +74,11 @@ function Syncer(options) {
this.titlesHaveBeenLazyLoaded = {}; // Hashmap of titles of tiddlers that have already been lazily loaded from the server
// Timers
this.taskTimerId = null; // Timer for task dispatch
this.pollTimerId = null; // Timer for polling server
// Number of outstanding requests
this.numTasksInProgress = 0;
// True when we want to force an immediate sync from the server
this.forceSyncFromServer = false;
this.timestampLastSyncFromServer = new Date();
// Listen out for changes to tiddlers
this.wiki.addEventListener("change",function(changes) {
// Filter the changes to just include ones that are being synced
@@ -203,33 +205,37 @@ Syncer.prototype.readTiddlerInfo = function() {
Checks whether the wiki is dirty (ie the window shouldn't be closed)
*/
Syncer.prototype.isDirty = function() {
this.logger.log("Checking dirty status");
// Check tiddlers that are in the store and included in the filter function
var titles = this.getSyncedTiddlers();
for(var index=0; index<titles.length; index++) {
var title = titles[index],
tiddlerInfo = this.tiddlerInfo[title];
if(this.wiki.tiddlerExists(title)) {
if(tiddlerInfo) {
// If the tiddler is known on the server and has been modified locally then it needs to be saved to the server
if(this.wiki.getChangeCount(title) > tiddlerInfo.changeCount) {
var self = this;
function checkIsDirty() {
// Check tiddlers that are in the store and included in the filter function
var titles = self.getSyncedTiddlers();
for(var index=0; index<titles.length; index++) {
var title = titles[index],
tiddlerInfo = self.tiddlerInfo[title];
if(self.wiki.tiddlerExists(title)) {
if(tiddlerInfo) {
// If the tiddler is known on the server and has been modified locally then it needs to be saved to the server
if(self.wiki.getChangeCount(title) > tiddlerInfo.changeCount) {
return true;
}
} else {
// If the tiddler isn't known on the server then it needs to be saved to the server
return true;
}
} else {
// If the tiddler isn't known on the server then it needs to be saved to the server
}
}
// Check tiddlers that are known from the server but not currently in the store
titles = Object.keys(self.tiddlerInfo);
for(index=0; index<titles.length; index++) {
if(!self.wiki.tiddlerExists(titles[index])) {
// There must be a pending delete
return true;
}
}
return false;
}
// Check tiddlers that are known from the server but not currently in the store
titles = Object.keys(this.tiddlerInfo);
for(index=0; index<titles.length; index++) {
if(!this.wiki.tiddlerExists(titles[index])) {
// There must be a pending delete
return true;
}
}
return false;
var dirtyStatus = checkIsDirty();
return dirtyStatus;
};
/*
@@ -293,92 +299,16 @@ Syncer.prototype.getStatus = function(callback) {
Synchronise from the server by reading the skinny tiddler list and queuing up loads for any tiddlers that we don't already have up to date
*/
Syncer.prototype.syncFromServer = function() {
var self = this,
cancelNextSync = function() {
if(self.pollTimerId) {
clearTimeout(self.pollTimerId);
self.pollTimerId = null;
}
},
triggerNextSync = function() {
self.pollTimerId = setTimeout(function() {
self.pollTimerId = null;
self.syncFromServer.call(self);
},self.pollTimerInterval);
},
syncSystemFromServer = (self.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
if(this.syncadaptor && this.syncadaptor.getUpdatedTiddlers) {
this.logger.log("Retrieving updated tiddler list");
cancelNextSync();
this.syncadaptor.getUpdatedTiddlers(self,function(err,updates) {
triggerNextSync();
if(err) {
self.displayError($tw.language.getString("Error/RetrievingSkinny"),err);
return;
}
if(updates) {
$tw.utils.each(updates.modifications,function(title) {
self.titlesToBeLoaded[title] = true;
});
$tw.utils.each(updates.deletions,function(title) {
if(syncSystemFromServer || !self.wiki.isSystemTiddler(title)) {
delete self.tiddlerInfo[title];
self.logger.log("Deleting tiddler missing from server:",title);
self.wiki.deleteTiddler(title);
}
});
if(updates.modifications.length > 0 || updates.deletions.length > 0) {
self.processTaskQueue();
}
}
});
} else if(this.syncadaptor && this.syncadaptor.getSkinnyTiddlers) {
this.logger.log("Retrieving skinny tiddler list");
cancelNextSync();
this.syncadaptor.getSkinnyTiddlers(function(err,tiddlers) {
triggerNextSync();
// Check for errors
if(err) {
self.displayError($tw.language.getString("Error/RetrievingSkinny"),err);
return;
}
// Keep track of which tiddlers we already know about have been reported this time
var previousTitles = Object.keys(self.tiddlerInfo);
// Process each incoming tiddler
for(var t=0; t<tiddlers.length; t++) {
// Get the incoming tiddler fields, and the existing tiddler
var tiddlerFields = tiddlers[t],
incomingRevision = tiddlerFields.revision + "",
tiddler = self.wiki.tiddlerExists(tiddlerFields.title) && self.wiki.getTiddler(tiddlerFields.title),
tiddlerInfo = self.tiddlerInfo[tiddlerFields.title],
currRevision = tiddlerInfo ? tiddlerInfo.revision : null,
indexInPreviousTitles = previousTitles.indexOf(tiddlerFields.title);
if(indexInPreviousTitles !== -1) {
previousTitles.splice(indexInPreviousTitles,1);
}
// Ignore the incoming tiddler if it's the same as the revision we've already got
if(currRevision !== incomingRevision) {
// Only load the skinny version if we don't already have a fat version of the tiddler
if(!tiddler || tiddler.fields.text === undefined) {
self.storeTiddler(tiddlerFields);
}
// Do a full load of this tiddler
self.titlesToBeLoaded[tiddlerFields.title] = true;
}
}
// Delete any tiddlers that were previously reported but missing this time
$tw.utils.each(previousTitles,function(title) {
if(syncSystemFromServer || !self.wiki.isSystemTiddler(title)) {
delete self.tiddlerInfo[title];
self.logger.log("Deleting tiddler missing from server:",title);
self.wiki.deleteTiddler(title);
}
});
self.processTaskQueue();
});
if(this.canSyncFromServer()) {
this.forceSyncFromServer = true;
this.processTaskQueue();
}
};
Syncer.prototype.canSyncFromServer = function() {
return !!this.syncadaptor.getUpdatedTiddlers || !!this.syncadaptor.getSkinnyTiddlers;
}
/*
Force load a tiddler from the server
*/
@@ -510,7 +440,7 @@ Syncer.prototype.processTaskQueue = function() {
} else {
self.updateDirtyStatus();
// Process the next task
self.processTaskQueue.call(self);
self.processTaskQueue.call(self);
}
});
} else {
@@ -518,31 +448,39 @@ Syncer.prototype.processTaskQueue = function() {
this.updateDirtyStatus();
// And trigger a timeout if there is a pending task
if(task === true) {
this.triggerTimeout();
this.triggerTimeout(this.taskTimerInterval);
} else if(this.canSyncFromServer()) {
this.triggerTimeout(this.pollTimerInterval);
}
}
} else {
this.updateDirtyStatus();
this.updateDirtyStatus();
this.triggerTimeout(this.taskTimerInterval);
}
};
Syncer.prototype.triggerTimeout = function(interval) {
var self = this;
if(!this.taskTimerId) {
this.taskTimerId = setTimeout(function() {
self.taskTimerId = null;
self.processTaskQueue.call(self);
},interval || self.taskTimerInterval);
if(this.taskTimerId) {
clearTimeout(this.taskTimerId);
}
this.taskTimerId = setTimeout(function() {
self.taskTimerId = null;
self.processTaskQueue.call(self);
},interval || self.taskTimerInterval);
};
/*
Choose the next sync task. We prioritise saves, then deletes, then loads from the server
Choose the next sync task. We prioritise saves to the server, then getting updates from the server, then deletes to the server, then loads from the server
Returns either a task object, null if there's no upcoming tasks, or the boolean true if there are pending tasks that aren't yet due
Returns either:
* a task object
* the boolean true if there are pending sync tasks that aren't yet due
* null if there's no pending sync tasks (just the next poll)
*/
Syncer.prototype.chooseNextTask = function() {
var thresholdLastSaved = (new Date()) - this.throttleInterval,
var now = new Date(),
thresholdLastSaved = now - this.throttleInterval,
havePending = null;
// First we look for tiddlers that have been modified locally and need saving back to the server
var titles = this.getSyncedTiddlers();
@@ -556,14 +494,18 @@ Syncer.prototype.chooseNextTask = function() {
isReadyToSave = !tiddlerInfo || !tiddlerInfo.timestampLastSaved || tiddlerInfo.timestampLastSaved < thresholdLastSaved;
if(hasChanged) {
if(isReadyToSave) {
return new SaveTiddlerTask(this,title);
return new SaveTiddlerTask(this,title);
} else {
havePending = true;
}
}
}
}
// Second, we check tiddlers that are known from the server but not currently in the store, and so need deleting on the server
// Second we check for an outstanding sync from server
if(this.forceSyncFromServer || (this.timestampLastSyncFromServer && (now.valueOf() >= (this.timestampLastSyncFromServer.valueOf() + this.pollTimerInterval)))) {
return new SyncFromServerTask(this);
}
// Third, we check tiddlers that are known from the server but not currently in the store, and so need deleting on the server
titles = Object.keys(this.tiddlerInfo);
for(index=0; index<titles.length; index++) {
title = titles[index];
@@ -573,13 +515,13 @@ Syncer.prototype.chooseNextTask = function() {
return new DeleteTiddlerTask(this,title);
}
}
// Check for tiddlers that need loading
// Finally, check for tiddlers that need loading
title = Object.keys(this.titlesToBeLoaded)[0];
if(title) {
delete this.titlesToBeLoaded[title];
return new LoadTiddlerTask(this,title);
}
// No tasks are ready
// No tasks are ready now, but might be in the future
return havePending;
};
@@ -589,6 +531,10 @@ function SaveTiddlerTask(syncer,title) {
this.type = "save";
}
SaveTiddlerTask.prototype.toString = function() {
return "SAVE " + this.title;
}
SaveTiddlerTask.prototype.run = function(callback) {
var self = this,
changeCount = this.syncer.wiki.getChangeCount(this.title),
@@ -613,7 +559,6 @@ SaveTiddlerTask.prototype.run = function(callback) {
tiddlerInfo: self.syncer.tiddlerInfo[self.title]
});
} else {
this.syncer.logger.log(" Not Dispatching 'save' task:",this.title,"tiddler does not exist");
$tw.utils.nextTick(callback(null));
}
};
@@ -624,6 +569,10 @@ function DeleteTiddlerTask(syncer,title) {
this.type = "delete";
}
DeleteTiddlerTask.prototype.toString = function() {
return "DELETE " + this.title;
}
DeleteTiddlerTask.prototype.run = function(callback) {
var self = this;
this.syncer.logger.log("Dispatching 'delete' task:",this.title);
@@ -647,6 +596,10 @@ function LoadTiddlerTask(syncer,title) {
this.type = "load";
}
LoadTiddlerTask.prototype.toString = function() {
return "LOAD " + this.title;
}
LoadTiddlerTask.prototype.run = function(callback) {
var self = this;
this.syncer.logger.log("Dispatching 'load' task:",this.title);
@@ -664,6 +617,91 @@ LoadTiddlerTask.prototype.run = function(callback) {
});
};
function SyncFromServerTask(syncer) {
this.syncer = syncer;
this.type = "syncfromserver";
}
SyncFromServerTask.prototype.toString = function() {
return "SYNCFROMSERVER";
}
SyncFromServerTask.prototype.run = function(callback) {
var self = this;
var syncSystemFromServer = (self.syncer.wiki.getTiddlerText("$:/config/SyncSystemTiddlersFromServer") === "yes" ? true : false);
var successCallback = function() {
self.syncer.forceSyncFromServer = false;
self.syncer.timestampLastSyncFromServer = new Date();
callback(null);
};
if(this.syncer.syncadaptor.getUpdatedTiddlers) {
this.syncer.syncadaptor.getUpdatedTiddlers(self.syncer,function(err,updates) {
if(err) {
self.syncer.displayError($tw.language.getString("Error/RetrievingSkinny"),err);
return callback(err);
}
if(updates) {
$tw.utils.each(updates.modifications,function(title) {
self.syncer.titlesToBeLoaded[title] = true;
});
$tw.utils.each(updates.deletions,function(title) {
if(syncSystemFromServer || !self.syncer.wiki.isSystemTiddler(title)) {
delete self.syncer.tiddlerInfo[title];
self.syncer.logger.log("Deleting tiddler missing from server:",title);
self.syncer.wiki.deleteTiddler(title);
}
});
}
return successCallback();
});
} else if(this.syncer.syncadaptor.getSkinnyTiddlers) {
this.syncer.syncadaptor.getSkinnyTiddlers(function(err,tiddlers) {
// Check for errors
if(err) {
self.syncer.displayError($tw.language.getString("Error/RetrievingSkinny"),err);
return callback(err);
}
// Keep track of which tiddlers we already know about have been reported this time
var previousTitles = Object.keys(self.syncer.tiddlerInfo);
// Process each incoming tiddler
for(var t=0; t<tiddlers.length; t++) {
// Get the incoming tiddler fields, and the existing tiddler
var tiddlerFields = tiddlers[t],
incomingRevision = tiddlerFields.revision + "",
tiddler = self.syncer.wiki.tiddlerExists(tiddlerFields.title) && self.syncer.wiki.getTiddler(tiddlerFields.title),
tiddlerInfo = self.syncer.tiddlerInfo[tiddlerFields.title],
currRevision = tiddlerInfo ? tiddlerInfo.revision : null,
indexInPreviousTitles = previousTitles.indexOf(tiddlerFields.title);
if(indexInPreviousTitles !== -1) {
previousTitles.splice(indexInPreviousTitles,1);
}
// Ignore the incoming tiddler if it's the same as the revision we've already got
if(currRevision !== incomingRevision) {
// Only load the skinny version if we don't already have a fat version of the tiddler
if(!tiddler || tiddler.fields.text === undefined) {
self.syncer.storeTiddler(tiddlerFields);
}
// Do a full load of this tiddler
self.syncer.titlesToBeLoaded[tiddlerFields.title] = true;
}
}
// Delete any tiddlers that were previously reported but missing this time
$tw.utils.each(previousTitles,function(title) {
if(syncSystemFromServer || !self.syncer.wiki.isSystemTiddler(title)) {
delete self.syncer.tiddlerInfo[title];
self.syncer.logger.log("Deleting tiddler missing from server:",title);
self.syncer.wiki.deleteTiddler(title);
}
});
self.syncer.forceSyncFromServer = false;
self.syncer.timestampLastSyncFromServer = new Date();
return successCallback();
});
} else {
return successCallback();
}
};
exports.Syncer = Syncer;
})();

View File

@@ -50,8 +50,8 @@ ListWidget.prototype.render = function(parent,nextSibling) {
$tw.modules.applyMethods("storyview",this.storyViews);
}
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
var changedAttributes = this.computeAttributes();
this.execute(changedAttributes);
this.renderChildren(parent,nextSibling);
// Construct the storyview
var StoryView = this.storyViews[this.storyViewName];
@@ -71,7 +71,7 @@ ListWidget.prototype.render = function(parent,nextSibling) {
/*
Compute the internal state of the widget
*/
ListWidget.prototype.execute = function() {
ListWidget.prototype.execute = function(changedAttributes) {
var self = this;
// Get our attributes
this.template = this.getAttribute("template");
@@ -80,6 +80,10 @@ ListWidget.prototype.execute = function() {
this.counterName = this.getAttribute("counter");
this.storyViewName = this.getAttribute("storyview");
this.historyTitle = this.getAttribute("history");
// Create join template only if needed
if(this.join === undefined || (changedAttributes && changedAttributes.join)) {
this.join = this.makeJoinTemplate();
}
// Compose the list elements
this.list = this.getTiddlerList();
var members = [],
@@ -102,6 +106,7 @@ ListWidget.prototype.findExplicitTemplates = function() {
var self = this;
this.explicitListTemplate = null;
this.explicitEmptyTemplate = null;
this.explicitJoinTemplate = null;
this.hasTemplateInBody = false;
var searchChildren = function(childNodes) {
$tw.utils.each(childNodes,function(node) {
@@ -109,6 +114,8 @@ ListWidget.prototype.findExplicitTemplates = function() {
self.explicitListTemplate = node.children;
} else if(node.type === "list-empty") {
self.explicitEmptyTemplate = node.children;
} else if(node.type === "list-join") {
self.explicitJoinTemplate = node.children;
} else if(node.type === "element" && node.tag === "p") {
searchChildren(node.children);
} else {
@@ -152,6 +159,24 @@ ListWidget.prototype.getEmptyMessage = function() {
}
};
/*
Compose the template for a join between list items
*/
ListWidget.prototype.makeJoinTemplate = function() {
var parser,
join = this.getAttribute("join","");
if(join) {
parser = this.wiki.parseText("text/vnd.tiddlywiki",join,{parseAsInline:true})
if(parser) {
return parser.tree;
} else {
return [];
}
} else {
return this.explicitJoinTemplate; // May be null, and that's fine
}
};
/*
Compose the template for a list item
*/
@@ -160,6 +185,7 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
var tiddler = this.wiki.getTiddler(title),
isDraft = tiddler && tiddler.hasField("draft.of"),
template = this.template,
join = this.join,
templateTree;
if(isDraft && this.editTemplate) {
template = this.editTemplate;
@@ -185,12 +211,12 @@ ListWidget.prototype.makeItemTemplate = function(title,index) {
}
}
// Return the list item
var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree};
var parseTreeNode = {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree, join: join};
parseTreeNode.isLast = index === this.list.length - 1;
if(this.counterName) {
parseTreeNode.counter = (index + 1).toString();
parseTreeNode.counterName = this.counterName;
parseTreeNode.isFirst = index === 0;
parseTreeNode.isLast = index === this.list.length - 1;
}
return parseTreeNode;
};
@@ -206,7 +232,7 @@ ListWidget.prototype.refresh = function(changedTiddlers) {
this.storyview.refreshStart(changedTiddlers,changedAttributes);
}
// Completely refresh if any of our attributes have changed
if(changedAttributes.filter || changedAttributes.variable || changedAttributes.counter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
if(changedAttributes.filter || changedAttributes.variable || changedAttributes.counter || changedAttributes.template || changedAttributes.editTemplate || changedAttributes.join || changedAttributes.emptyMessage || changedAttributes.storyview || changedAttributes.history) {
this.refreshSelf();
result = true;
} else {
@@ -310,10 +336,29 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
}
} else {
// Cycle through the list, inserting and removing list items as needed
var mustRecreateLastItem = false;
if(this.join && this.join.length) {
if(this.children.length !== this.list.length) {
mustRecreateLastItem = true;
} else if(prevList[prevList.length-1] !== this.list[this.list.length-1]) {
mustRecreateLastItem = true;
}
}
var isLast = false, wasLast = false;
for(t=0; t<this.list.length; t++) {
isLast = t === this.list.length-1;
var index = this.findListItem(t,this.list[t]);
wasLast = index === this.children.length-1;
if(wasLast && (index !== t || this.children.length !== this.list.length)) {
mustRecreateLastItem = !!(this.join && this.join.length);
}
if(index === undefined) {
// The list item must be inserted
if(isLast && mustRecreateLastItem && t>0) {
// First re-create previosly-last item that will no longer be last
this.removeListItem(t-1);
this.insertListItem(t-1,this.list[t-1]);
}
this.insertListItem(t,this.list[t]);
hasRefreshed = true;
} else {
@@ -322,9 +367,15 @@ ListWidget.prototype.handleListChanges = function(changedTiddlers) {
this.removeListItem(n);
hasRefreshed = true;
}
// Refresh the item we're reusing
var refreshed = this.children[t].refresh(changedTiddlers);
hasRefreshed = hasRefreshed || refreshed;
// Refresh the item we're reusing, or recreate if necessary
if(mustRecreateLastItem && (isLast || wasLast)) {
this.removeListItem(t);
this.insertListItem(t,this.list[t]);
hasRefreshed = true;
} else {
var refreshed = this.children[t].refresh(changedTiddlers);
hasRefreshed = hasRefreshed || refreshed;
}
}
}
}
@@ -414,8 +465,17 @@ ListItemWidget.prototype.execute = function() {
this.setVariable(this.parseTreeNode.counterName + "-first",this.parseTreeNode.isFirst ? "yes" : "no");
this.setVariable(this.parseTreeNode.counterName + "-last",this.parseTreeNode.isLast ? "yes" : "no");
}
// Add join if needed
var children = this.parseTreeNode.children,
join = this.parseTreeNode.join;
if(join && join.length && !this.parseTreeNode.isLast) {
children = children.slice(0);
$tw.utils.each(join,function(joinNode) {
children.push(joinNode);
})
}
// Construct the child widgets
this.makeChildWidgets();
this.makeChildWidgets(children);
};
/*
@@ -450,4 +510,14 @@ ListEmptyWidget.prototype.refresh = function() { return false; }
exports["list-empty"] = ListEmptyWidget;
var ListJoinWidget = function(parseTreeNode,options) {
// Main initialisation inherited from widget.js
this.initialise(parseTreeNode,options);
};
ListJoinWidget.prototype = new Widget();
ListJoinWidget.prototype.render = function() {}
ListJoinWidget.prototype.refresh = function() { return false; }
exports["list-join"] = ListJoinWidget;
})();

View File

@@ -12,6 +12,8 @@ Scrollable widget
/*global $tw: false */
"use strict";
var DEBOUNCE_INTERVAL = 100; // Delay after last scroll event before updating the bound tiddler
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var ScrollableWidget = function(parseTreeNode,options) {
@@ -174,22 +176,29 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
// If the scroll position is bound to a tiddler
if(this.scrollableBind) {
// After a delay for rendering, scroll to the bound position
setTimeout(this.updateScrollPositionFromBoundTiddler.bind(this),50);
// Save scroll position on DOM scroll event
this.outerDomNode.addEventListener("scroll",function(event) {
var existingTiddler = self.wiki.getTiddler(self.scrollableBind),
newTiddlerFields = {
title: self.scrollableBind,
"scroll-left": self.outerDomNode.scrollLeft.toString(),
"scroll-top": self.outerDomNode.scrollTop.toString()
};
if(!existingTiddler || (existingTiddler.fields["scroll-left"] !== newTiddlerFields["scroll-left"] || existingTiddler.fields["scroll-top"] !== newTiddlerFields["scroll-top"])) {
self.wiki.addTiddler(new $tw.Tiddler(existingTiddler,newTiddlerFields));
}
});
this.updateScrollPositionFromBoundTiddler();
// Set up event listener
this.currentListener = this.listenerFunction.bind(this);
this.outerDomNode.addEventListener("scroll", this.currentListener);
}
};
ScrollableWidget.prototype.listenerFunction = function(event) {
self = this;
clearTimeout(this.timeout);
this.timeout = setTimeout(function() {
var existingTiddler = self.wiki.getTiddler(self.scrollableBind),
newTiddlerFields = {
title: self.scrollableBind,
"scroll-left": self.outerDomNode.scrollLeft.toString(),
"scroll-top": self.outerDomNode.scrollTop.toString()
};
if(!existingTiddler || (existingTiddler.fields["title"] !== newTiddlerFields["title"]) || (existingTiddler.fields["scroll-left"] !== newTiddlerFields["scroll-left"] || existingTiddler.fields["scroll-top"] !== newTiddlerFields["scroll-top"])) {
self.wiki.addTiddler(new $tw.Tiddler(existingTiddler,newTiddlerFields));
}
}, DEBOUNCE_INTERVAL);
}
ScrollableWidget.prototype.updateScrollPositionFromBoundTiddler = function() {
// Bail if we're running on the fakedom
if(!this.outerDomNode.scrollTo) {
@@ -234,10 +243,22 @@ ScrollableWidget.prototype.refresh = function(changedTiddlers) {
this.refreshSelf();
return true;
}
if(changedAttributes.bind || changedTiddlers[this.getAttribute("bind")]) {
// If the bound tiddler has changed, update the eventListener and update scroll position
if(changedAttributes["bind"]) {
if(this.currentListener) {
this.outerDomNode.removeEventListener("scroll", this.currentListener, false);
}
this.scrollableBind = this.getAttribute("bind");
this.currentListener = this.listenerFunction.bind(this);
this.outerDomNode.addEventListener("scroll", this.currentListener);
}
// Refresh children
var result = this.refreshChildren(changedTiddlers);
// If the bound tiddler has changed, update scroll position
if(changedAttributes["bind"] || changedTiddlers[this.getAttribute("bind")]) {
this.updateScrollPositionFromBoundTiddler();
}
return this.refreshChildren(changedTiddlers);
return result;
};
exports.scrollable = ScrollableWidget;

View File

@@ -1,4 +1,3 @@
title: $:/core/templates/html-json-skinny-tiddler
<$list filter="[<numTiddlers>compare:number:gteq[1]] ~[<counter>!match[1]]">`,`<$text text=<<newline>>/></$list>
<$jsontiddler tiddler=<<currentTiddler>> exclude="text" escapeUnsafeScriptChars="yes"/>

View File

@@ -1,3 +1,3 @@
title: $:/core/templates/html-json-tiddler
<$list filter="[<counter>!match[1]]">`,`<$text text=<<newline>>/></$list><$jsontiddler tiddler=<<currentTiddler>> escapeUnsafeScriptChars="yes"/>
<$jsontiddler tiddler=<<currentTiddler>> escapeUnsafeScriptChars="yes"/>

View File

@@ -6,14 +6,14 @@ title: $:/core/templates/store.area.template.html
<$list filter="[[storeAreaFormat]is[variable]getvariable[]else[json]match[json]]">
<!-- New-style JSON store area, with an old-style store area for compatibility with v5.1.x tooling -->
`<script class="tiddlywiki-tiddler-store" type="application/json">[`
<$vars newline={{{ [charcode[10]] }}}>
<$let newline={{{ [charcode[10]] }}} join=`,$(newline)$`>
<$text text=<<newline>>/>
<$list filter=<<saveTiddlerFilter>> counter="counter" template="$:/core/templates/html-json-tiddler"/>
<$list filter=<<saveTiddlerFilter>> join=<<join>> template="$:/core/templates/html-json-tiddler"/>
<$vars numTiddlers={{{ [subfilter<saveTiddlerFilter>count[]] }}}>
<$list filter={{{ [<skinnySaveTiddlerFilter>] }}} counter="counter" template="$:/core/templates/html-json-skinny-tiddler"/>
<$list filter={{{ [<skinnySaveTiddlerFilter>] }}} join=<<join>> template="$:/core/templates/html-json-skinny-tiddler"/>
</$vars>
<$text text=<<newline>>/>
</$vars>
</$let>
`]</script>`
`<div id="storeArea" style="display:none;">`
`</div>`

View File

@@ -4,11 +4,8 @@ tags: $:/tags/ViewTemplate
\whitespace trim
<$reveal type="nomatch" stateTitle=<<folded-state>> text="hide" tag="div" retain="yes" animate="yes">
<div class="tc-subtitle">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate/Subtitle]!has[draft.of]]" variable="subtitleTiddler" counter="indexSubtitleTiddler">
<$list filter="[<indexSubtitleTiddler-first>match[no]]" variable="ignore">
&nbsp;
</$list>
<$transclude tiddler=<<subtitleTiddler>> mode="inline"/>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ViewTemplate/Subtitle]!has[draft.of]]" variable="subtitleTiddler">
<$transclude tiddler=<<subtitleTiddler>> mode="inline"/><$list-join>&nbsp;</$list-join>
</$list>
</div>
</$reveal>

View File

@@ -13,7 +13,7 @@ tags: $:/tags/Macro
$(colour-picker-update-recent)$
$actions$
<$transclude $variable="__actions__"/>
<span style="display:inline-block; background-color: $(colour-picker-value)$; width: 100%; height: 100%; border-radius: 50%;"/>
@@ -23,7 +23,7 @@ $actions$
\define colour-picker-recent-inner(actions)
\whitespace trim
<$set name="colour-picker-value" value="$(recentColour)$">
<$macrocall $name="colour-picker-inner" actions="""$actions$"""/>
<$macrocall $name="colour-picker-inner" actions=<<__actions__>>/>
</$set>
\end
@@ -31,7 +31,7 @@ $actions$
\whitespace trim
{{$:/language/ColourPicker/Recent}}<$list filter="[list[$:/config/ColourPicker/Recent]]" variable="recentColour">
&#32;
<$macrocall $name="colour-picker-recent-inner" actions="""$actions$"""/>
<$macrocall $name="colour-picker-recent-inner" actions=<<__actions__>>/>
</$list>
\end
@@ -39,13 +39,13 @@ $actions$
\whitespace trim
<div class="tc-colour-chooser">
<$macrocall $name="colour-picker-recent" actions="""$actions$"""/>
<$macrocall $name="colour-picker-recent" actions=<<__actions__>>/>
---
<$list filter="LightPink Pink Crimson LavenderBlush PaleVioletRed HotPink DeepPink MediumVioletRed Orchid Thistle Plum Violet Magenta Fuchsia DarkMagenta Purple MediumOrchid DarkViolet DarkOrchid Indigo BlueViolet MediumPurple MediumSlateBlue SlateBlue DarkSlateBlue Lavender GhostWhite Blue MediumBlue MidnightBlue DarkBlue Navy RoyalBlue CornflowerBlue LightSteelBlue LightSlateGrey SlateGrey DodgerBlue AliceBlue SteelBlue LightSkyBlue SkyBlue DeepSkyBlue LightBlue PowderBlue CadetBlue Azure LightCyan PaleTurquoise Cyan Aqua DarkTurquoise DarkSlateGrey DarkCyan Teal MediumTurquoise LightSeaGreen Turquoise Aquamarine MediumAquamarine MediumSpringGreen MintCream SpringGreen MediumSeaGreen SeaGreen Honeydew LightGreen PaleGreen DarkSeaGreen LimeGreen Lime ForestGreen Green DarkGreen Chartreuse LawnGreen GreenYellow DarkOliveGreen YellowGreen OliveDrab Beige LightGoldenrodYellow Ivory LightYellow Yellow Olive DarkKhaki LemonChiffon PaleGoldenrod Khaki Gold Cornsilk Goldenrod DarkGoldenrod FloralWhite OldLace Wheat Moccasin Orange PapayaWhip BlanchedAlmond NavajoWhite AntiqueWhite Tan BurlyWood Bisque DarkOrange Linen Peru PeachPuff SandyBrown Chocolate SaddleBrown Seashell Sienna LightSalmon Coral OrangeRed DarkSalmon Tomato MistyRose Salmon Snow LightCoral RosyBrown IndianRed Red Brown FireBrick DarkRed Maroon White WhiteSmoke Gainsboro LightGrey Silver DarkGrey Grey DimGrey Black" variable="colour-picker-value">
&#32;
<$macrocall $name="colour-picker-inner" actions="""$actions$"""/>
<$macrocall $name="colour-picker-inner" actions=<<__actions__>>/>
</$list>
---
@@ -54,7 +54,7 @@ $actions$
&#32;
<$edit-text tiddler="$:/config/ColourPicker/New" type="color" tag="input"/>
<$set name="colour-picker-value" value={{$:/config/ColourPicker/New}}>
<$macrocall $name="colour-picker-inner" actions="""$actions$"""/>
<$macrocall $name="colour-picker-inner" actions=<<__actions__>>/>
</$set>
</div>

View File

@@ -5,13 +5,13 @@ title: $:/core/macros/image-picker
type: text/vnd.tiddlywiki
\define image-picker-thumbnail(actions)
<$button tag="a" tooltip="""$(imageTitle)$""">$actions$<$transclude tiddler=<<imageTitle>>/></$button>
<$button tag="a" tooltip="""$(imageTitle)$"""><$transclude $variable="__actions__"/><$transclude tiddler=<<imageTitle>>/></$button>
\end
\define image-picker-list(filter,actions)
\whitespace trim
<$list filter="""$filter$""" variable="imageTitle">
<$macrocall $name="image-picker-thumbnail" actions="""$actions$"""/>
<$macrocall $name="image-picker-thumbnail" actions=<<__actions__>>/>
&#32;
</$list>
\end
@@ -25,15 +25,15 @@ type: text/vnd.tiddlywiki
{{$:/language/SystemTiddlers/Include/Prompt}}
</$checkbox>
<$reveal state=<<state-system>> type="match" text="hide" default="hide" tag="div">
<$macrocall $name="image-picker-list" filter="""$filter$ +[!is[system]]""" actions="""$actions$"""/>
<$macrocall $name="image-picker-list" filter="""$filter$ +[!is[system]]""" actions=<<__actions__>>/>
</$reveal>
<$reveal state=<<state-system>> type="nomatch" text="hide" default="hide" tag="div">
<$macrocall $name="image-picker-list" filter="""$filter$""" actions="""$actions$"""/>
<$macrocall $name="image-picker-list" filter="""$filter$""" actions=<<__actions__>>/>
</$reveal>
</$vars>
</div>
\end
\define image-picker-include-tagged-images(actions)
<$macrocall $name="image-picker" filter="[all[shadows+tiddlers]is[image]] [all[shadows+tiddlers]tag[$:/tags/Image]] -[type[application/pdf]] +[!has[draft.of]sort[title]]" actions="""$actions$"""/>
<$macrocall $name="image-picker" filter="[all[shadows+tiddlers]is[image]] [all[shadows+tiddlers]tag[$:/tags/Image]] -[type[application/pdf]] +[!has[draft.of]sort[title]]" actions=<<__actions__>>/>
\end

View File

@@ -16,7 +16,7 @@ second-search-filter: [tags[]is[system]search:title<userInput>sort[]]
emptyMessage="<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter='-[<tag>]'/>"
>
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>trim[]]"/>
$actions$
<$transclude $variable="__actions__"/>
</$list>
</$set>
<<delete-tag-state-tiddlers>>
@@ -102,7 +102,7 @@ second-search-filter: [tags[]is[system]search:title<userInput>sort[]]
<$set name="tag" value={{{ [<newTagNameTiddler>get[text]] }}}>
<$button set=<<newTagNameTiddler>> setTo="" class="">
<$action-listops $tiddler=<<saveTiddler>> $field=<<__tagField__>> $subfilter="[<tag>trim[]]"/>
$actions$
<$transclude $variable="__actions__"/>
<$set name="currentTiddlerCSSEscaped" value={{{ [<saveTiddler>escapecss[]] }}}>
<<delete-tag-state-tiddlers>><$action-sendmessage $message="tm-focus-selector" $param=<<get-tagpicker-focus-selector>>/>
</$set>

View File

@@ -21,8 +21,8 @@ Willkommen bei ''~TiddlyWiki'', dem einzigartigen [[nicht-linearen|Philosophy vo
Anders, als bei herkömmlichen Online-Diensten, lässt Ihnen ~TiddlyWiki die Freiheit, wo sie ihre Daten speichern. Da ~TiddlyWiki alle Daten als simplen Text speichert, sind Notizen, die Sie heute machen, garantiert in Jahrzehnten noch einfach lesbar.
<div style="font-size:0.7em;text-align:center;margin-top:3em;margin-bottom:3em;">
<a href="http://groups.google.com/group/TiddlyWiki" class="tc-btn-big-green" style="background-color:#FF8C19;" target="_blank">
{{$:/core/images/mail}} ~TiddlyWiki Mailing List
<a href="https://talk.tiddlywiki.org/" class="tc-btn-big-green" style="background-color:#FF8C19;" target="_blank">
{{$:/core/images/help}} ~TiddlyWiki Forum
</a>
<a href="https://twitter.com/TiddlyWiki" class="tc-btn-big-green" style="background-color:#5E9FCA;" target="_blank">
{{$:/core/images/twitter}} @~TiddlyWiki on Twitter

View File

@@ -7,5 +7,5 @@ type: text/vnd.tiddlywiki
Es gibt mehrere Ressourcen für Entwickler, um mehr über das TiddlyWiki Projekt zu erfahren, zu diskutieren und vor allem mitzuhelfen.
* [[tiddlywiki.com/dev|https://tiddlywiki.com/dev]] Offizielle Entwickler Doku.
* [[TiddlyWikiDev group|http://groups.google.com/group/TiddlyWikiDev]] Google Diskussionsforum für Entwickler.
* [[TiddlyWikiDev group|https://talk.tiddlywiki.org/c/devs/]] Diskussionsforum für Entwickler.
* https://github.com/Jermolene/TiddlyWiki5 .. Github Repository.

View File

@@ -12,7 +12,9 @@ Son listas de correo en las que hablamos de ~TiddlyWiki: pedimos ayuda, anunciam
Puedes participar a través de la página web asociada, o suscribirte via mail.
!!Usuarios
!! Usuarios
[[Foro oficial de TiddlyWiki| https://talk.tiddlywiki.org/]]
[[Grupo principal de TiddlyWiki| http://groups.google.com/group/TiddlyWiki]]
@@ -25,10 +27,7 @@ o síguenos [[en Twitter|http://twitter.com/TiddlyWiki]] si quieres recibir las
!! Desarrolladores
[[Grupo de desarrollo de TiddlyWiki|http://groups.google.com/group/TiddlyWikiDev]]
>No necesitas tener cuenta en Google para acceder al grupo. Suscríbete igualmente enviando un mail a:
*mailto:tiddlywikidev+subscribe@googlegroups.com.
[[Foro de desarrollo de TiddlyWiki|https://talk.tiddlywiki.org/c/devs]]
Accede a nuestra [[página de desarrollo|https://github.com/Jermolene/TiddlyWiki5]] en GitHub y haz tu contribución.

View File

@@ -20,8 +20,8 @@ BIenvenido a TiddlyWiki, un bloc de notas [[no lineal|Philosophy of Tiddlers]]
Al revés que los servicios online convencionales, TiddlyWiki te deja escoger dónde quieres guardar tus datos, garantizándote que, por más que pase el tiempo, podrás seguir usando en el futuro las notas que tomes hoy.
<div style="font-size:0.7em;text-align:center;margin-top:3em;margin-bottom:3em;">
<a href="http://groups.google.com/group/TiddlyWiki" class="tc-btn-big-green" style="background-color:#FF8C19;" target="_blank" rel="noopener noreferrer">
{{$:/core/images/mail}} ~TiddlyWiki en Google Groups
<a href="https://talk.tiddlywiki.org/" class="tc-btn-big-green" style="background-color:#FF8C19;" target="_blank" rel="noopener noreferrer">
{{$:/core/images/mail}} Foro oficial de ~TiddlyWiki
</a>
<a href="https://www.youtube.com/c/JeremyRuston" class="tc-btn-big-green" style="background-color:#e52d27;" target="_blank" rel="noopener noreferrer">
{{$:/core/images/video}} ~TiddlyWiki en ~YouTube

View File

@@ -8,7 +8,7 @@ type: text/vnd.tiddlywiki
Se recomienda el uso de las [[macros de documentación|Documentation Macros]] para facilitar las futuras tareas de mantenimiento del texto frente a nuevos cambios y actualizaciones.
Se recomienda precaución en el uso arbitrario de estilos directos de formato (''negrita'', //cursiva// ...etc). Si se puede usar una macro, conviene usarla. Si no existe la macro adecuada, se puede crear o, si no se sabe cómo, pedir su creación en el [[Grupo de Google|http://groups.google.com/group/TiddlyWiki]].
Se recomienda precaución en el uso arbitrario de estilos directos de formato (''negrita'', //cursiva// ...etc). Si se puede usar una macro, conviene usarla. Si no existe la macro adecuada, se puede crear o, si no se sabe cómo, pedir su creación en el [[Foro de TiddlyWiki|https://talk.tiddlywiki.org/]].
Por el mismo motivo, se aconseja el uso de acentos graves <code>&#96;...&#96;</code> para transcribir fragmentos de código y ~WikiText, pero no para nombres de cosas tales como campos, operadores, variables o widgets. Estas tienen su macro correspondiente.

View File

@@ -1,122 +0,0 @@
caption: 5.3.2
created: 20231016122502955
modified: 20231016122502955
tags: ReleaseNotes
title: Release 5.3.2
type: text/vnd.tiddlywiki
description: Under development
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.3.1...master]]//
! Major Improvements
!! Conditional Shortcut Syntax
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7710">> a new [[shortcut syntax|Conditional Shortcut Syntax]] for concisely expressing if-then-else logic. For example:
```
<% if [<animal>match[Elephant]] %>
It is an elephant
<% elseif [<animal>match[Giraffe]] %>
It is a giraffe
<% else %>
It is completely unknown
<% endif %>
```
!! Explicit Templates for the ListWidget
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7784">> support for `<$list-template>` and `<$list-empty>` as immediate children of the <<.wid "ListWidget">> widget to specify the list item template and/or the empty template. For example:
```
<$list filter=<<filter>>>
<$list-template>
<$text text=<<currentTiddler>>/>
</$list-template>
<$list-empty>
None!
</$list-empty>
</$list>
```
Note that the <<.attr "emptyMessage">> and <<.attr "template">> attributes take precedence if they are present.
!! jsonset operator
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7742">> [[jsonset Operator]] for setting values within JSON objects
!! QR Code Reader
<<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7746">> QR Code plugin to be able to read QR codes and a number of other bar code formats
! Translation improvement
Improvements to the following translations:
* Chinese
* Polish
* Spanish
! Plugin Improvements
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/1be8f0a9336952d4745d2bd4f2327e353580a272">> Comments Plugin to use predefined palette colours
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7785">> Evernote Importer Plugin to support images and other attachments
! Widget Improvements
*
! Usability Improvements
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7747">> editor preview button to automatically focus the editor
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7764">> file type names in the export menu
! Hackability Improvements
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7737">> an automatic build of the external core TiddlyWiki at https://tiddlywiki.com/empty-external-core.html
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7690">> the default page layout to better support CSS grid and flexbox layouts
! Bug Fixes
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/issues/7665">> `{{}}` generating a recursion error
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7758">> ordering of Vanilla stylesheets
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/fa9bfa07a095548eb2f8339b0b1b816d2e6794ef">> missing closing tag in tag-pill-inner macro
* <<.link-badge-removed "https://github.com/Jermolene/TiddlyWiki5/issues/7732">> invalid "type" attribute from textarea elements generated by the EditTextWidget
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7749">> editor "type" dropdown state tiddlers
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7712">> handling of "counter-last" variable when appending items with the ListWidget
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/6088">> upgrade download link in Firefox
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7698">> refreshing of transcluded functions
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7789">> resizing of height of textareas in control panel
! Node.js Improvements
*
! Performance Improvements
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7702">> performance of predefined patterns with [[all Operator]]
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/issues/7671">> favicon format to PNG
! Developer Improvements
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7751">> global hook handling to support removing hooks
! Acknowledgements
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
<<.contributors """
AnthonyMuscio
BramChen
BuckarooBanzay
BurningTreeC
EvidentlyCube
joebordes
kookma
linonetwo
mateuszwilczek
pmario
rmunn
simonbaird
T1mL3arn
""">>

View File

@@ -0,0 +1,58 @@
caption: 5.3.3
created: 20231213080754563
modified: 20231213080754563
tags: ReleaseNotes
title: Release 5.3.3
type: text/vnd.tiddlywiki
description: Under development
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.3.2...master]]//
! Translation improvements
Improvements to the following translations:
*
! Plugin Improvements
*
! Widget Improvements
*
! Usability Improvements
*
! Hackability Improvements
*
! Bug Fixes
*
! Node.js Improvements
*
! Performance Improvements
*
! Developer Improvements
*
! Infrastructure Improvements
*
! Acknowledgements
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
<<.contributors """
""">>

View File

@@ -0,0 +1,30 @@
title: ListWidget/WithJoinTemplate
description: List widget with join template and $list-empty
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
+
title: Output
\whitespace trim
\procedure test(filter)
<$list filter=<<filter>>>
Item:<<currentTiddler>>
<$list-empty>
None!
</$list-empty>
<$list-join>,</$list-join>
</$list>
\end
<<test "1 2 3">>
<<test "">>
+
title: ExpectedResult
<p>Item:1,Item:2,Item:3</p><p>None!</p>

View File

@@ -0,0 +1,32 @@
title: ListWidget/WithJoinTemplateInBlockMode
description: List widget with join template and $list-empty in block mode
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
+
title: Output
\whitespace trim
\procedure test(filter)
<$list filter=<<filter>>>
Item:<<currentTiddler>>
<$list-empty>
None!
</$list-empty>
<$list-join><br></$list-join>
</$list>
\end
<<test "1 2 3">>
<<test "">>
+
title: ExpectedResult
comment: I wish there was a good way to get rid of these extraneous paragraph elements
<p>Item:1</p><p></p><p></p><br><p>Item:2</p><p></p><p></p><br><p>Item:3</p><p></p><p></p>None!

View File

@@ -124,6 +124,7 @@ describe("json filter tests", function() {
});
it("should support the jsonset operator", function() {
expect(wiki.filterTiddlers("[jsonset[a],[aa]]")).toEqual(['"First"','"Second"','"Third"']);
expect(wiki.filterTiddlers("[{First}jsonset[]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
expect(wiki.filterTiddlers("[{First}jsonset[],[Antelope]]")).toEqual(['"Antelope"']);
expect(wiki.filterTiddlers("[{First}jsonset:number[],[not a number]]")).toEqual(['0']);

View File

@@ -527,6 +527,45 @@ describe("Widget module", function() {
expect(wrapper.children[0].children[15].sequenceNumber).toBe(53);
});
var testListJoin = function(oldList, newList) {
return function() {
var wiki = new $tw.Wiki();
// Add some tiddlers
wiki.addTiddler({title: "Numbers", text: "", list: oldList});
var text = "<$list filter='[list[Numbers]]' variable='item' join=', '><<item>></$list>";
var widgetNode = createWidgetNode(parseText(text,wiki),wiki);
// Render the widget node to the DOM
var wrapper = renderWidgetNode(widgetNode);
// Test the rendering
expect(wrapper.innerHTML).toBe("<p>" + oldList.split(' ').join(', ') + "</p>");
// Change the list and ensure new rendering is still right
wiki.addTiddler({title: "Numbers", text: "", list: newList});
refreshWidgetNode(widgetNode,wrapper,["Numbers"]);
expect(wrapper.innerHTML).toBe("<p>" + newList.split(' ').join(', ') + "</p>");
}
}
it("the list widget with join should update correctly when empty list gets one item", testListJoin("", "1"));
it("the list widget with join should update correctly when empty list gets two items", testListJoin("", "1 2"));
it("the list widget with join should update correctly when single-item list is appended to", testListJoin("1", "1 2"));
it("the list widget with join should update correctly when single-item list is prepended to", testListJoin("1", "2 1"));
it("the list widget with join should update correctly when list is appended", testListJoin("1 2 3 4", "1 2 3 4 5"));
it("the list widget with join should update correctly when last item is removed", testListJoin("1 2 3 4", "1 2 3"));
it("the list widget with join should update correctly when first item is inserted", testListJoin("1 2 3 4", "0 1 2 3 4"));
it("the list widget with join should update correctly when first item is removed", testListJoin("1 2 3 4", "2 3 4"));
it("the list widget with join should update correctly when first two items are swapped", testListJoin("1 2 3 4", "2 1 3 4"));
it("the list widget with join should update correctly when last two items are swapped", testListJoin("1 2 3 4", "1 2 4 3"));
it("the list widget with join should update correctly when last item is moved to the front", testListJoin("1 2 3 4", "4 1 2 3"));
it("the list widget with join should update correctly when last item is moved to the middle", testListJoin("1 2 3 4", "1 4 2 3"));
it("the list widget with join should update correctly when first item is moved to the back", testListJoin("1 2 3 4", "2 3 4 1"));
it("the list widget with join should update correctly when middle item is moved to the back", testListJoin("1 2 3 4", "1 3 4 2"));
it("the list widget with join should update correctly when the last item disappears at the same time as other edits 1", testListJoin("1 3 4", "1 2 3"));
it("the list widget with join should update correctly when the last item disappears at the same time as other edits 2", testListJoin("1 3 4", "1 3 2"));
it("the list widget with join should update correctly when the last item disappears at the same time as other edits 3", testListJoin("1 3 4", "2 1 3"));
it("the list widget with join should update correctly when the last item disappears at the same time as other edits 4", testListJoin("1 3 4", "2 3 1"));
it("the list widget with join should update correctly when the last item disappears at the same time as other edits 5", testListJoin("1 3 4", "3 1 2"));
it("the list widget with join should update correctly when the last item disappears at the same time as other edits 6", testListJoin("1 3 4", "3 2 1"));
var testCounterLast = function(oldList, newList) {
return function() {
var wiki = new $tw.Wiki();

View File

@@ -1,9 +1,15 @@
created: 20140211171341271
modified: 20230419103154328
modified: 20230922094937115
tags: Concepts Reference
title: Macros
type: text/vnd.tiddlywiki
!! Important
<<.from-version "5.3.0">> Macros have been [[superseded|Macro Pitfalls]] by [[Procedures]], [[Functions]] and [[Custom Widgets]] which together provide more robust and flexible ways to encapsulate and re-use code.
For text substitutions it is now recommended to use: [[Substituted Attribute Values]], [[substitute Operator]] and [[Transclusion and Substitution]]
!! Introduction
A <<.def macro>> is a named snippet of text. They are typically defined with the [[Pragma: \define]]:
@@ -26,8 +32,6 @@ The parameters that are specified in the macro call are substituted for special
* `$parameter-name$` is replaced with the value of the named parameter
* `$(variable-name)$` is replaced with the value of the named [[variable|Variables]]).
<<.from-version "5.3.0">> Macros have been [[superseded|Macro Pitfalls]] by [[Procedures]], [[Custom Widgets]] and [[Functions]] which together provide more robust and flexible ways to encapsulate and re-use code. It is now recommended to only use macros when textual substitution is specifically required.
!! How Macros Work
Macros are implemented as a special kind of [[variable|Variables]]. The only thing that distinguishes them from ordinary variables is the way that the parameters are handled.

View File

@@ -1,5 +1,5 @@
created: 20150117152418000
modified: 20220523075540462
modified: 20231019155036098
tags: Concepts
title: Title List
type: text/vnd.tiddlywiki
@@ -15,3 +15,7 @@ Title lists are used in various places, including PermaLinks and the ListField.
They are in fact the simplest case of a [[filter|Filters]], and are thus a way of expressing a [[selection of titles|Title Selection]].
<<.warning """The [[Title List]] format cannot reliably represent items that contain certain specific character sequences such as `]] `. Thus it should not be used where there is a possibility of such sequences occurring.""">>
See also:
* The [[format Operator]] with the 'titlelist' suffix conditionally wraps double square brackets around a string if it contains whitespace

View File

@@ -0,0 +1,59 @@
created: 20231204112944341
modified: 20231204115056732
tags: [[Operator Examples]] [[jsonset Operator]]
title: jsonset Operator (Examples)
<$let object-a="""{
"a": "one",
"b": "",
"c": "three",
"d": {
"e": "four",
"f": [
"five",
"six",
true,
false,
null
],
"g": {
"x": "max",
"y": "may",
"z": "maize"
}
}
}
"""
object-b="""{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}""">
The examples below assume the following JSON object is contained in the variable `object-a`:
<pre><<object-a>></pre>
<<.operator-example 1 "[<object-a>jsonset[d],[Jaguar]]">>
<<.operator-example 2 "[<object-a>jsonset[d],[f],[Panther]]">>
<<.operator-example 3 "[<object-a>jsonset[d],[f],[-1],[Elephant]]">>
<<.operator-example 4 "[<object-a>jsonset[d],[f],[-2],[Elephant]]">>
<<.operator-example 5 "[<object-a>jsonset[d],[f],[-4],[Elephant]]">>
<<.operator-example 6 "[<object-a>jsonset[Panther]]" "If only a single parameter is specified, it replaces the entire JSON object">>
<<.operator-example 7 "[<object-a>jsonset[]]" "If only a single blank parameter is specified, no changes are made to the JSON object">>
The examples below assume the following JSON object is contained in the variable `object-b`:
<pre><<object-b>></pre>
<<.operator-example 8 "[<object-b>jsonset[]]" "If only a single blank parameter is specified, no changes are made to the JSON object">>
<<.operator-example 9 "[<object-b>jsonset[],[Antelope]]" "If the property to be set is blank, the entire JSON object is replaced">>
<<.operator-example 10 "[<object-b>jsonset:number[],[not a number]]" "invalid numbers are interpreted as zero">>
<<.operator-example 11 "[<object-b>jsonset[id],[Antelope]]" "nonexistent top level properties are added to the object">>
<<.operator-example 19 "[<object-b>jsonset[missing],[id],[Antelope]]" "nonexistent nested properties are are ignored">>
<<.operator-example 12 "[<object-b>jsonset:notatype[id],[Antelope]]" "invalid type suffix is interpreted as the default string type">>
<<.operator-example 13 "[<object-b>jsonset:boolean[id],[false]]">>
<<.operator-example 14 "[<object-b>jsonset:boolean[id],[Antelope]]" "invalid boolean value causes no assignment to be made">>
<<.operator-example 15 "[<object-b>jsonset:number[id],[42]]">>
<<.operator-example 16 "[<object-b>jsonset:null[id]]">>
<<.operator-example 17 "[<object-b>jsonset:array[d],[f],[5]]">>
<<.operator-example 18 "[<object-b>jsonset:object[d],[f],[5]]">>
<<.operator-example 20 "[<object-a>] [<object-b>] :and[jsonset[b],[two]]" "If the input consists of multiple JSON objects with matching properties, the value is set for all of them">>

View File

@@ -0,0 +1,11 @@
created: 20230922121858167
modified: 20230922122333325
tags: [[Operator Examples]] [[jsonstringify Operator]]
title: jsonstringify Operator (Examples)
type: text/vnd.tiddlywiki
Compare the encoding of quotes and control characters in the first example with the analogue [[example for the stringify operator|stringify Operator (Examples)]].
<<.operator-example 1 """[[Backslash \, double quote ", single quote ', tab , line feed
]] +[jsonstringify[]]""">>
<<.operator-example 2 """[[Accents and emojis -> äñøßπ ⌛🎄🍪🍓 without suffix]] +[jsonstringify[]]""">>
<<.operator-example 3 """[[Accents and emojis -> äñøßπ ⌛🎄🍪🍓 with rawunicode suffix]] +[jsonstringify:rawunicode[]]""">>

View File

@@ -1,9 +1,11 @@
created: 20161017154944352
modified: 20230919124059118
modified: 20230922122319674
tags: [[Operator Examples]] [[stringify Operator]]
title: stringify Operator (Examples)
type: text/vnd.tiddlywiki
<<.operator-example 1 """[[Title with "double quotes" and single ' and \backslash]] +[stringify[]]""">>
Compare the encoding of quotes and control characters in the first example with the analogue [[example for the jsonstringify operator|jsonstringify Operator (Examples)]].
<<.operator-example 1 """[[Backslash \, double quote ", single quote ', tab , line feed
]] +[stringify[]]""">>
<<.operator-example 2 """[[Accents and emojis -> äñøßπ ⌛🎄🍪🍓 without suffix]] +[stringify[]]""">>
<<.operator-example 3 """[[Accents and emojis -> äñøßπ ⌛🎄🍪🍓 with rawunicode suffix]] +[stringify:rawunicode[]]""">>

View File

@@ -1,22 +1,31 @@
caption: jsonset
created: 20230915121010948
modified: 20230915121010948
modified: 20231204115203428
op-input: a selection of JSON objects
op-output: the JSON objects with the specified value assigned to the specified property
op-parameter: one or more indexes of the property to modify, if applicable followed by the value to be assigned
op-purpose: set the value of a property in JSON objects
op-suffix: data type of the value to be assigned to the property
tags: [[Filter Operators]] [[JSON Operators]]
title: jsonset Operator
caption: jsonset
op-purpose: set the value of a property in JSON strings
op-input: a selection of JSON strings
op-parameter: one or more indexes of the property to retrieve and sometimes a value to assign
op-output: the JSON strings with the specified property assigned
<<.from-version "5.3.2">> See [[JSON in TiddlyWiki]] for background.
The <<.op jsonset>> operator is used to set a property value in JSON strings. See also the following related operators:
<<.from-version "5.3.2">> The <<.op jsonset>> operator is used to set a property value in JSON strings. See [[JSON in TiddlyWiki]] for background. See also the following related operators:
* <<.olink jsonget>> to retrieve the values of a property in JSON data
* <<.olink jsontype>> to retrieve the type of a JSON value
* <<.olink jsonindexes>> to retrieve the names of the fields of a JSON object, or the indexes of a JSON array
* <<.olink jsonextract>> to retrieve a JSON value as a string of JSON
The type of the value to be assigned to the property can be optionally specified with a suffix:
* ''string'': default, the string is specified as the final operand
* ''boolean'': the boolean value is true if the final operand is the string "true" and false if the final operand is the string "false", any other value for the final string results prevents the property from being assigned
* ''number'': the numeric value is taken from the final operand, invalid numbers are interpreted as zero
* ''json'': the JSON string value is taken from the final operand, invalid JSON prevents the property from being assigned
* ''object'': an empty object is assigned to the property, the final operand is ignored
* ''array'': an empty array is assigned to the property, the final operand is ignored
* ''null'': the special value null is assigned to the property, the final operand is ignored
Properties within a JSON object are identified by a sequence of indexes. In the following example, the value at `[a]` is `one`, and the value at `[d][f][0]` is `five`.
```
@@ -42,63 +51,14 @@ Properties within a JSON object are identified by a sequence of indexes. In the
}
```
The following examples assume that this JSON data is contained in a variable called `jsondata`.
The <<.op jsonset>> operator uses multiple parameters to specify the indexes of the property to set. When used to assign strings (default behaviour if no suffix is specified) the final operand is interpreted as the value to assign.
The <<.op jsonset>> operator uses multiple operands to specify the indexes of the property to set. When used to assign strings the final operand is interpreted as the value to assign. For example:
Negative indexes are counted from the end, so -1 means the last item, -2 the next-to-last item, and so on.
```
[<jsondata>jsonset[d],[Jaguar]] --> {"a": "one","b": "","c": "three","d": "Jaguar"}
[<jsondata>jsonset[d],[f],[Panther]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": "Panther","g": {"x": "max","y": "may","z": "maize"}}"}
```
Indexes can be dynamically composed from variables and transclusions, e.g. `[<jsondata>jsonset<variable>,{!!field},[0],{CurrentResult}]`.
Negative indexes into an array are counted from the end, so -1 means the last item, -2 the next-to-last item, and so on:
In the special case where only a single parameter is defined, the operator replaces the entire input object with the the value of that parameter. If the single parameter is blank, the operation is ignored and no assignment takes place.
```
[<jsondata>jsonset[d],[f],[-1],[Elephant]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five","six",true,false,"Elephant"],"g": {"x": "max","y": "may","z": "maize"}}"}
[<jsondata>jsonset[d],[f],[-2],[Elephant]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five","six",true,"Elephant",null],"g": {"x": "max","y": "may","z": "maize"}}"}
[<jsondata>jsonset[d],[f],[-4],[Elephant]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five","Elephant",true,false,null],"g": {"x": "max","y": "may","z": "maize"}}"}
```
If the input consists of multiple JSON objects with matching properties, the value is set for all of them.
Indexes can be dynamically composed from variables and transclusions:
```
[<jsondata>jsonset<variable>,{!!field},[0],{CurrentResult}]
```
The data type of the value to be assigned to the property can be specified with an optional suffix:
|!Suffix |!Description |
|''string'' |The string is specified as the final operand |
|''boolean'' |The boolean value is true if the final operand is the string "true" and false if the final operand is the string "false". Any other value for the final string results prevents the property from being assigned |
|''number'' |The numeric value is taken from the final operand. Invalid numbers are interpreted as zero |
|''json'' |The JSON string value is taken from the final operand. Invalid JSON prevents the property from being assigned |
|''object'' |An empty object is assigned to the property. The final operand is not used as a value |
|''array'' |An empty array is assigned to the property. The final operand is not used as a value |
|''null'' |The special value null is assigned to the property. The final operand is not used as a value |
For example:
```
Input string:
{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}
[jsonset[]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}
[jsonset[],[Antelope]] --> "Antelope"
[jsonset:number[],[not a number]] --> 0
[jsonset[id],[Antelope]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":"Antelope"}
[jsonset:notatype[id],[Antelope]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":"Antelope"}
[jsonset:boolean[id],[false]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":false}
[jsonset:boolean[id],[Antelope]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}
[jsonset:number[id],[42]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":42}
[jsonset:null[id]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]},"id":null}
[jsonset:array[d],[f],[5]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null,[]]}}
[jsonset:object[d],[f],[5]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null,{}]}}
[jsonset[missing],[id],[Antelope]] --> {"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}
```
A subtlety is that the special case of a single operand sets the value of that operand as the new JSON string, entirely replacing the input object. If that operand is blank, the operation is ignored and no assignment takes place. Thus:
```
[<jsondata>jsonset[Panther]] --> "Panther"
[<jsondata>jsonset[]] --> {"a": "one","b": "","c": "three","d": "{"e": "four","f": ["five", "six", true, false, null],"g": {"x": "max","y": "may","z": "maize"}}"}
```
<<.operator-examples "jsonset">>

View File

@@ -1,12 +1,35 @@
caption: jsonstringify
created: 20171029155051467
from-version: 5.1.14
modified: 20230919124826880
modified: 20230922121404577
op-input: a [[selection of titles|Title Selection]]
op-output: the input with JSON string encodings applied
op-parameter:
op-parameter-name:
op-purpose: deprecated, use <<.olink stringify>> instead
op-purpose: apply JSON string encoding to a string, see also the similar <<.olink stringify>>
op-suffix: <<.from-version "5.1.23">> optionally, the keyword `rawunicode`
op-suffix-name: R
tags: [[Filter Operators]] [[String Operators]]
title: jsonstringify Operator
type: text/vnd.tiddlywiki
The following substitutions are made:
|!Character |!Replacement |!Condition |
|`\` |`\\` |Always |
|`"` |`\"` |Always |
|Carriage return (0x0d) |`\r` |Always |
|Line feed (0x0a) |`\n` |Always |
|Backspace (0x08) |`\b` |Always |
|Form field (0x0c) |`\f` |Always |
|Tab (0x09) |`\t` |Always|
|Characters from 0x00 to 0x1f, except listed above |`\u####` where #### is four hex digits |Always |
|Characters from from 0x80 to 0xffff|`\u####` where #### is four hex digits |If `rawunicode` suffix is not present (default) |
|Characters from 0x80 to 0xffff|<<.from-version "5.1.23">> Unchanged |If `rawunicode` suffix is present |
<<.from-version "5.1.23">> If the suffix `rawunicode` is present, Unicode characters above 0x80 (such as ß, ä, ñ or 🎄) will be passed through unchanged. Without the suffix, they will be substituted with `\u` codes, which was the default behavior before 5.1.23. Characters outside the Basic Multilingual Plane, such as 🎄 and other emojis, will be encoded as a UTF-16 surrogate pair, i.e. with two `\u` sequences.
<<.note """Mind the differences compared to <<.olink stringify>> in encoding of single quotes and control characters (0x00 to 0x1f).
""">>
<<.operator-examples "jsonstringify">>

View File

@@ -1,12 +1,12 @@
caption: stringify
created: 20161017153038029
from-version: 5.1.14
modified: 20230919130847809
modified: 20230922121406947
op-input: a [[selection of titles|Title Selection]]
op-output: the input with ~JavaScript string encodings applied
op-parameter:
op-parameter-name:
op-purpose: apply ~JavaScript string encoding to a string
op-purpose: apply ~JavaScript string encoding to a string, see also the similar <<.olink jsonstringify>>
op-suffix: <<.from-version "5.1.23">> optionally, the keyword `rawunicode`
op-suffix-name: R
tags: [[Filter Operators]] [[String Operators]]
@@ -18,19 +18,16 @@ The following substitutions are made:
|!Character |!Replacement |!Condition |
|`\` |`\\` |Always |
|`"` |`\"` |Always |
|Carriage return (0x0d) |`\r` |Always |
|`'` |`\'` |Always |
|Line feed (0x0a) |`\n` |Always |
|Backspace (0x08) |`\b` |Always |
|Form field (0x0c) |`\f` |Always |
|Tab (0x09) |`\t` |Always |
|Characters from 0x00 to 0x1f |`\x##` where ## is two hex digits |Always |
|Carriage return (0x0d) |`\r` |Always |
|Characters from 0x00 to 0x1f, except listed above |`\x##` where ## is two hex digits |Always |
|Characters from 0x80 to 0xffff|`\u####` where #### is four hex digits |If `rawunicode` suffix is not present (default) |
|Characters from 0x80 to 0xffff|<<.from-version "5.1.23">> Unchanged |If `rawunicode` suffix is present |
<<.from-version "5.1.23">> If the suffix `rawunicode` is present, Unicode characters above 0x80 (such as ß, ä, ñ or 🎄) will be passed through unchanged. Without the suffix, they will be substituted with `\u` codes, which was the default behavior before 5.1.23.
<<.from-version "5.1.23">> If the suffix `rawunicode` is present, Unicode characters above 0x80 (such as ß, ä, ñ or 🎄) will be passed through unchanged. Without the suffix, they will be substituted with `\u` codes, which was the default behavior before 5.1.23. Characters outside the Basic Multilingual Plane, such as 🎄 and other emojis, will be encoded as a UTF-16 surrogate pair, i.e. with two `\u` sequences.
<<.note """Characters outside the Basic Multilingual Plane, such as 🎄 and other emojis, will be encoded as a UTF-16 surrogate pair, i.e. with two `\u` sequences.""">>
<<.olink jsonstringify>> is considered deprecated, as it duplicates the functionality of <<.op stringify>>.
<<.note """Mind the differences compared to <<.olink jsonstringify>> in encoding of single quotes and control characters (0x00 to 0x1f).
""">>
<<.operator-examples "stringify">>

View File

@@ -1,6 +1,6 @@
created: 20130822170200000
list: [[A Gentle Guide to TiddlyWiki]] [[Discover TiddlyWiki]] [[Some of the things you can do with TiddlyWiki]] [[Ten reasons to switch to TiddlyWiki]] Examples [[What happened to the original TiddlyWiki?]]
modified: 20230820112855583
modified: 20231213080637781
tags: TableOfContents
title: HelloThere
type: text/vnd.tiddlywiki
@@ -20,7 +20,7 @@ TiddlyWiki lets you choose where to keep your data, guaranteeing that in the dec
</div>
<div class="tc-cards tc-small">
<$link to="中文社区 - Chinese Community" class="tc-btn-big-green tc-card">
中文社区 - Chinese Community
中文社区<br/>Chinese Community
</$link>
</div>

View File

@@ -1,5 +1,5 @@
created: 20220427174702859
modified: 20230809113620964
modified: 20230922122551197
tags: [[JSON in TiddlyWiki]] Learning
title: Constructing JSON tiddlers
@@ -13,4 +13,4 @@ At a high level, we have several ways to generate JSON data in TiddlyWiki's own
* [[jsontiddler Macro]]
* [[jsontiddlers Macro]]
When constructing JSON data manually, the [[stringify Operator]] is needed to ensure that any special characters are properly escaped.
When constructing JSON data manually, the [[jsonstringify Operator]] is needed to ensure that any special characters are properly escaped.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -5,4 +5,4 @@ type: text/vnd.tiddlywiki
The following [[macros|Macros]] are built into ~TiddlyWiki's core:
<<list-links "[tag[Core Macros]]">>
<<list-links "[tag[Core Macros]]" class:"multi-columns">>

View File

@@ -0,0 +1,184 @@
caption: 5.3.2
created: 20231213080637781
modified: 20231213080637781
released: 20231213080637781
tags: ReleaseNotes
title: Release 5.3.2
type: text/vnd.tiddlywiki
description: Under development
//[[See GitHub for detailed change history of this release|https://github.com/Jermolene/TiddlyWiki5/compare/v5.3.1...v5.3.2]]//
<<.banner-credits
credit:"""Congratulations to [[catter-fly|https://talk.tiddlywiki.org/u/catter-fly]] for their winning design for the banner for this release (here is the [[competition thread|https://talk.tiddlywiki.org/t/banner-image-competition-for-v5-3-2/8569]]).
"""
url:"https://raw.githubusercontent.com/Jermolene/TiddlyWiki5/51862f812851afda0ed3540f8463f51def0d4f9a/editions/tw5.com/tiddlers/images/New%20Release%20Banner.png"
>>
! Major Improvements
!! Conditional Shortcut Syntax
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7710">> a new [[shortcut syntax|Conditional Shortcut Syntax]] for concisely expressing if-then-else logic. This is the first of a new type of wikitext syntax based on tokens delimited with `<%` and `%>`. We plan to introduce other structures using the same format such as a "case" statement.
These new token-based shortcuts allow a richer structure and expressivity than existing features such as widgets or pragmas. For example:
```
<% if [<animal>match[Elephant]] %>
It is an elephant
<% elseif [<animal>match[Giraffe]] %>
It is a giraffe
<% else %>
It is completely unknown
<% endif %>
```
Behind the scenes, the conditional shortcut syntax is rendered as the equivalent [[ListWidgets|ListWidget]].
!! Explicit Templates for the ListWidget
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7784">> support for `<$list-template>` and `<$list-empty>` as immediate children of the <<.wid "ListWidget">> widget to specify the list item template and/or the empty template.
This new feature is designed to replace a common pattern of using the `emptyMessage` attribute of the ListWidget to render complex wikitext that thus has to be quoted. Working with wikitext within quotes is awkward and error prone. The new structure can be somewhat faster because it allows the empty message to be parsed in advanced of rendering.
For example:
```
<$list filter=<<filter>>>
<$list-template>
<$text text=<<currentTiddler>>/>
</$list-template>
<$list-empty>
None!
</$list-empty>
</$list>
```
Note that the <<.attr "emptyMessage">> and <<.attr "template">> attributes take precedence if they are present.
!! Joiners for the ListWidget
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7694">> a <<.attr "join">> attribute to the <<.wid "ListWidget">> widget to insert a short piece of text between list items. This is both easier to use and faster than using the <<.attr "counter">> attribute for the same purpose. So if your list looked like this:
```
<$list filter=<<filter>> counter="counter" variable="item">
<$text text=<<item>>/><$list filter="[<counter-last>match[no]]" variable="ignore"><$text text=", "/></$list>
</$list>
```
You can replace it with:
```
<$list filter=<<filter>> variable="item" join=", "><$text text=<<item>>/></$list>
```
If the joiner text that you need is long and awkward to write in an attribute, you can use the new `<$list-join>` widget. Like `<$list-template>` and `<$list-empty>`, it must be an immediate child of the <<.wid "ListWidget">>:
```
<$list filter=<<filter>> variable="item"><$text text=<<item>>/><$list-join>, and <em>also</em> let's not forget </$list-join></$list>
```
!! jsonset operator
<<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7742">> [[jsonset Operator]] for setting values within JSON objects
!! QR Code Reader
<<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7746">> QR Code plugin to be able to read QR codes and a number of other bar code formats
! Translation improvements
Improvements to the following translations:
* Chinese
* Polish
* Spanish
! Plugin Improvements
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/1be8f0a9336952d4745d2bd4f2327e353580a272">> Comments Plugin to use predefined palette colours
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7785">> Evernote Importer Plugin to support images and other attachments
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7790">> `$floating` attribute to Dynannotate Plugin to support popups that do not disappear when another part of the screen is clicked. Instead they have to dismissed manually
! Widget Improvements
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7734">> ImageWidget encoding for more image types
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7634">> ImageWidget to add a "usemap" attribute
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7649">> the ScrollableWidget to allow the scroll position to be bound to a tiddler, so that changes to the tiddler affect the scroll position, and vice versa
! Usability Improvements
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/7747">> editor preview button to automatically focus the editor
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7764">> file type names in the export menu
! Hackability Improvements
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7769">> all the relevant core widgets to allow arbitrary `data-*` attributes and `style.*` attributes to be applied to the generated DOM nodes. This is useful for passing data to the EventCatcherWidget
* <<.link-badge-extended "https://github.com/Jermolene/TiddlyWiki5/pull/7849">> [[jsonextract Operator]], [[jsonget Operator]], [[jsonset Operator]] and [[jsontype Operator]] to allow negative indexes into arrays to be counted from the end of the array
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7690">> the default page layout to better support CSS grid and flexbox layouts
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7787">> the editor to use grid layout, simplifying customisation
! Bug Fixes
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7758">> ordering of Vanilla stylesheets
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/fa9bfa07a095548eb2f8339b0b1b816d2e6794ef">> missing closing tag in tag-pill-inner macro
* <<.link-badge-removed "https://github.com/Jermolene/TiddlyWiki5/issues/7732">> invalid "type" attribute from textarea elements generated by the EditTextWidget
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7749">> editor "type" dropdown state tiddlers
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7712">> handling of "counter-last" variable when appending items with the ListWidget
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/6088">> upgrade download link in Firefox
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7698">> refreshing of transcluded functions
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7789">> resizing of height of textareas in control panel
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7683">> [[encodebase64 Operator]] and [[decodebase64 Operator]] to work properly with binary data
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7708">> [[WidgetMessage: tm-open-window]] when opening an existing window to bring it to the front and focus it
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7809">> behaviour of [[last Operator]] when zero items selected
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7806">> incorrectly setting focus on field name input field when deleting field using the delete field button
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7802">> [[Table-of-Contents Macros]] to not show expander icon for a sublist that has all children excluded
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7794">> overflow of [[CodeMirror Plugin]] editor within grid container
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7835">> wikitest parser removing whitespace when parsing pragmas
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7842">> tooltip for editor add field button
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7844">> plain text parser being susceptible to the CodeBlockWidget being redefined
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7855">> pragmas not working within the action string of several core macros
! Node.js Improvements
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/pull/7843">> a significant flaw in the synchronisation algorithm used by the client-server configuration. The flaw could lead to tiddlers temporarily disappearing from the browser
! Performance Improvements
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7702">> performance of predefined patterns with [[all Operator]]
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/issues/7671">> favicon format to PNG
! Developer Improvements
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7751">> global hook handling to support removing hooks
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7539">> some useful npm scripts to `package.json`
! Infrastructure Improvements
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/7820">> Continuous Integration tests to use Playwright to run our browser-based tests
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/7737">> an automatic build of the external core TiddlyWiki at https://tiddlywiki.com/empty-external-core.html
! Acknowledgements
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
<<.contributors """
AnthonyMuscio
BramChen
BuckarooBanzay
BurningTreeC
CrossEye
EvidentlyCube
Gk0Wk
joebordes
kookma
linonetwo
mateuszwilczek
oflg
pille1842
pmario
rmunn
saqimtiaz
simonbaird
T1mL3arn
yaisog
""">>

View File

@@ -148,6 +148,7 @@ type: text/vnd.tiddlywiki
}
.tc-cards.tc-small {
text-align: center;
font-size: 0.7em;
}

View File

@@ -84,6 +84,7 @@ The action of the list widget depends on the results of the filter combined with
|limit |<<.from-version "5.3.2">> Optional numeric limit for the number of results that are returned. Negative values will return the results from the end of the list |
|template |The title of a template tiddler for transcluding each tiddler in the list. When no template is specified, the body of the ListWidget serves as the item template. With no body, a simple link to the tiddler is returned. |
|editTemplate |An alternative template to use for [[DraftTiddlers|DraftMechanism]] in edit mode |
|join |<<.from-version "5.3.2">> Text to include between each list item |
|variable |The name for a [[variable|Variables]] in which the title of each listed tiddler is stored. Defaults to ''currentTiddler'' |
|counter |<<.from-version "5.2.0">> Optional name for a [[variable|Variables]] in which the 1-based numeric index of each listed tiddler is stored (see below) |
|emptyMessage |Message to be displayed when the list is empty |
@@ -120,10 +121,29 @@ Displays as:
</$list>
<<<
Note that using the `counter` attribute can reduce performance when working with list items that dynamically reorder or update themselves. The best advice is only to use it when it is really necessary: to obtain a numeric index, or to detect the first or last entries in the list.
Note that using the `counter` attribute can reduce performance when working with list items that dynamically reorder or update themselves. The best advice is only to use it when it is really necessary: to obtain a numeric index, or to detect the first or last entries in the list. Note that if you are only using it to insert something (like a comma) between list items, the `join` attribute performs much better and you should use it instead of `counter`.
Setting `counter="transclusion"` is a handy way to make child elements for each list element be identified as unique. A common use case are multiple [[tag macros|tag Macro]] for the same tag generated by a list widget. Refer to [[tag macro examples|tag Macro (Examples)]] for more details.
!! `join` attribute
<<.from-version "5.3.2">> The optional `join` attribute allow you to insert some [[WikiText]] between each list item without needing to use the `counter` attribute, which can become quite slow if the list is updated frequently.
<<.from-version "5.3.2">> If the widget `<$list-join>` is found as an immediate child of the <<.wid "ListWidget">> widget then the content of that widget is used as the "join" template, included between two list items. Note that the <<.attr "join">> attribute takes precedence if it is present.
For example:
```
<$list filter="[tag[About]sort[title]]" join=", " variable="item"><<item>></$list>
```
Displays as:
<<<
<$list filter="[tag[About]sort[title]]" join=", " variable="item"><<item>></$list>
<<<
!! Edit mode
The `<$list>` widget can optionally render draft tiddlers through a different template to handle editing, see DraftMechanism.

View File

@@ -18,7 +18,7 @@ The content of the `<$scrollable>` widget is displayed within a pair of wrapper
|fallthrough |See below |
|bind |<<.from-version "5.3.2">> Optional title of tiddler to which the scroll position should be bound |
Binding the scroll position to a tiddler automatically copies the scroll coordinates into the `scroll-left` and `scroll-top` fields as scrolling occurs. Conversely, setting those field values will automatically cause the scrollable to scroll if it can.
Binding the scroll position to a tiddler automatically copies the scroll coordinates into the `scroll-left` and `scroll-top` fields after scrolling occurs. Conversely, setting those field values will automatically cause the scrollable to scroll if it can.
<$macrocall $name=".note" _="""If a scrollable widget can't handle the `tm-scroll` message because the inner DIV fits within the outer DIV, then by default the message falls through to the parent widget. Setting the ''fallthrough'' attribute to `no` prevents this behaviour."""/>

View File

@@ -1,6 +1,6 @@
caption: set
created: 20131115182700000
modified: 20220523075522407
modified: 20230720174707977
tags: Widgets
title: SetWidget
type: text/vnd.tiddlywiki
@@ -120,3 +120,19 @@ src='<$set name="myTiddler" value="HelloThere">
</$set>'/>
<<<
!! Using the Set Widget to Create Global Variables
There are times when it makes sense to use the features of the [[SetWidget]] rather than procedures or functions to create global variables. This can be accomplished by placing the set variable widget in a tiddler that is tagged [[$:/tags/Global|SystemTag: $:/tags/Global]]. If multiple variables are required, the set variable widget can be nested as shown here:
<<<
<div class="doc-example">
```
<$set name="myGlobalVariable" value="I am global">
<$set name="myOtherGlobalVariable" value="I am also a global variable.">
</$set>
</$set>
```
</div>
<<<

View File

@@ -4,12 +4,14 @@ tags: WikiText
title: Conditional Shortcut Syntax
type: text/vnd.tiddlywiki
<<.from-version "5.3.2">> The conditional shortcut syntax provides a convenient way to express if-then-else logic within WikiText. It evaluates a filter and considers the condition to be true if there is at least one result (regardless of the value of that result).
<<.from-version "5.3.2">> The conditional shortcut syntax provides a convenient way to express if-then-else logic within WikiText. It evaluates a [[filter expression|Filter Expression]] and considers the condition to be true if there is at least one result (regardless of the value of that result).
Within an "if" or "elseif" clause, the variable `condition` contains the value of the first result of evaluating the filter condition.
A simple example:
<$macrocall $name='wikitext-example-without-html'
src='<% if [{$:/$:/info/url/protocol}match[file:]] %>
src='<% if [{$:/info/url/protocol}match[file:]] %>
Loaded from a file URI
<% else %>
Not loaded from a file URI
@@ -19,11 +21,11 @@ src='<% if [{$:/$:/info/url/protocol}match[file:]] %>
One or more `<% elseif %>` clauses may be included before the `<% else %>` clause:
<$macrocall $name='wikitext-example-without-html'
src='<% if [{$:/$:/info/url/protocol}match[file:]] %>
src='<% if [{$:/info/url/protocol}match[file:]] %>
Loaded from a file URI
<% elseif [{$:/$:/info/url/protocol}match[https:]] %>
<% elseif [{$:/info/url/protocol}match[https:]] %>
Loaded from an HTTPS URI
<% elseif [{$:/$:/info/url/protocol}match[http:]] %>
<% elseif [{$:/info/url/protocol}match[http:]] %>
Loaded from an HTTP URI
<% else %>
Loaded from an unknown protocol
@@ -55,7 +57,6 @@ src='\procedure test(animal)
Notes:
* Clauses are parsed in inline mode by default. Force block mode parsing by following the opening `<% if %>`, `<% elseif %>` or `<% else %>` with two line breaks
* Within an "if" or "elseif" clause, the variable `condition` contains the value of the first result of evaluating the filter condition
* Widgets and HTML elements must be within a single conditional clause; it is not possible to start an element in one conditional clause and end it in another
* The conditional shortcut syntax cannot contain pragmas such as procedure definitions

View File

@@ -1,5 +1,5 @@
created: 20141018090608643
modified: 20230419103154329
modified: 20231030124224424
tags: WikiText
title: Transclusion and Substitution
type: text/vnd.tiddlywiki
@@ -55,6 +55,6 @@ As described in [[Introduction to filter notation]], you can also transclude a v
! Textual Substitution
Textual substitution occurs when the value of a macro/variable is used. It is described in [[Macros]].
Textual substitution occurs when the value of a macro/variable is used. It is described in [[Substituted Attribute Values]] and [[substitute Operator]]
The key difference between substitution and transclusion is that substitution occurs before WikiText parsing. This means that you can use substitution to build WikiText constructions. Transclusions are processed independently, and cannot be combined with adjacent text to define WikiText constructions.
The key difference between substitution and transclusion is that substitution occurs before WikiText parsing. This means that you can use substitution to build ~WikiText constructions. Transclusions are processed independently, and cannot be combined with adjacent text to define ~WikiText constructions.

View File

@@ -3,4 +3,4 @@ title: $:/language/Exporters/
StaticRiver: HTML - Statisch
JsonFile: JSON - Format
CsvFile: CSV - Format
TidFile: .tid - Format
TidFile: TID - Text Format

View File

@@ -1,7 +1,7 @@
title: $:/language/Help/commands
description: Ausführen von Befehlen aus einem Tiddler
Sequentielle Abarbeitung von Befehlen aus einem Tiddler.
Sequentielle Abarbeitung von Befehlen aus einem Tiddler.
```
--commands <filter>
@@ -9,6 +9,6 @@ Sequentielle Abarbeitung von Befehlen aus einem Tiddler.
Beispiele
`--commands "[enlist{$:/build-commands-as-text}]"`
`--commands "[enlist:raw{$:/build-commands-as-text}]"`
`--commands "[{$:/build-commands-as-json}jsonindexes[]] :map[{$:/build-commands-as-json}jsonget<currentTiddler>]"`

View File

@@ -1,5 +1,5 @@
title: $:/language/Help/server
description: Stellt einen HTTP server für TiddlyWiki zur Verfügung. (Dieser Befehl ist abgekündigt! - Neu ist: "listen")
description: (Dieser Befehl ist abgekündigt! - Neu ist: "listen") -- Stellt einen HTTP server für TiddlyWiki zur Verfügung.
TiddlyWiki bringt einen einfachen Web-Server mit.

View File

@@ -1,4 +1,4 @@
title: $:/language/Docs/Types/image/x-icon
description: ICO - Piktogramm Format
description: ICO - Piktogramm (Icon)
name: image/x-icon
group: Bilder

View File

@@ -10,7 +10,7 @@ Uruchamia komendy zwrócone przez filtr.
Dla przykładu:
```
--commands "[enlist{$:/build-commands-as-text}]"
--commands "[enlist:raw{$:/build-commands-as-text}]"
```
```

View File

@@ -10,7 +10,7 @@ description: 运行从筛选器传回的命令
示例
```
--commands "[enlist{$:/build-commands-as-text}]"
--commands "[enlist:raw{$:/build-commands-as-text}]"
```
```

View File

@@ -10,7 +10,7 @@ description: 執行從篩選器傳回的命令
範例
```
--commands "[enlist{$:/build-commands-as-text}]"
--commands "[enlist:raw{$:/build-commands-as-text}]"
```
```

View File

@@ -553,3 +553,7 @@ BuckarooBanzay, @BuckarooBanzay, 2023/09/01
Timur, @T1mL3arn, 2023/10/04
Wang Ke, @Gk0Wk, 2023/10/17
@frittro, 2023/10/27
@etardiff, 2023/12/10

View File

@@ -1,7 +1,7 @@
{
"name": "tiddlywiki",
"preferGlobal": "true",
"version": "5.3.2-prerelease",
"version": "5.3.2",
"author": "Jeremy Ruston <jeremy@jermolene.com>",
"description": "a non-linear personal web notebook",
"contributors": [

View File

@@ -51,7 +51,7 @@ describe("Wiki-based tests", function() {
});
function readMultipleTiddlersTiddler(title) {
var rawTiddlers = $tw.wiki.getTiddlerText(title).split(/\r?\n+\r?\n/mg);
var rawTiddlers = $tw.wiki.getTiddlerText(title).split(/\r?\n\+\r?\n/mg);
var tiddlers = [];
$tw.utils.each(rawTiddlers,function(rawTiddler) {
var fields = Object.create(null),

View File

@@ -1,4 +1,3 @@
title: $:/core/templates/html-json-skinny-tiddler
<$list filter="[<numTiddlers>compare:number:gteq[1]] ~[<counter>!match[1]]">`,`<$text text=<<newline>>/></$list>
<$jsontiddler tiddler=<<currentTiddler>> exclude="text" escapeUnsafeScriptChars="yes" $revision=<<changecount>> $bag="default" $_is_skinny=""/>

View File

@@ -1,4 +1,3 @@
title: $:/core/templates/html-json-tiddler
<$list filter="[<counter>!match[1]]">`,`<$text text=<<newline>>/></$list>
<$jsontiddler tiddler=<<currentTiddler>> escapeUnsafeScriptChars="yes" $revision=<<changecount>> $bag="default">/>
<$jsontiddler tiddler=<<currentTiddler>> escapeUnsafeScriptChars="yes" $revision=<<changecount>> $bag="default"/>

View File

@@ -44,7 +44,7 @@ Make sure that you keep a safe copy of your previous ~TiddlyWiki file.
Close this browser window to prevent others from being able to access your data.
For help and support, visit [[the TiddlyWiki discussion forum|http://groups.google.com/group/TiddlyWiki]].
For help and support, visit [[the TiddlyWiki discussion forum|https://talk.tiddlywiki.org]].
</$reveal>

View File

@@ -1,7 +1,7 @@
<p>Welcome to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a>, a non-linear personal web notebook that anyone can use and keep forever, independently of any corporation.</p><p><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> is a complete interactive wiki in <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/JavaScript.html">JavaScript</a>. It can be used as a single HTML file in the browser or as a powerful Node.js application. It is highly customisable: the entire user interface is itself implemented in hackable <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/WikiText.html">WikiText</a>.</p><p>Learn more and see it in action at <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/</a></p><p>Developer documentation is in progress at <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev/" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/dev/</a></p><h1 class="">Join the Community</h1><p>
<h2 class="">Official Forums</h2><p>The new official forum for talking about TiddlyWiki: requests for help, announcements of new releases and plugins, debating new features, or just sharing experiences. You can participate via the associated website, or subscribe via email.</p><p><a class="tc-tiddlylink-external" href="https://talk.tiddlywiki.org/" rel="noopener noreferrer" target="_blank">https://talk.tiddlywiki.org/</a></p><p>Note that talk.tiddlywiki.org is a community run service that we host and maintain ourselves. The modest running costs are covered by community contributions.</p><p>For the convenience of existing users, we also continue to operate the original TiddlyWiki group (hosted on Google Groups since 2005):</p><p><a class="tc-tiddlylink-external" href="https://groups.google.com/group/TiddlyWiki" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/TiddlyWiki</a></p><h2 class="">Developer Forums</h2><p>There are several resources for developers to learn more about <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> and to discuss and contribute to its development.</p><ul><li><a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">tiddlywiki.com/dev</a> is the official developer documentation</li><li>Get involved in the <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5" rel="noopener noreferrer" target="_blank">development on GitHub</a><ul><li><a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/discussions" rel="noopener noreferrer" target="_blank">Discussions</a> are for Q&amp;A and open-ended discussion</li><li><a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/issues" rel="noopener noreferrer" target="_blank">Issues</a> are for raising bug reports and proposing specific, actionable new ideas</li></ul></li><li>The older TiddlyWikiDev Google Group is now closed in favour of <a class="tc-tiddlylink-external" href="https://github.com/Jermolene/TiddlyWiki5/discussions" rel="noopener noreferrer" target="_blank">GitHub Discussions</a> but remains a useful archive: <a class="tc-tiddlylink-external" href="https://groups.google.com/group/TiddlyWikiDev" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/TiddlyWikiDev</a><ul><li>An enhanced group search facility is available on <a class="tc-tiddlylink-external" href="https://www.mail-archive.com/tiddlywikidev@googlegroups.com/" rel="noopener noreferrer" target="_blank">mail-archive.com</a></li></ul></li><li>Follow <a class="tc-tiddlylink-external" href="http://twitter.com/#!/TiddlyWiki" rel="noopener noreferrer" target="_blank">@TiddlyWiki on Twitter</a> for the latest news</li><li>Chat at <a class="tc-tiddlylink-external" href="https://gitter.im/TiddlyWiki/public" rel="noopener noreferrer" target="_blank">https://gitter.im/TiddlyWiki/public</a> (development room coming soon)</li></ul><h2 class="">Other Forums</h2><ul><li><a class="tc-tiddlylink-external" href="https://www.reddit.com/r/TiddlyWiki5/" rel="noopener noreferrer" target="_blank">TiddlyWiki Subreddit</a></li><li>Chat with Gitter at <a class="tc-tiddlylink-external" href="https://gitter.im/TiddlyWiki/public" rel="noopener noreferrer" target="_blank">https://gitter.im/TiddlyWiki/public</a> !</li><li>Chat on Discord at <a class="tc-tiddlylink-external" href="https://discord.gg/HFFZVQ8" rel="noopener noreferrer" target="_blank">https://discord.gg/HFFZVQ8</a></li></ul><h3 class="">Documentation</h3><p>There is also a discussion group specifically for discussing <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> documentation improvement initiatives: <a class="tc-tiddlylink-external" href="https://groups.google.com/group/tiddlywikidocs" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/tiddlywikidocs</a>
</p>
</p><h1 class="">Installing <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on Node.js</h1><ol><li>Install <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Node.js.html">Node.js</a><ul><li>Linux: <blockquote><div><em>Debian/Ubuntu</em>:<br><code>apt install nodejs</code><br>May need to be followed up by:<br><code>apt install npm</code></div><div><em>Arch Linux</em><br><code>yay -S tiddlywiki</code> <br>(installs node and tiddlywiki)</div></blockquote></li><li>Mac<blockquote><div><code>brew install node</code></div></blockquote></li><li>Android<blockquote><div><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Serving%2520TW5%2520from%2520Android.html">Termux for Android</a></div></blockquote></li><li>Other <blockquote><div>See <a class="tc-tiddlylink-external" href="http://nodejs.org" rel="noopener noreferrer" target="_blank">http://nodejs.org</a></div></blockquote></li></ul></li><li>Open a command line terminal and type:<blockquote><div><code>npm install -g tiddlywiki</code></div><div>If it fails with an error you may need to re-run the command as an administrator:</div><div><code>sudo npm install -g tiddlywiki</code> (Mac/Linux)</div></blockquote></li><li>Ensure TiddlyWiki is installed by typing:<blockquote><div><code>tiddlywiki --version</code></div></blockquote><ul><li>In response, you should see <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> report its current version (eg "5.3.1". You may also see other debugging information reported.)</li></ul></li><li>Try it out:<ol><li><code>tiddlywiki mynewwiki --init server</code> to create a folder for a new wiki that includes server-related components</li><li><code>tiddlywiki mynewwiki --listen</code> to start <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a></li><li>Visit <a class="tc-tiddlylink-external" href="http://127.0.0.1:8080/" rel="noopener noreferrer" target="_blank">http://127.0.0.1:8080/</a> in your browser</li><li>Try editing and creating tiddlers</li></ol></li><li>Optionally, make an offline copy:<ul><li>click the <span class="doc-icon"><svg class="tc-image-save-button-dynamic tc-image-button" height="22pt" viewBox="0 0 128 128" width="22pt">
</p><h1 class="">Installing <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> on Node.js</h1><ol><li>Install <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Node.js.html">Node.js</a><ul><li>Linux: <blockquote><div><em>Debian/Ubuntu</em>:<br><code>apt install nodejs</code><br>May need to be followed up by:<br><code>apt install npm</code></div><div><em>Arch Linux</em><br><code>yay -S tiddlywiki</code> <br>(installs node and tiddlywiki)</div></blockquote></li><li>Mac<blockquote><div><code>brew install node</code></div></blockquote></li><li>Android<blockquote><div><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Serving%2520TW5%2520from%2520Android.html">Termux for Android</a></div></blockquote></li><li>Other <blockquote><div>See <a class="tc-tiddlylink-external" href="http://nodejs.org" rel="noopener noreferrer" target="_blank">http://nodejs.org</a></div></blockquote></li></ul></li><li>Open a command line terminal and type:<blockquote><div><code>npm install -g tiddlywiki</code></div><div>If it fails with an error you may need to re-run the command as an administrator:</div><div><code>sudo npm install -g tiddlywiki</code> (Mac/Linux)</div></blockquote></li><li>Ensure TiddlyWiki is installed by typing:<blockquote><div><code>tiddlywiki --version</code></div></blockquote><ul><li>In response, you should see <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> report its current version (eg "5.3.2". You may also see other debugging information reported.)</li></ul></li><li>Try it out:<ol><li><code>tiddlywiki mynewwiki --init server</code> to create a folder for a new wiki that includes server-related components</li><li><code>tiddlywiki mynewwiki --listen</code> to start <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a></li><li>Visit <a class="tc-tiddlylink-external" href="http://127.0.0.1:8080/" rel="noopener noreferrer" target="_blank">http://127.0.0.1:8080/</a> in your browser</li><li>Try editing and creating tiddlers</li></ol></li><li>Optionally, make an offline copy:<ul><li>click the <span class="doc-icon"><svg class="tc-image-save-button-dynamic tc-image-button" height="22pt" viewBox="0 0 128 128" width="22pt">
<g class="tc-image-save-button-dynamic-clean">
<path d="M120.783 34.33c4.641 8.862 7.266 18.948 7.266 29.646 0 35.347-28.653 64-64 64-35.346 0-64-28.653-64-64 0-35.346 28.654-64 64-64 18.808 0 35.72 8.113 47.43 21.03l2.68-2.68c3.13-3.13 8.197-3.132 11.321-.008 3.118 3.118 3.121 8.193-.007 11.32l-4.69 4.691zm-12.058 12.058a47.876 47.876 0 013.324 17.588c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48c14.39 0 27.3 6.332 36.098 16.362L58.941 73.544 41.976 56.578c-3.127-3.127-8.201-3.123-11.32-.005-3.123 3.124-3.119 8.194.006 11.319l22.617 22.617a7.992 7.992 0 005.659 2.347c2.05 0 4.101-.783 5.667-2.349l44.12-44.12z" fill-rule="evenodd"></path>
</g>