1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-23 10:07:19 +00:00

Adopt new URL scheme for permalinks

Instead of using `%00` as a separator we do the more conventional
`#!<target-title>:<story filter>`.
This commit is contained in:
Jermolene 2014-05-03 11:32:55 +01:00
parent 327b53a641
commit a5e9ef9b5f
4 changed files with 88 additions and 57 deletions

View File

@ -25,6 +25,8 @@ var DEFAULT_HISTORY_TITLE = "$:/HistoryList";
// Default tiddlers
var DEFAULT_TIDDLERS_TITLE = "$:/DefaultTiddlers";
// Favicon tiddler
var FAVICON_TITLE = "$:/favicon.ico";
var widget = require("$:/core/modules/widgets/widget.js");
@ -75,34 +77,37 @@ exports.startup = function() {
// Clear outstanding tiddler store change events to avoid an unnecessary refresh cycle at startup
$tw.wiki.clearTiddlerEventQueue();
// Decode the hash portion of our URL
var parts = [];
var target,
storyFilter;
if($tw.locationHash.charAt(1) === "!") {
parts = decodeURIComponent($tw.locationHash.substr(2)).split("\u0000")
var hash = $tw.locationHash.substr(2),
split = hash.indexOf(":");
if(split === -1) {
target = decodeURIComponent(hash.trim());
} else {
target = decodeURIComponent(hash.substr(0,split - 1).trim());
storyFilter = decodeURIComponent(hash.substr(split + 1).trim());
}
}
if(parts[0]) {
// Set the history
var historyList = [{title: parts[0]}];
$tw.wiki.setTiddlerData(DEFAULT_HISTORY_TITLE, historyList, {"current-tiddler": parts[0]});
// Set the story
var story = [];
for(var t=1; t<parts.length; t++) {
if(parts[t]) {
story.push(parts[t]);
}
// If a target tiddler was specified add it to the history stack
if(target && target !== "") {
// The target tiddler doesn't need double square brackets, but we'll silently remove them if they're present
if(target.indexOf("[[") === 0 && target.substr(-2) === "]]") {
target = target.substr(2,target.length - 4);
}
// If the story is empty use the default tiddlers
if(story.length === 0) {
story = getDefaultTiddlers();
}
// If the target tiddler isn't included then splice it in at the top
if(story.indexOf(parts[0]) === -1) {
story.unshift(parts[0]);
}
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: story},$tw.wiki.getModificationFields());
} else {
// Display the default tiddlers if the hash portion was empty
displayDefaultTiddlers();
$tw.wiki.addToHistory(target);
}
// Use the story filter specified in the hash, or the default tiddlers
if(!storyFilter || storyFilter === "") {
storyFilter = $tw.wiki.getTiddlerText(DEFAULT_TIDDLERS_TITLE);
}
var storyList = $tw.wiki.filterTiddlers(storyFilter);
// If the target tiddler isn't included then splice it in at the top
if(target && storyList.indexOf(target) === -1) {
storyList.unshift(target);
}
// Save the story list
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: storyList},$tw.wiki.getModificationFields());
// Set up the syncer object
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki});
// Host-specific startup
@ -205,20 +210,25 @@ exports.startup = function() {
}
});
// Set up the favicon
var faviconTitle = "$:/favicon.ico",
faviconLink = document.getElementById("faviconLink"),
var faviconLink = document.getElementById("faviconLink"),
setFavicon = function() {
var tiddler = $tw.wiki.getTiddler(faviconTitle);
var tiddler = $tw.wiki.getTiddler(FAVICON_TITLE);
if(tiddler) {
faviconLink.setAttribute("href","data:" + tiddler.fields.type + ";base64," + tiddler.fields.text);
}
};
setFavicon();
$tw.wiki.addEventListener("change",function(changes) {
if($tw.utils.hop(changes,faviconTitle)) {
if($tw.utils.hop(changes,FAVICON_TITLE)) {
setFavicon();
}
});
// Set up location hash update
$tw.wiki.addEventListener("change",function(changes) {
if($tw.utils.hop(changes,DEFAULT_STORY_TITLE) || $tw.utils.hop(changes,DEFAULT_HISTORY_TITLE)) {
updateLocationHash();
}
});
// Set up the styles
var styleTemplateTitle = "$:/core/ui/PageStylesheet",
styleParser = $tw.wiki.parseTiddler(styleTemplateTitle);
@ -266,24 +276,11 @@ exports.startup = function() {
}
};
/*
Helper to display the default tiddlers
*/
function displayDefaultTiddlers() {
// Get the default tiddlers
var defaultTiddlersTitle = "$:/DefaultTiddlers",
defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle),
defaultTiddlers = [];
if(defaultTiddlersTiddler) {
defaultTiddlers = $tw.wiki.filterTiddlers(defaultTiddlersTiddler.fields.text);
}
// Initialise the story
var story = [];
for(var t=0; t<defaultTiddlers.length; t++) {
story[t] = defaultTiddlers[t];
}
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: story},$tw.wiki.getModificationFields());
$tw.wiki.addTiddler({title: DEFAULT_STORY_TITLE, text: "", list: getDefaultTiddlers()},$tw.wiki.getModificationFields());
}
function getDefaultTiddlers() {
@ -295,6 +292,16 @@ function getDefaultTiddlers() {
return defaultTiddlers;
}
function updateLocationHash() {
var storyList = $tw.wiki.getTiddlerList(DEFAULT_STORY_TITLE),
historyList = $tw.wiki.getTiddlerData(DEFAULT_HISTORY_TITLE,[]);
var targetTiddler = "";
if(historyList.length > 0) {
targetTiddler = historyList[historyList.length-1].title;
}
location.hash = "#!" + encodeURIComponent(targetTiddler) + ":" + encodeURIComponent($tw.utils.stringifyList(storyList));
}
/*
Main render function for PageMacros, which includes the PageTemplate
*/

View File

@ -133,15 +133,7 @@ title: a title string or an array of title strings
fromPageRect: page coordinates of the origin of the navigation
*/
NavigatorWidget.prototype.addToHistory = function(title,fromPageRect) {
var titles = $tw.utils.isArray(title) ? title : [title];
// Add a new record to the top of the history stack
if(this.historyTitle) {
var historyList = this.wiki.getTiddlerData(this.historyTitle,[]);
$tw.utils.each(titles,function(title) {
historyList.push({title: title, fromPageRect: fromPageRect});
});
this.wiki.setTiddlerData(this.historyTitle,historyList,{"current-tiddler": titles[titles.length-1]});
}
this.wiki.addToHistory(title,fromPageRect,this.historyTitle);
};
/*

View File

@ -1070,7 +1070,7 @@ exports.readFile = function(file,callback) {
/*
Check whether the specified draft tiddler has been modified
*/
$tw.Wiki.prototype.isDraftModified = function(title) {
exports.isDraftModified = function(title) {
var tiddler = this.getTiddler(title);
if(!tiddler.isDraft()) {
return false;
@ -1091,4 +1091,21 @@ $tw.Wiki.prototype.isDraftModified = function(title) {
});
};
/*
Add a new record to the top of the history stack
title: a title string or an array of title strings
fromPageRect: page coordinates of the origin of the navigation
historyTitle: title of history tiddler (defaults to $:/HistoryList)
*/
exports.addToHistory = function(title,fromPageRect,historyTitle) {
historyTitle = historyTitle || "$:/HistoryList";
var titles = $tw.utils.isArray(title) ? title : [title];
// Add a new record to the top of the history stack
var historyList = this.getTiddlerData(historyTitle,[]);
$tw.utils.each(titles,function(title) {
historyList.push({title: title, fromPageRect: fromPageRect});
});
this.setTiddlerData(historyTitle,historyList,{"current-tiddler": titles[titles.length-1]});
};
})();

