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

Compare commits

...

20 Commits

Author SHA1 Message Date
Saq Imtiaz
bd050521ff Create eslint.yml 2025-10-02 22:30:06 +02:00
Mario Pietsch
87ba87bdd2 Set AES strength to 256 bit (#8249)
* Set AES strength to 256 bit

* Update Encryption tiddler to AES 256
2025-10-02 11:49:45 +01:00
Leilei332
619bdfcab5 Reimplement regexp sticky flag (#9119) 2025-10-02 11:42:30 +01:00
Arlen Beiler
f8170cd50a [5.4.0] Update eslint target to 2017 and do initial fixes (#9135)
* eslint manual fixes
- update eslint to 2017
- add self to forbidden globals
- fix a few unfixable bugs caught by eslint
- convert newer features in twitter-archivist

* add eslint plugin to forbid features

* import changes from @saqimtiaz

* add package.json changes
2025-10-01 15:08:00 +01:00
Jeremy Ruston
5389dc0fa7 Merge branch 'tiddlywiki-com' 2025-09-25 16:48:39 +01:00
Jeremy Ruston
2cc7c96eec Remove inadvertently committed files 2025-09-25 16:48:22 +01:00
Jeremy Ruston
8cd3d4e22c HireJeremy: Tweaks 2025-09-20 11:52:39 +01:00
Jeremy Ruston
37e09d1c25 Add Bluesky link for Jermolene 2025-09-17 14:02:13 +01:00
Jeremy Ruston
7a080092d0 Allow community cards to be edited in the browser under Node.js 2025-09-16 11:05:04 +01:00
Jeremy Ruston
810ac42810 Release notes: show current banner for the current release 2025-09-14 14:36:31 +01:00
Jeremy Ruston
88d3f69a3b Merge branch 'tiddlywiki-com' 2025-09-14 14:32:25 +01:00
Jeremy Ruston
e956bb32e9 Extend release note mechanism to allow multiple github commits/prs for a change
Also added @Leilei332's credit for #9288
2025-09-14 11:43:22 +01:00
Leilei332
dd91ac0b82 [DOCS] Button widget role attribute (#9168)
* [DOCS] Button role attribute

* Fix wrong language
2025-09-14 11:27:49 +01:00
Leilei332
af63a3b920 Further improvements for offloading server components (#9288)
* Move edition-info and repository to core-server

* Update readme

* Set platform to server for filesystem plugin

* Move startup/command.js
2025-09-14 11:21:42 +01:00
Jeremy Ruston
e4fb47ee76 Add change note for #9183 2025-09-12 17:45:13 +01:00
Jeremy Ruston
7944f42467 [v5.4.0] Offload server components from browser builds of TiddlyWiki (#9183)
* Move Node.js specific files out of the core plugin

* Package server files as new $:/core-server plugin

* Missed commander.js

* Fix crash in browser

* Extend server-only mechanism to be usable by other plugins

* in

* Revert "Extend server-only mechanism to be usable by other plugins"

This reverts commit 3faf503073.

* Revert "in"

This reverts commit b80213128f.

* Reapply "Extend server-only mechanism to be usable by other plugins"

This reverts commit c6c83bc18b.

* Fix test failure

* Move filesystem utilities into core-server

* Move old-style release notes out of the way

* Move the 5.4.0 release note into the right place

* Revert "Move the 5.4.0 release note into the right place"

This reverts commit 3f5c2bfba3.

* Revert "Move old-style release notes out of the way"

This reverts commit ee16e48a43.
2025-09-12 15:21:34 +01:00
Jeremy Ruston
578c09e0ce Remove change note for #9183 until it is merged 2025-09-12 15:19:28 +01:00
Jeremy Ruston
ffb0a2fde2 Merge branch 'tiddlywiki-com' 2025-09-12 15:15:58 +01:00
Jeremy Ruston
c5a80a1984 [v5.4.0] New release note architecture (#9287)
* Initial Commit

* Move the old release notes out of the way

* A self-referential change note

* Fix procedure name

* Rationalise link badges in old release notes

Some of them were hardly used, and getting rid of them makes it easier to see what badges we need in the new system

* Update 5.4.0 and 5.3.8 to use the new format
2025-09-12 15:13:07 +01:00
Jeremy Ruston
c22046a2c2 Fix some duplicate tiddlers
There were two Welcome tiddlers, and two tiddlers with the title "Saving with the HTML5 saver"
2025-09-11 13:29:53 +01:00
192 changed files with 567 additions and 26117 deletions

43
.github/workflows/eslint.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: ESLint
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- master
workflow_dispatch:
concurrency:
group: lint-${{ github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
# Needed for GitHub Checks API
checks: write
jobs:
eslint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm install --include=dev
- name: Run ESLint with reviewdog (GitHub Checks)
uses: reviewdog/action-eslint@v1
with:
eslint_flags: '.'
reporter: github-pr-check
fail_level: error
level: error
tool_name: ESLint PR code

View File

@@ -799,12 +799,13 @@ the password, and to encrypt/decrypt a block of text
$tw.utils.Crypto = function() {
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
currentPassword = null,
callSjcl = function(method,inputText,password) {
callSjcl = function(method,inputText,password,options) {
options = options || {};
password = password || currentPassword;
var outputText;
try {
if(password) {
outputText = sjcl[method](password,inputText);
outputText = sjcl[method](password,inputText,options);
}
} catch(ex) {
console.log("Crypto error:" + ex);
@@ -830,7 +831,8 @@ $tw.utils.Crypto = function() {
return !!currentPassword;
}
this.encrypt = function(text,password) {
return callSjcl("encrypt",text,password);
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
};
this.decrypt = function(text,password) {
return callSjcl("decrypt",text,password);
@@ -1433,7 +1435,7 @@ $tw.Wiki = function(options) {
checkTiddler = function(tiddler,title) {
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
if(title === "$:/core" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
if(title === "$:/core" || title === "$:/core-server" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
pluginTiddlers.push(tiddler);
registeredTitles.push(tiddler.fields.title);
@@ -2350,6 +2352,7 @@ $tw.loadTiddlersNode = function() {
});
// Load the core tiddlers
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.coreServerPath));
// Load any extra plugins
$tw.utils.each($tw.boot.extraPlugins,function(name) {
if(name.charAt(0) === "+") { // Relative path to plugin
@@ -2423,6 +2426,7 @@ $tw.boot.initStartup = function(options) {
// System paths and filenames
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
$tw.boot.coreServerPath = path.resolve($tw.boot.bootPath,"../core-server");
// If there's no arguments then default to `--help`
if($tw.boot.argv.length === 0) {
$tw.boot.argv = ["--help"];

View File

@@ -6,6 +6,7 @@ talk.tiddlywiki.org: jeremyruston
github: Jermolene
linkedin: www.linkedin.com/in/jermy
flickr: www.flickr.com/photos/jermy/
bluesky: https://bsky.app/profile/jermolene.bsky.social
homepage: jermolene.com
email: jeremy@jermolene.com
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAtAAEBAAMAAAAAAAAAAAAAAAAHBgIEBQEBAQEBAAAAAAAAAAAAAAAAAgQBBf/aAAwDAQACEAMQAAAANF4uTuPRhD2nBLnUiJvKM0DtMKy//8QAKxAAAgIBAwMDAQkAAAAAAAAAAQIDBBEABRITITEiMkFxFEJRUmFicoGR/9oACAEBAAE/AInTA6gUGP4ZOQbW1bPsmyUq1q+gmvFPUzZPDkPamtwqU75ks04JakroVcg5RwRjg66NUx25KbzqJYyMngfqSuq0M3NZYIebJIvZozIvI/iNPcp/aalSdJXsS4VcKeIzlvU3jVTcYLNiaGISrjkhWQYDfQ63pYAzCDBsOiu7Dsx4EHH6r2w2ttimjd2IsNErhhJHKI04/uzqxuCxpBYVVWKSHqwMyMSQ33SB7dUJFmlkMYRgnqZgCMf7rf8AeEt3A9YOhjXAb2k8u7dtT1RZeOtXmYxiOPj4ZWY/lb51skqUNnNW/wBNzC7IpB6gQeeB/jq/fqGOaLbowuYn5MAQOw8LjW5Vmeo0qIsqYLLKjHIZmwv9fB1//8QAHxEAAQMEAwEAAAAAAAAAAAAAEQABAgMSIWExMkFR/9oACAECAQE/AD9iTy2lJmHUB8BVKM4SNSOj46a29saX/8QAHREAAgICAwEAAAAAAAAAAAAAAQIAAwQRITGBkf/aAAgBAwEBPwDHpFpJZtamVSiBWT2Yt7hmCDsb+TKtsKqpGg3M/9k=

View File

@@ -76,6 +76,7 @@ WikiFolderMaker.prototype.tiddlersToIgnore = [
"$:/boot/boot.js",
"$:/boot/bootprefix.js",
"$:/core",
"$:/core-server",
"$:/library/sjcl.js",
"$:/temp/info-plugin"
];

11
core-server/plugin.info Normal file
View File

@@ -0,0 +1,11 @@
{
"title": "$:/core-server",
"name": "Core Server Components",
"description": "TiddlyWiki5 core server components",
"author": "JeremyRuston",
"core-version": ">=5.0.0",
"platform": "server",
"plugin-priority": "0",
"list": "readme",
"stability": "STABILITY_2_STABLE"
}

7
core-server/readme.tid Normal file
View File

@@ -0,0 +1,7 @@
title: $:/core-server/readme
This plugin contains TiddlyWiki's core components that are only needed on the server, comprising:
* Commands
* HTTP server code
* Utility functions for server

View File

@@ -82,6 +82,7 @@ exports.parseTokenString = function(source,pos,token) {
/*
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
Use the "Y" (sticky) flag to avoid searching the entire rest of the string
*/
exports.parseTokenRegExp = function(source,pos,reToken) {
var node = {
@@ -172,7 +173,7 @@ exports.parseMacroParameter = function(source,pos) {
start: pos
};
// Define our regexp
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/g;
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the parameter
@@ -240,7 +241,7 @@ exports.parseMacroInvocation = function(source,pos) {
params: []
};
// Define our regexps
var reMacroName = /([^\s>"'=]+)/g;
const reMacroName = /([^\s>"'=]+)/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double less than sign
@@ -277,7 +278,7 @@ exports.parseFilterVariable = function(source) {
params: [],
},
pos = 0,
reName = /([^\s"']+)/g;
reName = /([^\s"']+)/y;
// If there is no whitespace or it is an empty string then there are no macro parameters
if(/^\S*$/.test(source)) {
node.name = source;
@@ -302,11 +303,11 @@ exports.parseAttribute = function(source,pos) {
start: pos
};
// Define our regexps
var reAttributeName = /([^\/\s>"'`=]+)/g,
reUnquotedAttribute = /([^\/\s<>"'`=]+)/g,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
const reAttributeName = /([^\/\s>"'`=]+)/y,
reUnquotedAttribute = /([^\/\s<>"'`=]+)/y,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
reIndirectValue = /\{\{([^\}]+)\}\}/y,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the attribute name

View File

@@ -49,7 +49,7 @@ exports.parse = function() {
// Advance the parser position to past the tag
this.parser.pos = tag.end;
// Check for an immediately following double linebreak
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
// Set whether we're in block mode
tag.isBlock = this.is.block || hasLineBreak;
// Parse the body if we need to
@@ -100,7 +100,7 @@ exports.parseTag = function(source,pos,options) {
orderedAttributes: []
};
// Define our regexps
var reTagName = /([a-zA-Z0-9\-\$\.]+)/g;
const reTagName = /([a-zA-Z0-9\-\$\.]+)/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a less than sign
@@ -148,7 +148,7 @@ exports.parseTag = function(source,pos,options) {
pos = token.end;
// Check for a required line break
if(options.requireLineBreak) {
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
if(!token) {
return null;
}

View File

@@ -113,7 +113,7 @@ exports.parseImage = function(source,pos) {
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the source up to the terminating `]]`
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/y);
if(!token) {
return null;
}

View File

@@ -31,5 +31,7 @@ exports.startup = function() {
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
$tw.macros = $tw.modules.getModulesByTypeAsHashmap("macro");
$tw.wiki.initParsers();
$tw.Commander.initCommands();
if($tw.node) {
$tw.Commander.initCommands();
}
};

View File

@@ -181,7 +181,7 @@ ScrollableWidget.prototype.render = function(parent,nextSibling) {
};
ScrollableWidget.prototype.listenerFunction = function(event) {
self = this;
var self = this;
clearTimeout(this.timeout);
this.timeout = setTimeout(function() {
var existingTiddler = self.wiki.getTiddler(self.scrollableBind),

View File

@@ -3,7 +3,7 @@ title: $:/core/save/all-external-js
\whitespace trim
\import [subfilter{$:/core/config/GlobalImportFilter}]
\define saveTiddlerFilter()
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]] $(publishFilter)$
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]] $(publishFilter)$
\end
<!-- Important: core library is provided by serving URI encoded $:/core/templates/tiddlywiki5.js -->

View File

@@ -3,7 +3,7 @@ title: $:/core/save/offline-external-js
\whitespace trim
\import [subfilter{$:/core/config/GlobalImportFilter}]
\define saveTiddlerFilter()
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/plugins/tiddlywiki/filesystem]] -[[$:/plugins/tiddlywiki/tiddlyweb]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]] $(publishFilter)$
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/core]] -[[$:/plugins/tiddlywiki/filesystem]] -[[$:/plugins/tiddlywiki/tiddlyweb]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]] $(publishFilter)$
\end
\define defaultCoreURL() tiddlywikicore-$(version)$.js
<$let coreURL={{{ [[coreURL]is[variable]then<coreURL>else<defaultCoreURL>] }}}>

View File

@@ -2,6 +2,6 @@ title: $:/core/save/all
\import [subfilter{$:/core/config/GlobalImportFilter}]
\define saveTiddlerFilter()
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]] $(publishFilter)$
[is[tiddler]] -[prefix[$:/state/popup/]] -[prefix[$:/temp/]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]] $(publishFilter)$
\end
{{$:/core/templates/tiddlywiki5.html}}

View File

@@ -1,6 +1,6 @@
title: $:/core/save/empty
\define saveTiddlerFilter()
[is[system]] -[prefix[$:/state/popup/]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]]
[is[system]] -[prefix[$:/state/popup/]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]]
\end
{{$:/core/templates/tiddlywiki5.html}}

View File

@@ -1,7 +1,7 @@
title: $:/core/save/lazy-all
\define saveTiddlerFilter()
[is[system]] -[prefix[$:/state/popup/]] -[[$:/HistoryList]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] [is[tiddler]type[application/javascript]] +[sort[title]]
[is[system]] -[prefix[$:/state/popup/]] -[[$:/HistoryList]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] [is[tiddler]type[application/javascript]] +[sort[title]]
\end
\define skinnySaveTiddlerFilter()
[!is[system]] -[type[application/javascript]]

View File

@@ -1,7 +1,7 @@
title: $:/core/save/lazy-images
\define saveTiddlerFilter()
[is[tiddler]] -[prefix[$:/state/popup/]] -[[$:/HistoryList]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[!is[system]is[image]] +[sort[title]]
[is[tiddler]] -[prefix[$:/state/popup/]] -[[$:/HistoryList]] -[[$:/boot/boot.css]] -[is[system]type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] -[!is[system]is[image]] +[sort[title]]
\end
\define skinnySaveTiddlerFilter()
[!is[system]is[image]]

View File

@@ -4,7 +4,7 @@ title: $:/editions/de-AT-DE/download-empty
type: text/vnd.tiddlywiki
\define saveTiddlerFilter()
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/de-DE]] [[$:/languages/de-AT]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]]
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/de-DE]] [[$:/languages/de-AT]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]]
\end
\define savingEmpty()
yes

View File

@@ -2,7 +2,7 @@ title: $:/editions/es-ES/download-empty
type: text/vnd.tiddlywiki
\define saveTiddlerFilter()
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/es-ES]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]]
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/es-ES]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]]
\end
\define savingEmpty()
yes

View File

@@ -2,7 +2,7 @@ title: $:/editions/fr-FR/download-empty
type: text/vnd.tiddlywiki
\define saveTiddlerFilter()
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/fr-FR]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]]
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/fr-FR]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]]
\end
\define savingEmpty()
yes

View File

@@ -2,7 +2,7 @@ title: $:/editions/ja-JP/download-empty
type: text/vnd.tiddlywiki
\define saveTiddlerFilter()
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/ja-JP]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]]
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/ja-JP]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]]
\end
\define savingEmpty()
yes

View File

@@ -2,7 +2,7 @@ title: $:/editions/ko-KR/download-empty
type: text/vnd.tiddlywiki
\define saveTiddlerFilter()
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/ko-KR]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] +[sort[title]]
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] [[$:/languages/ko-KR]] [[$:/language]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] +[sort[title]]
\end
\define savingEmpty()
yes

View File

@@ -1,62 +0,0 @@
caption: 5.4.0
created: 20250807084952911
modified: 20250807084952911
tags: ReleaseNotes
title: Release 5.4.0
type: text/vnd.tiddlywiki
description: Under development
//[[See GitHub for detailed change history of this release|https://github.com/TiddlyWiki/TiddlyWiki5/compare/v5.3.8...master]]//
! New Features
-
! Translation improvements
*
! Plugin Improvements
*
! Widget Improvements
*
! Usability Improvements
*
! Palette Improvements
*
! Hackability Improvements
*
! Bug Fixes
*
! Node.js Improvements
*
! Performance Improvements
*
! Developer 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

@@ -2,7 +2,7 @@ title: $:/editions/tw5.com/download-empty
code-body: yes
\define saveTiddlerFilter()
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] [[$:/config/OfficialPluginLibrary]] +[sort[title]]
[[$:/core]] [[$:/isEncrypted]] [[$:/themes/tiddlywiki/snowwhite]] [[$:/themes/tiddlywiki/vanilla]] -[[$:/boot/boot.css]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[has[plugin-type]field:platform[server]] [[$:/config/OfficialPluginLibrary]] +[sort[title]]
\end
\define savingEmpty()
yes

View File

@@ -103,7 +103,7 @@ Tests the checkbox widget thoroughly.
];
var indexModeTests = fieldModeTests.map(data => {
var newData = {...data};
var newData = Object.assign({}, data);
var newName = data.testName.replace('field mode', 'index mode');
var tiddlerOneAlreadyExists = false;
var newTiddlers = data.tiddlers.map(tiddler => {
@@ -274,14 +274,13 @@ Tests the checkbox widget thoroughly.
listModeTests
.filter(data => data.widgetText.includes("listField='colors'"))
.map(data => {
var newData = {
...data,
tiddlers: data.tiddlers.map(tiddler => ({...tiddler, list: tiddler.colors, colors: undefined})),
var newData = Object.assign({}, data, {
tiddlers: data.tiddlers.map(tiddler => Object.assign({}, tiddler, {list: tiddler.colors, colors: undefined})),
widgetText: data.widgetText.replace("listField='colors'", "listField='list'"),
expectedChange: {
"Colors": { list: data.expectedChange.Colors.colors.split(' ') }
},
}
})
return newData;
})
);
@@ -289,20 +288,19 @@ Tests the checkbox widget thoroughly.
listModeTests
.filter(data => data.widgetText.includes("listField='colors'"))
.map(data => {
var newData = {
...data,
tiddlers: data.tiddlers.map(tiddler => ({...tiddler, tags: tiddler.colors, colors: undefined})),
var newData = Object.assign({}, data, {
tiddlers: data.tiddlers.map(tiddler => Object.assign({}, tiddler, {tags: tiddler.colors, colors: undefined})),
widgetText: data.widgetText.replace("listField='colors'", "listField='tags'"),
expectedChange: {
"Colors": { tags: data.expectedChange.Colors.colors.split(' ') }
},
}
})
return newData;
})
);
var indexListModeTests = listModeTests.map(data => {
var newData = {...data};
var newData = Object.assign({}, data);
var newName = data.testName.replace('list mode', 'index list mode');
var newTiddlers = data.tiddlers.map(tiddler => {
if (tiddler.hasOwnProperty('colors')) {

View File

@@ -1137,7 +1137,7 @@ Tests the filtering mechanism.
// No such tiddlers. Nothing to return.
expect(wiki.filterTiddlers("[[nonexistent]moduleproperty[name]]").length).toBe(0);
// Non string properties should get toStringed.
expect(wiki.filterTiddlers("[[$:/core/modules/commands/init.js]moduleproperty[info]]").join(" ")).toBe('{"name":"init","synchronous":true}');
expect(wiki.filterTiddlers("[[$:/core/modules/startup.js]moduleproperty[synchronous]]").join(" ")).toBe('true');
});
it("should minimize unnecessary variable lookup", function() {

View File

@@ -1,191 +0,0 @@
body {
font-size: 62.5%;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
a {
color: #BC4378;
}
.ts-loggedin .ts-openidlogin,
.ts-loggedin .ts-login {
display: none;
}
form input {
width: 90px;
border: solid 1px #CCC;
height: 24px;
}
.ts-login input,
.ts-logout input {
font-size: 11px;
}
form input[type=text],
form input[type=password] {
border-radius: 2px;
padding: 0.1em 0.5em;
}
form input[type=submit] {
width: auto;
}
.ts-logout,
.ts-logout form {
font-size: 1.6em;
text-align: center;
}
.ts-logout form {
display: inline;
}
#app-list {
background: #F0F4F8;
list-style: none;
padding: 0; margin: 0;
}
#app-list li {
height: 4.5em;
line-height: 4.5em;
background: url(/bags/common/tiddlers/double_angle_lightblue_42x42.png) no-repeat 90% #F0F4F8;
background-size: 24px 24px;
}
#app-list li:hover {
cursor: pointer;
background: url(/bags/common/tiddlers/double_angle_lightblue_42x42.png) no-repeat 90% #0082AF;
background-size: 24px 24px;
}
#app-list li form,
#app-list li a {
display: block;
height: 100%;
font-size: 2em;
text-decoration: none;
color: #8C9DA7;
width: 100%;
font-weight: normal;
}
#app-list li input {
width: 50%;
}
#app-list li:hover a {
color: #E56AA0;
}
.tsbackstage #app-list li:hover a {
color: #fff;
}
#app-list .app-img {
position: relative;
top: 0.2125em;
margin: 0 1.25em 0 1em;
height: 1.25em;
width: 1.25em;
}
#app-list .search .app-img {
margin-right: 10px;
}
.ts-loggedin .login-method:target,
.login-method {
display: none;
}
.login-method {
display: block;
}
.login-method-hide {
display: none;
}
.login-method p {
padding-bottom: 5px;
}
.tsbackstage .message {
color: #4C4A54;
display: block;
text-align: center;
}
.tsbackstage .message a {
text-decoration: none;
}
.btn {
border-radius: 2px;
}
.btn-action {
background: #0082AF;
color: #fff;
border: none;
}
.btn-action:hover {
box-shadow: 0 0 3px rgba(0,0,0,.5);
}
form input.btn-system {
background: #F8F9F9;
color: #4C4A54;
border: 1px solid rgba(0,0,0,.2);
}
.btn-system:hover {
color: #000;
cursor: pointer;
box-shadow: 0 0 3px rgba(0,0,0,.25);
}
.search form {
height: 4.5em;
}
.search input {
font-size: 1em;
border: none;
outline: none;
padding: 0.2em 0.5em;
background: transparent;
border-radius: 2px;
}
.search:hover input {
color: #fff;
}
.search input:focus {
-webkit-box-shadow: inset 0 0 8px rgba(140,157,167,0.75);
-moz-box-shadow: inset 0 0 8px rgba(140,157,167,0.75);
box-shadow: inset 0 0 8px rgba(140,157,167,0.75);
}
.search:hover input:focus {
-webkit-box-shadow: inset 0 0 8px rgba(255,255,255,0.5);
-moz-box-shadow: inset 0 0 8px rgba(255,255,255,0.5);
box-shadow: inset 0 0 8px rgba(255,255,255,0.5);
}
.logindetails {
background: #fff;
padding: 1em 1em 2em;
box-shadow: 0 0 6px 0px rgba(0, 0, 0, 0.25);
z-index: 1;
position: relative;
text-align: center;
}
.logindetails p {
margin: 0;
}

View File

@@ -1,95 +0,0 @@
<!DOCTYPE html>
<!-- saved from url=(0078)http://interview.tiddlyspace.com/bags/common/tiddlers/backstage#userpass-login -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="./normalize.css">
<link rel="stylesheet" href="./app.css">
</head>
<body class="tsbackstage ts-loggedin ts-member">
<div class="logindetails">
<form class="ts-login login login-method" action="http://interview.tiddlyspace.com/bags/common/tiddlers/backstage" autocomplete="off" id="userpass-login">
<p>login via <a class="toggle-form" href="http://interview.tiddlyspace.com/bags/common/tiddlers/backstage#openid-login">openid</a></p>
<input autocapitalize="off" autocorrect="off" type="text" name="username" placeholder="username">
<input autocapitalize="off" autocorrect="off" type="password" name="password" placeholder="password">
<input type="hidden" name="redirect" value="/bags/common/tiddlers/backstage?action=login#refreshParent">
<input type="submit" class="btn btn-action" value="Log In">
</form>
<form class="ts-openidlogin login-method login-method-hide" id="openid-login" method="post" action="http://interview.tiddlyspace.com/challenge/tiddlywebplugins.tiddlyspace.openid">
<p>login with <a class="toggle-form" href="http://interview.tiddlyspace.com/bags/common/tiddlers/backstage#userpass-login">username and password</a></p>
<input name="tiddlyweb_redirect" type="hidden" value="/bags/common/tiddlers/backstage">
<input class="openid" autocapitalize="off" autocorrect="off" type="text" name="openid" placeholder="your openid">
<input class="button btn btn-action" type="submit" value="Sign In">
<a class="openid-help" href="http://openid.net/get-an-openid/">What is an open id?</a>
</form>
<div class="ts-logout logout"><span class="message">Welcome back <a href="http://jermolene.tiddlyspace.com/" target="_parent">jermolene</a><span>!</span></span>
<form method="post" action="http://interview.tiddlyspace.com/logout">
<input type="hidden" name="tiddlyweb_redirect" value="/bags/common/tiddlers/backstage?action=login#refreshParent">
<input type="submit" class="btn btn-system" value="Log out">
<input type="hidden" name="csrf_token" value="2016120917:jermolene:8cef480d1bd2bf774327ae085b2efa8bb7937fd1"></form>
</div>
</div>
<div><ul id="app-list">
<li class="search">
<form method="GET" target="_blank" action="http://interview.tiddlyspace.com/hsearch">
<img src="./search.png" alt="Search Icon" class="app-img">
<input type="text" name="q" placeholder="Search">
</form></li>
<li class="help">
<a href="http://help.tiddlyspace.com/" target="_blank">
<img src="./help.png" alt="Help SiteIcon" class="app-img">Help
</a>
</li>
<li class="space">
<a href="http://interview.tiddlyspace.com/_space" target="_blank">
<img src="./SiteIcon(24)" alt="Space SiteIcon" class="app-img">This space
</a>
</li>
<li class="account"><a target="_blank" href="http://jermolene.tiddlyspace.com/_account"><img class="app-img" alt="SiteIcon for jermolene" src="./SiteIcon">Your account</a></li></ul></div>
<script type="text/javascript" src="./jquery.js"></script>
<script type="text/javascript" src="./chrjs"></script>
<script type="text/javascript" src="./chrjs.users"></script>
<script type="text/javascript" src="./chrjs.space"></script>
<script type="text/javascript" src="./chrjs.identities"></script>
<script type="text/javascript" src="./ts.js"></script>
<script src="./status.js"></script>
<script type="text/javascript">
if(window.location.hash === "#refreshParent") {
window.location.hash = "";
window.parent.location.reload();
}
var li, siteiconurl, link, host;
ts.init(function(ts) {
host = ts.getHost(ts.user.name);
$(document.body).show();
window.location.hash = "#userpass-login";
if (ts.user.anon) {
$('.toggle-form').click(function(ev) {
$(this).closest('form').addClass('login-method-hide')
.siblings('form').removeClass('login-method-hide');
ev.preventDefault();
});
}
if ($(document.body).hasClass('ts-nonmember')) {
$('.write').remove();
}
if(!ts.user.anon) {
li = $('<li class="account" />').appendTo("#app-list")[0];
siteiconurl = host + '/bags/' + ts.user.name + '_public/tiddlers/SiteIcon';
link = $('<a target="_blank" />').attr("href", host + "/_account").
text("Your account").appendTo(li);
$('<img class="app-img">').attr("alt", 'SiteIcon for ' + ts.user.name).
attr("src", siteiconurl).prependTo(link);
}
}, {});
(function($) {
$(function() {
// send doc height to parent window
var totalHeight = $("html").height();
if(self !== top && !!window.postMessage) {
parent.postMessage(totalHeight, "*");
}
});
}(jQuery));
</script>
</body></html>

View File

@@ -1,360 +0,0 @@
/***
Adds the app switcher to a TiddlySpace app.
Makes use of tw.Stylesheet
Triple licensed under the BSD, MIT and GPL licenses:
http://www.opensource.org/licenses/bsd-license.php
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
***/
(function() {
// Add or replace a style sheet
// css argument is a string of CSS rule sets
// options.id is an optional name identifying the style sheet
// options.doc is an optional document reference
// N.B.: Uses DOM methods instead of jQuery to ensure cross-browser comaptibility.
var twStylesheet = function(css, options) {
options = options || {};
var id = options.id || "backstageStyleSheet";
var doc = options.doc || document;
var el = doc.getElementById(id);
if(doc.createStyleSheet) { // IE-specific handling
if(el) {
el.parentNode.removeChild(el);
}
doc.getElementsByTagName("head")[0].insertAdjacentHTML("beforeEnd",
'&nbsp;<style id="' + id + '" type="text/css">' + css + '</style>'); // fails without &nbsp;
} else { // modern browsers
if(el) {
el.replaceChild(doc.createTextNode(css), el.firstChild);
} else {
el = doc.createElement("style");
el.type = "text/css";
el.id = id;
el.appendChild(doc.createTextNode(css));
doc.getElementsByTagName("head")[0].appendChild(el);
}
}
};
// detect background-size support
// in <IE9 need to fallback to msfilter property
function hasBgSizing() {
var supported,
elem = document.createElement('div');
document.body.appendChild(elem);
elem.style.cssText = "background-size: cover;";
supported = (elem.style.backgroundSize === undefined || elem.style.backgroundSize === null) ? false : true;
// clean up
elem.parentNode.removeChild(elem);
return supported;
}
// ms filters as fix for not supporting background-size property
var msfilter_in = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/bags/tiddlyspace/tiddlers/privateAndPublicIcon', sizingMethod='scale')",
msfilter_out = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/bags/tiddlyspace/tiddlers/publicIcon', sizingMethod='scale')";
var stylesheet = ["#tsbackstage {",
" height: 256px; /* default value unless changed */",
" z-index: 1000;",
" position: relative;",
"}",
"",
"#app-picker {",
" cursor: pointer;",
" position: absolute;",
" right: 24px;",
" top: 0px;",
" width: 24px;",
" height: 24px;",
" background-size: 24px 24px;",
" text-indent: -999px;",
" overflow: hidden;",
" z-index: 2000;",
" border: none;",
" opacity: 0.5;",
"}",
"",
"#app-picker:hover {",
" background-color: none !important;",
" opacity: 1;",
"}",
"",
".bs-popup {",
" width: 100%;",
" position: absolute;",
" z-index: 1000;",
" right: 10px;",
" top: 36px;",
"}",
"",
".bubble .description {",
" margin-left: 70px;",
" margin-top: 2px;",
"}",
"",
".bubble {",
" float: right;",
" font-size: 0.9em;",
" font-family: Georgia;",
" position: relative;",
" width: 300px;",
" margin: 0px auto 0px auto;",
" margin: top right bottom left;",
" border: solid 1px rgb(200, 200, 200);",
" border-radius: 4px;",
" -webkit-box-shadow: 0px 0px 4px rgba(0,0,0,.2);",
" -moz-box-shadow: 0px 0px 4px rgba(0,0,0,.2);",
" -o-box-shadow: 0px 0px 4px rgba(0,0,0,.2);",
" -ms-box-shadow: 0px 0px 4px rgba(0,0,0,.2);",
" box-shadow: 0px 0px 4px rgba(0,0,0,.2);",
" background-color: #F0F4F8;",
"}",
"",
".ts-logout {",
" display: none;",
"}",
".ts-loggedin .ts-logout {",
" display: block;",
"}",
".arrow {",
" border-width: 0 10px 10px;",
" border-style: dashed dashed solid;",
" width: 0;",
" height: 0;",
" border-color: transparent;",
" display: inline-block;",
" position: absolute;",
" top: -10px;",
" right: 16px;",
" border-bottom-color: #fff;",
"}",
".bubble div.whitearrow {",
" top: -11px;",
" border-bottom-color: rgba(0,0,0,0.25);",
"}",
".ts-terms {",
" color: #999;",
" display: block;",
" font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Garuda, Verdana, Tahoma, sans-serif;",
" font-size: 12px;",
" font-style: normal;",
" font-variant: normal;",
" font-weight: normal;",
" height: 46px;",
" line-height: 16.7999992370605px;",
" z-index: 800;",
" background-color: rgb(218, 218, 218);",
" padding-right: 50px;",
" padding-top: 10px;",
" padding-left: 10px;",
" padding-bottom: 10px;",
"}",
".ts-terms a {",
" color: #333;",
"}",
".ts-service-update {",
" padding: 10px;",
" background-color: red;",
" font-family: Arial;",
" color: #ffffff;",
" font-size: 15px;",
" text-align: center;",
"}",
".ts-service-update a {",
" color: #ffffff;",
" font-weight: bold;",
" text-decoration: underline;",
"}",
".ts-service-update a:hover {",
" background-color: #cc0000;",
" text-decoration: none;",
"}"
].join("\n");
function addEventListener(node, event, handler, bubble) {
if (node.addEventListener){
node.addEventListener(event, handler, bubble);
} else if (node.attachEvent){
event = event == "click" ? "onclick" : event;
event = event == "load" ? "onload" : event;
node.attachEvent(event, handler);
}
}
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+d.toUTCString();
document.cookie = cname + "=" + cvalue + "; " + expires;
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1);
if (c.indexOf(name) != -1) return c.substring(name.length,c.length);
}
return "";
}
var loadEvent = function() {
var link = document.createElement("a");
link.setAttribute("id", "app-picker");
link.setAttribute("class", "app-picker");
link.setAttribute("title", "Click to navigate around tiddlyspace");
link.appendChild(document.createTextNode("tiddlyspace"));
var backgroundSizeSupported = hasBgSizing();
// Quite a hack. GUEST does not have a csrf token.
if (/csrf_token=\d+:\w+:\w+/.test(document.cookie)) {
if( backgroundSizeSupported ) {
link.style.backgroundImage = 'url(/bags/tiddlyspace/tiddlers/privateAndPublicIcon)';
} else {
link.style.filter = msfilter_in;
}
} else {
if( backgroundSizeSupported ) {
link.style.backgroundImage = 'url(/bags/tiddlyspace/tiddlers/publicIcon)';
} else {
link.style.filter = msfilter_out;
}
stylesheet = stylesheet.replace('height: 180px;', 'height: 156px;');
}
var body = document.getElementsByTagName("BODY")[0];
body.insertBefore(link, body.firstChild);
var html = [
'<div class="bubble">',
'<iframe src="/bags/common/tiddlers/backstage#userpass-login" name="tsbackstage" id="tsbackstage" width="auto" frameborder=0 border=0></iframe>',
'<div class="arrow whitearrow"></div>',
'<div class="arrow"></div>',
'</div>'].join("");
var bubble = document.createElement("div");
bubble.setAttribute("id", "bs-popup");
bubble.style.cssText = "visibility:hidden;";
bubble.className = "bs-popup";
bubble.innerHTML = html;
body.insertBefore(bubble, link);
//Terms and Conditions
if (document.getElementById("backstageButton")) {
//backstage area is displayed, so also check for terms acceptance;
var acceptedTermsVersion,
latestTermsVersion = 'v1.0-dec2014',
privacyPolicyOpen = false,
cookiePolicyOpen = false;
acceptedTermsVersion = getCookie('termsAccepted');
if (acceptedTermsVersion !== latestTermsVersion) {
html = 'The tiddlyspace service uses cookies. By using the service, you are agreeing to the <a href="http://osmo-terms.tiddlyspace.com/Cookies20141205" target="_blank">Cookie Policy</a>. We have updated tiddlyspace <a href="http://osmo-terms.tiddlyspace.com/TermsOfService20141205" target="_blank">Terms of Service</a>, effective as of 05 December 2014. By using the service you\'re agreeing to the updated terms. <a id="acceptTermsId" href="#">OK, got it</a>.';
var terms = document.createElement('div');
terms.setAttribute('id', 'bs-terms');
terms.className = 'ts-terms';
terms.innerHTML = html;
contentWrapper = document.getElementById('contentWrapper');
body.insertBefore(terms, contentWrapper);
addEventListener(document.getElementById("acceptTermsId"), "click", function(ev) {
setCookie('termsAccepted', latestTermsVersion, 365);
terms.style.cssText = "display:none;";
});
}
//Add Service Update Message
html = 'Service Update: <a href="http://osmo-service.tiddlyspace.com/ServiceUpdate20161205">***Please read this important Tiddlyspace service announcement December 5th 2016 ***</a>';
var serviceUpdate = document.createElement('div');
serviceUpdate.setAttribute('id', 'bs-serviceUpdate');
serviceUpdate.className = 'ts-service-update';
serviceUpdate.innerHTML = html;
contentWrapper = document.getElementById('contentWrapper');
body.insertBefore(serviceUpdate, contentWrapper);
//End of Service Update Message
}
//End of Terms and Conditions
twStylesheet(stylesheet);
var bubbleFadeInterval;
function fade(el, fadeIn) {
var opacity = fadeIn ? 0 : 1;
if(bubbleFadeInterval) {
clearInterval(bubbleFadeInterval);
}
bubbleFadeInterval = setInterval(function() {
// TODO: IE does not support opacity
el.style.cssText = "opacity:" + opacity;
opacity = fadeIn ? opacity + 0.1 : opacity - 0.1;
if(opacity < 0 || opacity > 1) {
clearInterval(bubbleFadeInterval);
el.style.cssText = fadeIn ? "" : "visibility:hidden;";
}
}, 25);
}
addEventListener(link, "mousedown", function(ev) {
ev.preventDefault();
}, false);
var bubbleOpen = false;
var toggleBubble = function(ev) {
if(ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = false;
}
if(bubbleOpen) {
fade(bubble, false);
} else {
fade(bubble, true);
}
bubbleOpen = !bubbleOpen;
};
addEventListener(link, "click", toggleBubble);
addEventListener(window.document.body, "click",
function(ev) {
var targ,
ev = ev || window.event;
if (ev.target) targ = ev.target;
else if (ev.srcElement) targ = ev.srcElement;
if(targ == link) {
return;
}
if(bubbleOpen) {
toggleBubble(ev);
}
}, true);
addEventListener(bubble, "click", function(ev) {
if(ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = false;
}
});
};
if(window.top == window) { // only add the backstage when NOT in an iframe (top window)
addEventListener(window, "load", loadEvent);
// check if postMessage is supported
// best test: https://github.com/ternarylabs/porthole/pull/10
if(!!window.postMessage) {
addEventListener(window, "message", function(e) {
var iframe = document.getElementById('tsbackstage');
if(e.data) {
iframe.style.height = e.data + "px";
}
});
}
}
})();

View File

@@ -1,373 +0,0 @@
/***
https://raw.github.com/tiddlyweb/chrjs/master/main.js
***/
//{{{
// TiddlyWeb adaptor
// v0.14.3
/*jslint vars: true, unparam: true, nomen: true, white: true */
/*global jQuery */
var tiddlyweb = (function($) {
"use strict";
var tw = {
routes: {
// host is the TiddlyWeb instance's URI (including server_prefix)
// placeholders "_type" & "name" refer to the respective bag/recipe
root : "{host}/",
bags : "{host}/bags",
bag : "{host}/bags/{name}",
recipes : "{host}/recipes",
recipe : "{host}/recipes/{name}",
tiddlers : "{host}/{_type}s/{name}/tiddlers",
tiddler : "{host}/{_type}s/{name}/tiddlers/{title}",
revisions: "{host}/{_type}s/{name}/tiddlers/{title}/revisions",
revision : "{host}/{_type}s/{name}/tiddlers/{title}/revisions/{revision}",
search : "{host}/search?q={query}"
}
};
var convertTimestamp, supplant;
// host (optional) is the URI of the originating TiddlyWeb instance
tw.Resource = function(type, host) {
if(arguments.length) { // initialization
this._type = type;
if(host !== false) {
this.host = host !== undefined ? host.replace(/\/$/, "") : null;
}
}
};
$.extend(tw.Resource.prototype, {
// retrieves resource from server
// callback is passed resource, status, XHR (cf. jQuery.ajax success)
// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
// filters is an optional filter string (e.g. "select=tag:foo;limit=5")
get: function(callback, errback, filters) {
var uri = this.route();
if(filters) {
var separator = uri.indexOf("?") === -1 ? "?" : ";";
uri += separator + filters;
}
var self = this;
return $.ajax({
url: uri,
type: "GET",
dataType: "json",
success: function(data, status, xhr) {
var resource = self.parse(data);
resource.etag = xhr.getResponseHeader("Etag");
callback(resource, status, xhr);
},
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
});
},
// sends resource to server
// callback is passed data, status, XHR (cf. jQuery.ajax success)
// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
put: function(callback, errback) {
var self = this;
var options = {
url: this.route(),
type: "PUT",
contentType: "application/json",
data: JSON.stringify(this.baseData()),
success: function(data, status, xhr) {
callback(self, status, xhr);
},
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
};
if(this.ajaxSetup) {
this.ajaxSetup(options);
}
return $.ajax(options);
},
// deletes resource on server
// callback is passed data, status, XHR (cf. jQuery.ajax success)
// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
"delete": function(callback, errback) {
var self = this;
var options = {
url: this.route(),
type: "DELETE",
success: function(data, status, xhr) {
callback(self, status, xhr);
},
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
};
if(this.ajaxSetup) {
this.ajaxSetup(options);
}
return $.ajax(options);
},
// returns an object carrying only the essential information of the resource
baseData: function() {
var data = {},
self = this;
$.each(this.data, function(i, item) {
var value = self[item];
if(value !== undefined) {
data[item] = value;
}
});
return data;
},
// returns corresponding instance from a raw object (if applicable)
parse: function(data) {
return data;
},
// list of accepted keys in serialization
data: [],
// returns resource's URI
route: function() {
return supplant(tw.routes[this._type], this);
}
});
var Container = function(type, name, host) {
if(arguments.length) { // initialization
tw.Resource.apply(this, [type, host]);
this.name = name;
this.desc = "";
this.policy = new tw.Policy({});
}
};
Container.prototype = new tw.Resource();
$.extend(Container.prototype, {
tiddlers: function() {
return new tw.TiddlerCollection(this);
},
parse: function(data) {
var type = tw._capitalize(this._type),
container = new tw[type](this.name, this.host);
data.policy = new tw.Policy(data.policy);
return $.extend(container, data);
},
data: ["desc", "policy"]
});
// attribs is an object whose members are merged into the instance (e.g. query)
tw.Collection = function(type, host, attribs) {
if(arguments.length) { // initialization
tw.Resource.apply(this, [type, host]);
$.extend(this, attribs);
}
};
tw.Collection.prototype = new tw.Resource();
tw.TiddlerCollection = function(container, tiddler) {
if(arguments.length) { // initialization
tw.Collection.apply(this, [tiddler ? "revisions" : "tiddlers"]);
this.container = container || null;
this.tiddler = tiddler || null;
}
};
tw.TiddlerCollection.prototype = new tw.Collection();
$.extend(tw.TiddlerCollection.prototype, {
parse: function(data) {
var container = this.container;
return $.map(data, function(item, i) {
var tiddler = new tw.Tiddler(item.title, container),
bag = item.bag;
tiddler = tw.Tiddler.prototype.parse.apply(tiddler, [item]);
if(!tiddler.bag && bag) { // XXX: bag always present!?
tiddler.bag = new tw.Bag(bag, container.host);
}
if(!tiddler.recipe && item.recipe) {
tiddler.recipe = new tw.Recipe(item.recipe, container.host);
}
delete item.recipe;
return $.extend(tiddler, item);
});
},
route: function() {
var params = this.container;
if(this.tiddler) {
var container = this.tiddler.bag || this.tiddler.recipe;
params = {
_type: container._type,
host: container.host,
name: container.name,
title: this.tiddler.title
};
}
return supplant(tw.routes[this._type], params);
}
});
tw.Search = function(query, host) {
tw.Collection.apply(this, ["search", host]);
this.query = query;
};
tw.Search.prototype = new tw.Collection();
$.extend(tw.Search.prototype, {
parse: function(data) {
this.container = { // XXX: hacky
_type: "bag",
host: this.host
};
var tiddlers = tw.TiddlerCollection.prototype.parse.apply(this, arguments);
delete this.container;
return tiddlers;
}
});
// title is the name of the tiddler
// container (optional) is an instance of either Bag or Recipe
// optionally accepts a single object representing tiddler attributes
tw.Tiddler = function(title, container) {
tw.Resource.apply(this, ["tiddler", false]);
this.title = title;
this.bag = container && container._type === "bag" ? container : null;
this.recipe = container && container._type === "recipe" ? container : null;
var self = this;
$.each(this.data, function(i, item) {
self[item] = undefined; // exposes list of standard attributes for inspectability
});
if(title && title.title) { // title is an object of tiddler attributes
$.extend(this, title);
}
};
tw.Tiddler.prototype = new tw.Resource();
$.extend(tw.Tiddler.prototype, {
revisions: function() {
return new tw.TiddlerCollection(this.bag || this.recipe, this);
},
route: function() {
var container = this.bag || this.recipe;
var params = $.extend({}, this, {
host: container ? container.host : null,
_type: this.bag ? "bag" : (this.recipe ? "recipe" : null),
name: container ? container.name : null
});
return supplant(tw.routes[this._type], params);
},
parse: function(data) {
var tiddler = new tw.Tiddler(this.title),
container = this.bag || this.recipe;
if(data.bag) {
tiddler.bag = new tw.Bag(data.bag, container.host);
delete data.bag;
}
delete data.recipe;
tiddler.created = data.created ? convertTimestamp(data.created) : new Date();
delete data.created;
tiddler.modified = data.modified ? convertTimestamp(data.modified) : new Date();
delete data.modified;
if(this.recipe) {
tiddler.recipe = this.recipe;
}
return $.extend(tiddler, data);
},
data: ["created", "creator", "modifier", "modified", "tags", "type", "text",
"fields"],
ajaxSetup: function(options) {
var self = this;
if(this.etag && (options.type === "PUT" || options.type === "DELETE")) {
options.beforeSend = function(xhr) {
xhr.setRequestHeader("If-Match", self.etag);
};
}
if(options.type === "PUT") {
var callback = options.success;
options.success = function(data, status, xhr) {
var loc = xhr.getResponseHeader("Location"),
etag = xhr.getResponseHeader("Etag");
if(loc && etag) {
self.etag = etag;
if(!self.bag) {
var bag = loc.split("/bags/").pop().split("/")[0];
self.bag = new tw.Bag(bag, self.recipe.host);
}
callback(self, status, xhr);
} else { // IE
self.get(callback, options.error);
}
};
}
}
});
tw.Revision = function(id, tiddler) {
var container = tiddler.bag || tiddler.recipe;
tw.Tiddler.apply(this, [tiddler.title, container]);
this._type = "revision";
this.revision = id;
};
tw.Revision.prototype = new tw.Tiddler();
$.extend(tw.Revision.prototype, {
revisions: false,
data: false,
put: false,
"delete": false
});
tw.Bag = function(name, host) {
Container.apply(this, ["bag", name, host]);
};
tw.Bag.prototype = new Container();
tw.Recipe = function(name, host) {
Container.apply(this, ["recipe", name, host]);
this.recipe = [];
};
tw.Recipe.prototype = new Container();
$.extend(tw.Recipe.prototype, {
data: ["recipe"].concat(Container.prototype.data)
});
tw.Policy = function(constraints) { // TODO: validation?
var self = this;
$.each(this.constraints, function(i, item) {
self[item] = constraints[item];
});
};
tw.Policy.prototype.constraints = ["read", "write", "create", "delete",
"manage", "accept", "owner"];
/*
* utilities
*/
tw._capitalize = function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
// convert YYYYMMDDhhmmss timestamp to Date instance
convertTimestamp = function(t) {
if (t.match(/^\d{12,17}$/)) {
return new Date(Date.UTC(
parseInt(t.substr(0, 4), 10),
parseInt(t.substr(4, 2), 10) - 1,
parseInt(t.substr(6, 2), 10),
parseInt(t.substr(8, 2), 10),
parseInt(t.substr(10, 2), 10),
parseInt(t.substr(12, 2) || "0", 10),
parseInt(t.substr(14, 3) || "0", 10)
));
} else {
return new Date(Date.parse(t));
}
};
// adapted from Crockford (http://javascript.crockford.com/remedial.html)
supplant = function(str, obj) {
return str.replace(/{([^{}]*)}/g, function (a, b) {
var r = obj[b];
r = typeof r === "string" || typeof r === "number" ? r : a;
return $.inArray(b, ["host", "query"]) !== -1 ? r : encodeURIComponent(r); // XXX: special-casing
});
};
return tw;
}(jQuery));
//}}}

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