View File

@ -6,6 +6,8 @@ type: text/vnd.tiddlywiki
Permalinks allow direct links to individual tiddlers within a TiddlyWiki.
! Simple Permalinks
The simplest form of permalink is a single target tiddler title appended to the base URL with "#!":
http://tiddlywiki.com/#!HelloThere
@ -14,13 +16,26 @@ The tiddler title can contain spaces if required:
[[http://tiddlywiki.com/#!Using TiddlyWiki on Node.js]]
The permalink can also specify the story list of tiddlers that should be opened alongside the target tiddler. The tiddler titles are separated by `%00`:
Note that double square brackets are not required around the target tiddler title; however, if present they are silently removed.
http://tiddlywiki.com/#!Tiddlers%00Tags%00TiddlerFields%00Tiddlers
! Story Permalinks
In this form, the first tiddler title is taken to be the target tiddler, and the remaining titles give the sequence of tiddlers in the story list.
The permalink can also specify the story list of tiddlers that should be opened alongside the target tiddler as a [[TiddlerFilter|TiddlerFilters]]:
[[http://tiddlywiki.com/#!TiddlerFields:Tiddlers TiddlerTags TiddlerFields ContentType]]
If the target tiddler isn't present in the story list then it is automatically inserted at the top. This means that the following two examples both target the tiddler `Tiddlers` within the story sequence `Tiddlers`, `Tags`, `TiddlerFields`:
http://tiddlywiki.com/#!Tiddlers%00Tags%00TiddlerFields
http://tiddlywiki.com/#!Tiddlers%00Tiddlers%00Tags%00TiddlerFields
[[http://tiddlywiki.com/#!Tiddlers:Tags TiddlerFields]]
[[http://tiddlywiki.com/#!Tiddlers:Tiddlers Tags TiddlerFields]]
It is also possible to specify a story filter without specifying a target tiddler for navigation:
<a href="http://tiddlywiki.com/#!:[tags[task]]">~http://tiddlywiki.com/#!:[tags[task]]</a>
! About URL encoding
There are technical restrictions on the legal characters in an URL fragment. To allow all tiddler titles to be addressed, illegal characters are subject to a process called "URL encoding" whereby problematic characters are replaced by their numeric code. For example, the space character is replaced with `%20`.
Both the target tiddler title and the story filter should be URL encoded (but not the separating colon). TiddlyWiki generates properly encoded URLs which can look quite ugly. However, in practice browsers will usually perfectly happily process arbitrary characters in URL fragments. Thus when creating permalinks manually you can choose to ignore URL encoding.