1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-01-23 11:24:40 +00:00

Compare commits

..

10 Commits

Author SHA1 Message Date
Jeremy Ruston
2fab886564 Add incompleteness warning 2025-11-09 15:42:33 +00:00
Jeremy Ruston
f4db2300be Disable the #8702 changenote as it is not yet merged 2025-11-09 15:42:11 +00:00
Jeremy Ruston
33d3372229 Styling refinements 2025-11-09 15:37:50 +00:00
Jeremy Ruston
7a304df673 Update field names 2025-11-09 15:16:07 +00:00
Jeremy Ruston
a273ed05eb Embarrassing typo 2025-11-06 21:26:54 +00:00
Jeremy Ruston
a4721ce24a Merge branch 'master' into new-release-note-architecture 2025-11-05 12:37:59 +00:00
Jeremy Ruston
3ab6302353 Formatting. More to do. 2025-11-05 10:54:32 +00:00
Jeremy Ruston
85ed513bef Slightly better description for v5.4.0 2025-11-05 10:54:15 +00:00
Jeremy Ruston
1832aff565 Add more tickets for demo and testing purposes 2025-11-05 10:54:02 +00:00
Jeremy Ruston
a07ecb6156 Introduce impact notes attached to change notes
No styles yet
2025-11-02 12:09:03 +00:00
202 changed files with 1095 additions and 2856 deletions

4
.gitattributes vendored
View File

@@ -1,4 +0,0 @@
boot/** -linguist-generated
**/tiddlywiki.files linguist-language=JSON
**/tiddlywiki.info linguist-language=JSON
**/plugin.info linguist-language=JSON

View File

@@ -1,7 +1,6 @@
name: Bug report
description: Create a report to help us improve TiddlyWiki 5
title: "[BUG] "
type: bug
body:
- type: textarea
id: Describe

View File

@@ -4,7 +4,6 @@ about: Suggest an idea for TiddlyWiki 5
title: "[IDEA]"
labels: ''
assignees: ''
type: feature
---

View File

@@ -20,7 +20,7 @@ jobs:
steps:
- name: build-size-check
id: get_sizes
uses: TiddlyWiki/cerebrus@v6
uses: TiddlyWiki/cerebrus@v4
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}

View File

@@ -25,7 +25,7 @@ jobs:
steps:
- name: Build and check size
uses: TiddlyWiki/cerebrus@v6
uses: TiddlyWiki/cerebrus@v4
with:
pr_number: ${{ inputs.pr_number }}
repo: ${{ github.repository }}

View File

@@ -0,0 +1,18 @@
name: Validate PR Paths
on:
pull_request_target:
types: [opened, reopened, synchronize]
jobs:
validate-pr:
runs-on: ubuntu-latest
steps:
- name: Validate PR
uses: TiddlyWiki/cerebrus@v4
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
base_ref: ${{ github.base_ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,37 +0,0 @@
name: PR Validation
on:
pull_request_target:
types: [opened, reopened, synchronize]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
validate-pr:
runs-on: ubuntu-latest
steps:
# Step 1: Validate PR paths
- name: Validate PR Paths
uses: TiddlyWiki/cerebrus@v6
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
base_ref: ${{ github.event.pull_request.base.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: rules
continue-on-error: true
# Step 2: Validate change notes
- name: Validate Change Notes
uses: TiddlyWiki/cerebrus@v6
with:
pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }}
base_ref: ${{ github.event.pull_request.base.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
mode: changenotes
continue-on-error: false

View File

@@ -8,8 +8,6 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
\*/
/* eslint-disable @stylistic/indent */
var _boot = (function($tw) {
/*jslint node: true, browser: true */
@@ -46,8 +44,12 @@ $tw.utils.hop = function(object,property) {
return object ? Object.prototype.hasOwnProperty.call(object,property) : false;
};
/** @deprecated Use Array.isArray instead */
$tw.utils.isArray = value => Array.isArray(value);
/*
Determine if a value is an array
*/
$tw.utils.isArray = function(value) {
return Object.prototype.toString.call(value) == "[object Array]";
};
/*
Check if an array is equal by value and by reference.
@@ -126,22 +128,35 @@ $tw.utils.pushTop = function(array,value) {
return array;
};
/** @deprecated Use instanceof Date instead */
$tw.utils.isDate = value => value instanceof Date;
/*
Determine if a value is a date
*/
$tw.utils.isDate = function(value) {
return Object.prototype.toString.call(value) === "[object Date]";
};
/** @deprecated Use array iterative methods instead */
/*
Iterate through all the own properties of an object or array. Callback is invoked with (element,title,object)
*/
$tw.utils.each = function(object,callback) {
var next,f,length;
if(object) {
if(Array.isArray(object)) {
object.every((element,index,array) => {
const next = callback(element,index,array);
return next !== false;
});
if(Object.prototype.toString.call(object) == "[object Array]") {
for(f=0, length=object.length; f<length; f++) {
next = callback(object[f],f,object);
if(next === false) {
break;
}
}
} else {
Object.entries(object).every(entry => {
const next = callback(entry[1], entry[0], object);
return next !== false;
});
var keys = Object.keys(object);
for(f=0, length=keys.length; f<length; f++) {
var key = keys[f];
next = callback(object[key],key,object);
if(next === false) {
break;
}
}
}
}
};
@@ -316,13 +331,32 @@ $tw.utils.htmlDecode = function(s) {
return s.toString().replace(/&lt;/mg,"<").replace(/&nbsp;/mg,"\xA0").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&");
};
/** @deprecated Use window.location.hash instead. */
$tw.utils.getLocationHash = () => window.location.hash;
/*
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
*/
$tw.utils.getLocationHash = function() {
var href = window.location.href;
var idx = href.indexOf('#');
if(idx === -1) {
return "#";
} else if(href.substr(idx + 1,1) === "#" || href.substr(idx + 1,3) === "%23") {
// Special case: ignore location hash if it itself starts with a #
return "#";
} else {
return href.substring(idx);
}
};
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
$tw.utils.pad = function(value,length = 2) {
const s = value.toString();
return s.padStart(length, "0");
/*
Pad a string to a given length with "0"s. Length defaults to 2
*/
$tw.utils.pad = function(value,length) {
length = length || 2;
var s = value.toString();
if(s.length < length) {
s = "000000000000000000000000000".substr(0,length - s.length) + s;
}
return s;
};
// Convert a date into UTC YYYYMMDDHHMMSSmmm format
@@ -596,7 +630,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
// Compile the code into a function
var fn;
if($tw.browser) {
fn = window["eval"](code + "\n\n//# sourceURL=" + filename); // eslint-disable-line no-eval -- See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
} else {
if(sandbox){
fn = vm.runInContext(code,sandbox,filename)
@@ -2767,8 +2801,6 @@ return $tw;
});
/* eslint-enable @stylistic/indent */
if(typeof(exports) !== "undefined") {
exports.TiddlyWiki = _boot;
} else {

View File

@@ -12,8 +12,6 @@ See Boot.js for further details of the boot process.
\*/
/* eslint-disable @stylistic/indent */
var _bootprefix = (function($tw) {
"use strict";
@@ -116,8 +114,6 @@ return $tw;
});
/* eslint-enable @stylistic/indent */
if(typeof(exports) === "undefined") {
// Set up $tw global for the browser
window.$tw = _bootprefix(window.$tw);

View File

@@ -1,14 +0,0 @@
title: @Christian_Byron
tags: Community/Person
fullname: Christian Byron
talk.tiddlywiki.org: Christian_Byron
github: ceebeetree
linkedin: www.linkedin.com/in/christian-byron-b84a594/
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEBAAMBAAAAAAAAAAAAAAAHBgEDBQQBAAMBAAAAAAAAAAAAAAAAAAABAwX/2gAMAwEAAhADEAAAADv2xtJlY03sqePW3ARS1RSydIhcH//EACcQAAICAgIBAgYDAAAAAAAAAAECAwQFEQASMRMhBhBBk8HRIzJx/9oACAEBAAE/AMFQxs+NExqJLMCwYE+SOT4bF3qr+hAIpRsDQ6lWH0Yco4S/eVniRVQHXZzrZ5dwGQpQtNII2RfJVvHMRl5cbKxC94n/ALp+RxfiKpNcgMMUqPIwjcnWip/I5XtUowaL3Ujir/xt79Glb6/4OZ7MV5oEpUzuIa7MPB14A5jpoYLsEsydo1bbLre+CWEEEYab7Uf74ZYSSThpvtR/vmRmhnuzywp1jZtquta+VPM49qlcy24lf017At7g8uZnHrUsGK3Ez+m3UBvcnXy//8QAHhEAAgEFAAMAAAAAAAAAAAAAAQIDAAQRIkEyUaH/2gAIAQIBAT8AmiuVlZkLEeQOflJPcvMAF0z65V+h0YIW52rBDuxUrztf/8QAIxEBAAEDAwMFAAAAAAAAAAAAAgEAAxEEBSMSQcEiMVJxof/aAAgBAwEBPwC/Z1ZvNBOYz1Gc/lDUat3ySPRM/H2P3W4hcbIldpxnxW3BcjQk9oznzX//2Q==
Hello ~TiddlyWikiers - I have been a long time fan, recent contributor to the TW community.
Recently I have volunteered to run the [[TiddlyWiki Newsletter|https://tiddlywiki.substack.com/]] to spread the great news about TW.
I have been in the IT industry for about thirty years, mostly as a consultant and technical arcitect.
More recently I went back to study a masters in IT focussing on AI and data science.
Now my partner and I have started our own business ([[Sphere Innovations|https://sphere-innovations.com.au]]) - in consulting and building web applications for small to medium size businesses here in Australia.

View File

@@ -1,19 +0,0 @@
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEAAwEBAAAAAAAAAAAAAAAGAwQHAgUBAAMBAAAAAAAAAAAAAAAAAAACAwT/2gAMAwEAAhADEAAAAOfCWAMdKKetM4wOvY5OcvZnrYf/xAApEAACAQQBBAECBwAAAAAAAAABAgMABAURQQYSIVETFCIxMkJicYKh/9oACAEBAAE/AEtysaStr7mPaPeuazWdMM4gEnfPryW8hBUuZvou2RXRxyreBWPmgyNqs8f8MOQalhdY7Vz+R4/s/qfP+1edNi/zl7HDcFbmS3E8CcMR4INP0PkBhklIm+sZNtFtQiV0nj57Owl+dSrSTFgD6/CtH4VV9lU3oAbPngAVY389lc5URuUZkMxhnR4pvW0VwDqsP1FNmLWYqCpikMbngmliJNY+aKzyTxXS6lRAyg/u5rq+5x2RsuyTa3MQMlvKniRGThTUd1JYXUdzAwDvqVxGdRXMbfrVOD7HBrG3mNEsU8z98TRhl9eRzX//xAAcEQACAgIDAAAAAAAAAAAAAAABAgARAzESIVH/2gAIAQIBAT8ARuXZPsul3Eoje5lBQWBP/8QAGREAAwEBAQAAAAAAAAAAAAAAAAECEiER/9oACAEDAQE/AM98Lk7LJe20z//Z
created: 20251110102157310
first-sighting: 2019-03-01
fullname: Lin Onetwo
github: linonetwo
homepage: https://wiki.onetwo.website/
modified: 20251111184556193
tags: Community/Person Community/Team/Contributors
talk.tiddlywiki.org: linonetwo
title: @linonetwo
type: text/vnd.tiddlywiki
Since 2014, when I started college, I've been on a quest for a lifelong PKM tool. I cherish my life and all my experiences, and I dont want to forget any of them. When Im deeply focused on a task, its easy to lose sight of other important parts of my life—so I needed a system to help me stay balanced.
Early on, I tried TiddlyWiki several times, but I was initially put off by its save mechanism and markup editing. That changed when I discovered an auto-backup script, which gave me the confidence to fully commit. Over time, I improved the script and eventually transitioned to using TidGi-Desktop and TidGi-Mobile.
Today, my TiddlyWiki holds all my game design ideas and progress logs—it has truly become my second brain. With the help of LLM-powered programming tools, Ive enhanced it with numerous plugins, allowing me to manage my mind in a more programmable and structured way. As a game developer, TiddlyWiki isn't the core of my professional work; But I've invested so much time because it's fundamentally about upgrading my mind.
Most of my notes are open by default and shared publicly on my homepage as a digital garden.

View File

@@ -1,25 +0,0 @@
avatar: UklGRiwIAABXRUJQVlA4WAoAAAAwAAAAPwAAPwAASUNDUCACAAAAAAIgbGNtcwRAAABtbnRyR1JBWVhZWiAH6QALAAoACwADAAZhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkZXNjAAAAzAAAAG5jcHJ0AAABPAAAADZ3dHB0AAABdAAAABRrVFJDAAABiAAAACBkbW5kAAABqAAAACRkbWRkAAABzAAAAFJtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFIAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA81EAAQAAAAEWzHBhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbbWx1YwAAAAAAAAABAAAADGVuVVMAAAAIAAAAHABHAEkATQBQbWx1YwAAAAAAAAABAAAADGVuVVMAAAA2AAAAHABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAVlA4TOYFAAAvP8APEDWGgbRtWv+yt/0WImICOBvWn1C4dFi1bStbvpY8Qg2ePANNNAMh3N2db/7A91/7CHBvBBRr25ZFH+4k98ihkqi2CP4tsANvX8a+8y8Ct04dn0nuUt39ZiBJkowqt911M+MJ1G3bNiZJr1iP0DZ+2bbdadsqprOjAqmoUIX9hf3Fl5/uPYV7I3OMeoFzIvrvwG0kRUr3zPLdYMMXaqrMMsp0K4fufKO6c2hFV5Zh7kRROZX0PSCmB/3KWQwpuiekWelSRZDW94d0q750NrxavpFn1eLNQ9EV8nWlmAET6Q8lrCRTcjFLlLImluK3iXJW/hT47KGklS8OlzWUtXLFYDRCSS74ojUjxggqKMoxd6A1lTCyvsvyzC5/d7BsCHb7yIcHyrX2yR/NPnsAdRT2i0Pwp/o0Il6ix8hsRAuJmQgcr4KREfAiMgUVm9KqmfSxL5pOJspVwwTiV6jiIAg1RMhHpERhbvwgGI34Hc49T7UeKZtXwEqJ+BAaoBneperJH0POs1u4dufwv8Gf+qcOfjyvX6ZIVgxE0Rw87YF3BSc9c7jsXfdjOBG7FwmSb39pfGRwu8IuvUjJNoTpFzkEvDg6W3Qt/9nf99ZXPy8HM43IweTKyNR+WVatXcWWyakBksj9cqW+QetplcjsKElvZH/zuOO/PrCx//tL3/6x/O/C1PZZvSKuulLcS4l8M1ewGPR6ef5sllXW2eGQZ7hVSEZiPmcqrSS8e2ElX8o7t1fvB9LFetmEx5hx1Xuye2PpfjZnSjj7QfKTB3bZZo05Zvh6YuivX24cpc8+ddvADWG9odrSwFalVurxUiidDHmTiaoNkkh2gjbcpxMiAbd39aVP119/N9k4+euNKfcNjwaPhZEuUupUsJrHchw1LkPrRC9bQKa3M8Mj/xx903drdnHMpbirj1ENsUre0oo3N+7gat+2ZctKdsIUYc21sRu+Ucdhn+P7DyarftW00iu3Tmbv+hTfdCTmyaIPT4PrYZDFtBN2W8S9m4oTB5Z2P3Oe7weKjVBq86kXX/r0+WuvTAzfjqm1hsYRPWlbxm4n3IaeGOJEizv8orH9w5ejjmSrfOuEq/HxT6eDemtsZ/HTvvG1/8iVspxZILrlkz/cdsIbIroOgJileFSty2xiHNW5t9fbHJ3ze87bp5T9vc8RuqMB0ReDSt464R/BJxspvgpEsrVAJMTsYg2QovPTOHrvQ9et/S2Xx+40z7dY4JBX0Pz/ElH/T73U2DkK8EiqC9hM/zV3frQfzjaAqO16s1l6xCUXnBFlYxyIer3eEdth7u5xsHKxWoGLqzY3wIULt9G3K6soei9jZ+UcF+Ka3M/II9EUWrJ/LLxy+Q9xIh0vOl3NZCrVnBsuFUTOSnJnSioRWZ9q4g+ZDk5XVORoW2qX2hbIkna3JOrdR3jmpHVLovUkLES6grRO010u0GkDlX7SpH1DQ64Wl2zaSUJv1Mtti2G7kx5IyftWMhfDlGClcxvIUhP5crhp9LIb1Vne187oSAWxelcR/kXjYQTZboW+Oj1pqF0gmfZhSDD6bSgzGWrw3s7QLNtCV+2uatYrd/aFtjDI8R52e/DdyKgRKXBhEak3Ev50+GCUA9EFUor39htVMxmWvW8AM6ptG416rZvdWn+MarIEyH5r6ruZSrx8XrWDP370vbfTjqpmZGIbiFPFoihc4jcrlYi9p3ndSuymZ+XLaKza/P/HUWHn5Axdkd9OjBskY0+pIlz4AlFPFs+aStK5PBIRR4MVVJDihsy4JdEA4pVcrVqMZDyL2/8aYocikEAR9Xjc1BNG9zEiJG7n/cGyrtnblkClBhEgMW4Kx21BEBGJjLa0hcOGmTK64KsKLfKr9QyQELclxY3hqowTIZKdZNTSS5BWiBPlKxDWBVSS41bOepkhTkhGDajLfLyUBOKlkMHPgOhx3JoRN/cEiRgSWdgF2yCyDQu4IcbNo8ftTzxveOJ5y+h509h52+h549h569h587/M20f/b1AB
created: 20251110102157310
first-sighting: 2009-11-14
fullname: Mario Pietsch
github: pmario
homepage: https://wikilabs.github.io/
modified: 20251110124935183
tags: Community/Person Community/Team/Contributors
talk.tiddlywiki.org: pmario
title: @pmario
type: text/vnd.tiddlywiki
youtube: https://www.youtube.com/@pmario
''Hi, My name is Mario Pietsch''. Back in 2009 I was ''searching'' for ''a simple presentation tool'' and discovered ~TiddlyWiki Classic, Monkey Pirate ~TiddlyWiki ([[MPTW|https://mptw.tiddlyspot.com/]]) with ~TagglyTagging, Eric Shulman's ~TiddlyTools, Saq Imtiaz's navigation macros, and more. --- ''I was captivated''.
After a deep dive, I combined these elements into my own "Presentation Manager", along [[3 step by step tutorials|https://groups.google.com/g/tiddlywiki/c/qG_tZ1x0MEU/m/-vLA0luMicYJ]] to help others build it.
Thanks to ''the positive spirit'' of the ~TiddlyWiki community, I am proud to be part of it since 2009.
When Jeremy started developing ~TiddlyWiki 5 on ~GitHub, I joined in—opening [[issue no. 1|https://github.com/TiddlyWiki/TiddlyWiki5/issues/1]] all the way up to 13. For what thats good ;) Since then, I have submitted nearly 600 pull requests and more than 500 issues, many of which have been merged or resolved.
My ~TiddlyWiki 5 "laboratory" is at https://wikilabs.github.io, and I also share content on my ''~YouTube'' channel: https://www.youtube.com/@pmario
Have fun!<br>
Mario

View File

@@ -1,19 +0,0 @@
title: Developer Experience Team
tags: Community/Team
modified: 20251109200632671
created: 20251109200632671
leader: @pmario
team: @saqimtiaz
The Developer Experience Team improves the experience of software contributors to the TiddlyWiki project. This includes enhancing documentation, streamlining contribution processes, and providing tools and resources to help developers effectively contribute to TiddlyWiki.
Tools and resources managed by the Developer Experience Team include:
* Advising and assisting contributors, particularly new developers
* Maintenance of developer-focused documentation on the https://tiddlywiki.com/dev/ site, including:
** Development environment setup guides
** Code review processes and best practices
** Contribution guidelines and documentation
* Continuous integration and deployment scripts providing feedback on pull requests
* Devising and implementing labelling systems for issues and pull requests
* Automation scripts to simplify common development tasks

View File

@@ -1,8 +1,8 @@
created: 20250909171928024
modified: 20251110133437795
tags: Community/Team
team: @MotovunJack
title: Infrastructure Team
tags: Community/Team
modified: 20250909171928024
created: 20250909171928024
team: @MotovunJack
The Infrastructure Team is responsible for maintaining and improving the infrastructure that supports the TiddlyWiki project. This includes the hosting, deployment, and management of the TiddlyWiki websites and services, as well as the tools and systems used by the TiddlyWiki community.
@@ -12,4 +12,3 @@ The infrastructure includes:
* github.com/TiddlyWiki
* tiddlywiki.com DNS
* Netlify account for PR previews
* edit.tiddlywiki.com

View File

@@ -0,0 +1,6 @@
title: Newsletter Team
tags: Community/Team
modified: 20250909171928024
created: 20250909171928024
The Newsletter Team is responsible for producing the TiddlyWiki Newsletter, a monthly email newsletter that highlights news, updates, and community contributions related to TiddlyWiki.

View File

@@ -1,11 +0,0 @@
title: Quality Assurance Team
created: 20251112125742296
modified: 20251112125742296
tags: Community/Team
team:
leader: @Leilei332
title: Quality Assurance Team
The Quality Assurance Team is responsible for ensuring the quality and reliability of TiddlyWiki releases. This includes reviewing code submissions, testing new features, identifying bugs, and verifying that fixes are effective.

View File

@@ -1,15 +0,0 @@
title: TiddlyWiki Newsletter Team
tags: Community/Team
modified: 20251219090709874
created: 20250909171928024
leader: @Christian_Byron
The Newsletter Team is responsible for producing the [[TiddlyWiki Newsletter]]. We would love to have your help if you would like to get involved.
! Audience
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
Subscribing to the newsletter is intended to give people confidence that they will not miss any important developments.

View File

@@ -1,5 +1,5 @@
title: Community/Team
modified: 20250909171928024
created: 20250909171928024
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Infrastructure Team]] [[Succession Team]]

View File

@@ -156,8 +156,8 @@ Fix the height of textarea to fit content
FramedEngine.prototype.fixHeight = function() {
// Make sure styles are updated
this.copyStyles();
// If .editRows is initialised, it takes precedence
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
// Adjust height
if(this.widget.editTag === "textarea") {
if(this.widget.editAutoHeight) {
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);

View File

@@ -100,8 +100,7 @@ SimpleEngine.prototype.getText = function() {
Fix the height of textarea to fit content
*/
SimpleEngine.prototype.fixHeight = function() {
// If .editRows is initialised, it takes precedence
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
if(this.widget.editTag === "textarea") {
if(this.widget.editAutoHeight) {
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);

View File

@@ -1,41 +0,0 @@
/*\
title: $:/core/modules/filterrunprefixes/let.js
type: application/javascript
module-type: filterrunprefix
Assign a value to a variable
\*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter prefix function
*/
exports.let = function(operationSubFunction,options) {
// Return the filter run prefix function
return function(results,source,widget) {
// Save the result list
var resultList = results.toArray();
// Clear the results
results.clear();
// Evaluate the subfunction to get the variable name
var subFunctionResults = operationSubFunction(source,widget);
if(subFunctionResults.length === 0) {
return;
}
var name = subFunctionResults[0];
if(typeof name !== "string" || name.length === 0) {
return;
}
// Assign the result of the subfunction to the variable
var variables = {};
variables[name] = resultList;
// Return the variables
return {
variables: variables
};
};
};

View File

@@ -35,7 +35,7 @@ function parseFilterOperation(operators,filterString,p) {
operator.prefix = filterString.charAt(p++);
}
// Get the operator name
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
if(nextBracketPos === -1) {
throw "Missing [ in filter expression";
}
@@ -79,17 +79,13 @@ function parseFilterOperation(operators,filterString,p) {
operand.variable = true;
nextBracketPos = filterString.indexOf(">",p);
break;
case "(": // Round brackets
operand.multiValuedVariable = true;
nextBracketPos = filterString.indexOf(")",p);
break;
case "/": // regexp brackets
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
rexMatch = rex.exec(filterString.substring(p));
if(rexMatch) {
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
// DEPRECATION WARNING
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
// DEPRECATION WARNING
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
nextBracketPos = p + rex.lastIndex - 1;
}
else {
@@ -116,7 +112,7 @@ function parseFilterOperation(operators,filterString,p) {
// Check for multiple operands
while(filterString.charAt(p) === ",") {
p++;
if(/^[\[\{<\/\(]/.test(filterString.substring(p))) {
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
nextBracketPos = p;
p++;
parseOperand(filterString.charAt(nextBracketPos));
@@ -145,15 +141,7 @@ exports.parseFilter = function(filterString) {
p = 0, // Current position in the filter string
match;
var whitespaceRegExp = /(\s+)/mg,
// Groups:
// 1 - entire filter run prefix
// 2 - filter run prefix itself
// 3 - filter run prefix suffixes
// 4 - opening square bracket following filter run prefix
// 5 - double quoted string following filter run prefix
// 6 - single quoted string following filter run prefix
// 7 - anything except for whitespace and square brackets
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
while(p < filterString.length) {
// Skip any whitespace
whitespaceRegExp.lastIndex = p;
@@ -164,45 +152,38 @@ exports.parseFilter = function(filterString) {
// Match the start of the operation
if(p < filterString.length) {
operandRegExp.lastIndex = p;
match = operandRegExp.exec(filterString);
if(!match || match.index !== p) {
throw $tw.language.getString("Error/FilterSyntax");
}
var operation = {
prefix: "",
operators: []
};
match = operandRegExp.exec(filterString);
if(match && match.index === p) {
// If there is a filter run prefix
if(match[1]) {
operation.prefix = match[1];
p = p + operation.prefix.length;
// Name for named prefixes
if(match[2]) {
operation.namedPrefix = match[2];
}
// Suffixes for filter run prefix
if(match[3]) {
operation.suffixes = [];
$tw.utils.each(match[3].split(":"),function(subsuffix) {
operation.suffixes.push([]);
$tw.utils.each(subsuffix.split(","),function(entry) {
entry = $tw.utils.trim(entry);
if(entry) {
operation.suffixes[operation.suffixes.length -1].push(entry);
}
});
if(match[1]) {
operation.prefix = match[1];
p = p + operation.prefix.length;
if(match[2]) {
operation.namedPrefix = match[2];
}
if(match[3]) {
operation.suffixes = [];
$tw.utils.each(match[3].split(":"),function(subsuffix) {
operation.suffixes.push([]);
$tw.utils.each(subsuffix.split(","),function(entry) {
entry = $tw.utils.trim(entry);
if(entry) {
operation.suffixes[operation.suffixes.length -1].push(entry);
}
});
}
});
}
// Opening square bracket
if(match[4]) {
p = parseFilterOperation(operation.operators,filterString,p);
} else {
p = match.index + match[0].length;
}
} else {
// No filter run prefix
p = parseFilterOperation(operation.operators,filterString,p);
}
// Quoted strings and unquoted title
if(match[4]) { // Opening square bracket
p = parseFilterOperation(operation.operators,filterString,p);
} else {
p = match.index + match[0].length;
}
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
operation.operators.push(
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
@@ -232,12 +213,7 @@ exports.getFilterRunPrefixes = function() {
exports.filterTiddlers = function(filterString,widget,source) {
var fn = this.compileFilter(filterString);
try {
const fnResult = fn.call(this,source,widget);
return fnResult;
} catch(e) {
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
}
return fn.call(this,source,widget);
};
/*
@@ -275,8 +251,6 @@ exports.compileFilter = function(filterString) {
results = [];
$tw.utils.each(operation.operators,function(operator) {
var operands = [],
multiValueOperands = [],
isMultiValueOperand = [],
operatorFunction;
if(!operator.operator) {
// Use the "title" operator if no operator is specified
@@ -292,46 +266,28 @@ exports.compileFilter = function(filterString) {
if(operand.indirect) {
var currTiddlerTitle = widget && widget.getVariable("currentTiddler");
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
operand.multiValue = [operand.value];
} else if(operand.variable) {
var varTree = $tw.utils.parseFilterVariable(operand.text);
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
operand.multiValue = [operand.value];
} else if(operand.multiValuedVariable) {
var varTree = $tw.utils.parseFilterVariable(operand.text);
var resultList = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source});
if((resultList.length > 0 && resultList[0] !== undefined) || resultList.length === 0) {
operand.multiValue = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}) || [];
operand.value = operand.multiValue[0] || "";
} else {
operand.value = "";
operand.multiValue = [];
}
operand.isMultiValueOperand = true;
} else {
operand.value = operand.text;
operand.multiValue = [operand.value];
}
operands.push(operand.value);
multiValueOperands.push(operand.multiValue);
isMultiValueOperand.push(!!operand.isMultiValueOperand);
});
// Invoke the appropriate filteroperator module
results = operatorFunction(accumulator,{
operator: operator.operator,
operand: operands.length > 0 ? operands[0] : undefined,
operands: operands,
multiValueOperands: multiValueOperands,
isMultiValueOperand: isMultiValueOperand,
prefix: operator.prefix,
suffix: operator.suffix,
suffixes: operator.suffixes,
regexp: operator.regexp
},{
wiki: self,
widget: widget
});
operator: operator.operator,
operand: operands.length > 0 ? operands[0] : undefined,
operands: operands,
prefix: operator.prefix,
suffix: operator.suffix,
suffixes: operator.suffixes,
regexp: operator.regexp
},{
wiki: self,
widget: widget
});
if($tw.utils.isArray(results)) {
accumulator = self.makeTiddlerIterator(results);
} else {
@@ -363,8 +319,6 @@ exports.compileFilter = function(filterString) {
return filterRunPrefixes["and"](operationSubFunction, options);
case "~": // This operation is unioned into the result only if the main result so far is empty
return filterRunPrefixes["else"](operationSubFunction, options);
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
return filterRunPrefixes["let"](operationSubFunction, options);
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
@@ -391,13 +345,7 @@ exports.compileFilter = function(filterString) {
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
$tw.utils.each(operationFunctions,function(operationFunction) {
var operationResult = operationFunction(results,source,widget);
if(operationResult) {
if(operationResult.variables) {
// If the filter run prefix has returned variables, create a new fake widget with those variables
widget = widget.makeFakeWidgetWithVariables(operationResult.variables);
}
}
operationFunction(results,source,widget);
});
} else {
results.push("/**-- Excessive filter recursion --**/");

View File

@@ -16,8 +16,8 @@ exports.function = function(source,operator,options) {
var functionName = operator.operands[0],
params = [],
results;
$tw.utils.each(operator.multiValueOperands.slice(1),function(paramList) {
params.push({value: paramList[0] || "",multiValue: paramList});
$tw.utils.each(operator.operands.slice(1),function(param) {
params.push({value: param});
});
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});

View File

@@ -113,22 +113,6 @@ exports["jsonset"] = function(source,operator,options) {
return results;
};
exports["jsondelete"] = function(source,operator,options) {
var indexes = operator.operands,
results = [];
source(function(tiddler,title) {
var data = $tw.utils.parseJSONSafe(title,title);
// If parsing failed (data equals original title and is a string), return unchanged
if(data === title && typeof data === "string") {
results.push(title);
} else if(data) {
data = deleteDataItem(data,indexes);
results.push(JSON.stringify(data));
}
});
return results;
};
/*
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
*/
@@ -160,7 +144,7 @@ function convertDataItemValueToStrings(item) {
return ["null"]
} else if(typeof item === "object") {
var results = [],i,t;
if(Array.isArray(item)) {
if($tw.utils.isArray(item)) {
// Return all the items in arrays recursively
for(i=0; i<item.length; i++) {
t = convertDataItemValueToStrings(item[i])
@@ -194,7 +178,7 @@ function convertDataItemKeysToStrings(item) {
return [];
}
var results = [];
if(Array.isArray(item)) {
if($tw.utils.isArray(item)) {
for(var i=0; i<item.length; i++) {
results.push(i.toString());
}
@@ -217,7 +201,7 @@ function getDataItemType(data,indexes) {
return item;
} else if(item === null) {
return "null";
} else if(Array.isArray(item)) {
} else if($tw.utils.isArray(item)) {
return "array";
} else if(typeof item === "object") {
return "object";
@@ -229,7 +213,7 @@ function getDataItemType(data,indexes) {
function getItemAtIndex(item,index) {
if($tw.utils.hop(item,index)) {
return item[index];
} else if(Array.isArray(item)) {
} else if($tw.utils.isArray(item)) {
index = $tw.utils.parseInt(index);
if(index < 0) { index = index + item.length };
return item[index]; // Will be undefined if index was out-of-bounds
@@ -239,16 +223,15 @@ function getItemAtIndex(item,index) {
}
/*
Traverse the index chain and return the item at the specified depth.
Returns the item at the end of the traversal, or undefined if traversal fails.
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
*/
function traverseIndexChain(data,indexes,stopBeforeLast) {
function getDataItem(data,indexes) {
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
return data;
}
// Get the item
var item = data;
var stopIndex = stopBeforeLast ? indexes.length - 1 : indexes.length;
for(var i = 0; i < stopIndex; i++) {
for(var i=0; i<indexes.length; i++) {
if(item !== undefined) {
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
item = getItemAtIndex(item,indexes[i]);
@@ -260,13 +243,6 @@ function traverseIndexChain(data,indexes,stopBeforeLast) {
return item;
}
/*
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
*/
function getDataItem(data,indexes) {
return traverseIndexChain(data,indexes,false);
}
/*
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
*/
@@ -279,15 +255,18 @@ function setDataItem(data,indexes,value) {
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
return value;
}
// Traverse the JSON data structure using the index chain up to the parent
var current = traverseIndexChain(data,indexes,true);
if(current === undefined) {
// Return the original JSON data structure if any of the index strings are invalid
return data;
// Traverse the JSON data structure using the index chain
var current = data;
for(var i = 0; i < indexes.length - 1; i++) {
current = getItemAtIndex(current,indexes[i]);
if(current === undefined) {
// Return the original JSON data structure if any of the index strings are invalid
return data;
}
}
// Add the value to the end of the index chain
var lastIndex = indexes[indexes.length - 1];
if(Array.isArray(current)) {
if($tw.utils.isArray(current)) {
lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
}
@@ -297,32 +276,3 @@ function setDataItem(data,indexes,value) {
}
return data;
}
/*
Given a JSON data structure and an array of index strings, return the data structure with the item at the end of the index chain deleted. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then the JSON data structure is returned unmodified.
*/
function deleteDataItem(data,indexes) {
// Check for the root item - don't delete the root
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
return data;
}
// Traverse the JSON data structure using the index chain up to the parent
var current = traverseIndexChain(data,indexes,true);
if(current === undefined || current === null) {
// Return the original JSON data structure if any of the index strings are invalid
return data;
}
// Delete the item at the end of the index chain
var lastIndex = indexes[indexes.length - 1];
if(Array.isArray(current) && current !== null) {
lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
// Check if index is valid before splicing
if(lastIndex >= 0 && lastIndex < current.length) {
current.splice(lastIndex,1);
}
} else if(typeof current === "object" && current !== null) {
delete current[lastIndex];
}
return data;
}

View File

@@ -16,13 +16,12 @@ exports.title = function(source,operator,options) {
var results = [];
if(operator.prefix === "!") {
source(function(tiddler,title) {
var titleList = operator.multiValueOperands[0] || [];
if(tiddler && titleList.indexOf(tiddler.fields.title) === -1) {
if(tiddler && tiddler.fields.title !== operator.operand) {
results.push(title);
}
});
} else {
Array.prototype.push.apply(results,operator.multiValueOperands[0]);
results.push(operator.operand);
}
return results;
};

View File

@@ -20,8 +20,8 @@ exports["[unknown]"] = function(source,operator,options) {
// Check for a user defined filter operator
if(operator.operator.indexOf(".") !== -1) {
var params = [];
$tw.utils.each(operator.multiValueOperands,function(paramList) {
params.push({value: paramList[0] || "",multiValue: paramList});
$tw.utils.each(operator.operands,function(param) {
params.push({value: param});
});
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source});
if(variableInfo && variableInfo.srcVariable) {

View File

@@ -11,13 +11,10 @@ The CSV text parser processes CSV files into a table wrapped in a scrollable wid
var CsvParser = function(type,text,options) {
// Special handler for tab-delimited files
if(
!options.separator &&
(type === "text/tab-delimited-values" || type === "text/tab-separated-values")
) {
if (type === 'text/tab-delimited-values' && !options.separator) {
options.separator = "\t";
}
// Table framework
this.tree = [{
"type": "scrollable", "children": [{
@@ -35,7 +32,7 @@ var CsvParser = function(type,text,options) {
$tw.utils.each(lines, function(columns) {
maxColumns = Math.max(columns.length, maxColumns);
});
for(var line=0; line<lines.length; line++) {
var columns = lines[line];
var row = {
@@ -58,4 +55,3 @@ var CsvParser = function(type,text,options) {
exports["text/csv"] = CsvParser;
exports["text/tab-delimited-values"] = CsvParser;
exports["text/tab-separated-values"] = CsvParser;

View File

@@ -18,7 +18,6 @@ exports.synchronous = true;
// Default story and history lists
var PAGE_TITLE_TITLE = "$:/core/wiki/title";
var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet";
var ROOT_STYLESHEET_TITLE = "$:/core/ui/RootStylesheet";
var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate";
// Time (in ms) that we defer refreshing changes to draft tiddlers
@@ -45,13 +44,22 @@ exports.startup = function() {
publishTitle();
}
});
var styleParser = $tw.wiki.parseTiddler(ROOT_STYLESHEET_TITLE,{parseAsInline: true}),
styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: document});
styleWidgetNode.render(document.head,null);
// Set up the styles
$tw.styleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_STYLESHEET_TITLE,{document: $tw.fakeDocument});
$tw.styleContainer = $tw.fakeDocument.createElement("style");
$tw.styleWidgetNode.render($tw.styleContainer,null);
$tw.styleWidgetNode.assignedStyles = $tw.styleContainer.textContent;
$tw.styleElement = document.createElement("style");
$tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles;
document.head.insertBefore($tw.styleElement,document.head.firstChild);
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
styleWidgetNode.refresh(changes,document.head,null);
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) {
var newStyles = $tw.styleContainer.textContent;
if(newStyles !== $tw.styleWidgetNode.assignedStyles) {
$tw.styleWidgetNode.assignedStyles = newStyles;
$tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles;
}
}
}));
// Display the $:/core/ui/PageTemplate tiddler to kick off the display
$tw.perf.report("mainRender",function() {
@@ -60,7 +68,7 @@ exports.startup = function() {
$tw.utils.addClass($tw.pageContainer,"tc-page-container-wrapper");
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
$tw.pageWidgetNode.render($tw.pageContainer,null);
$tw.hooks.invokeHook("th-page-refreshed");
$tw.hooks.invokeHook("th-page-refreshed");
})();
// Remove any splash screen elements
var removeList = document.querySelectorAll(".tc-remove-when-wiki-loaded");

View File

@@ -63,16 +63,24 @@ exports.startup = function() {
$tw.eventBus.emit("window:closed",{windowID});
},false);
// Set up the styles
var styleParser = $tw.wiki.parseTiddler("$:/core/ui/RootStylesheet",{parseAsInline: true}),
styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: srcDocument});
styleWidgetNode.render(srcDocument.head,null);
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
document: $tw.fakeDocument,
variables: variables,
importPageMacros: true}),
styleContainer = $tw.fakeDocument.createElement("style");
styleWidgetNode.render(styleContainer,null);
var styleElement = srcDocument.createElement("style");
styleElement.innerHTML = styleContainer.textContent;
srcDocument.head.insertBefore(styleElement,srcDocument.head.firstChild);
// Render the text of the tiddler
var parser = $tw.wiki.parseTiddler(template),
widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, parentWidget: $tw.rootWidget, variables: variables});
widgetNode.render(srcDocument.body,srcDocument.body.firstChild);
// Function to handle refreshes
refreshHandler = function(changes) {
styleWidgetNode.refresh(changes);
if(styleWidgetNode.refresh(changes,styleContainer,null)) {
styleElement.innerHTML = styleContainer.textContent;
}
widgetNode.refresh(changes);
};
$tw.wiki.addEventListener("change",refreshHandler);

View File

@@ -1,58 +0,0 @@
/*\
title: $:/core/modules/utils/deprecated.js
type: application/javascript
module-type: utils
Deprecated util functions
\*/
exports.logTable = data => console.table(data);
exports.repeat = (str,count) => str.repeat(count);
exports.startsWith = (str,search) => str.startsWith(search);
exports.endsWith = (str,search) => str.endsWith(search);
exports.trim = function(str) {
if(typeof str === "string") {
return str.trim();
} else {
return str;
}
};
exports.hopArray = (object,array) => array.some(element => $tw.utils.hop(object,element));
exports.sign = Math.sign;
exports.strEndsWith = (str,ending,position) => str.endsWith(ending,position);
exports.stringifyNumber = num => num.toString();
exports.tagToCssSelector = function(tagName) {
return "tc-tagged-" + encodeURIComponent(tagName).replace(/[!"#$%&'()*+,\-./:;<=>?@[\\\]^`{\|}~,]/mg,function(c) {
return "\\" + c;
});
};
exports.domContains = (a,b) => a.compareDocumentPosition(b) & 16;
exports.domMatchesSelector = (node,selector) => node.matches(selector);
exports.hasClass = (el,className) => el.classList && el.classList.contains(className);
exports.addClass = function(el,className) {
el.classList && el.classList.add(className);
};
exports.removeClass = function(el,className) {
el.classList && el.classList.remove(className);
};
exports.toggleClass = function(el,className,status) {
el.classList && el.classList.toggle(className, status);
};
exports.getLocationPath = () => window.location.origin + window.location.pathname;

View File

@@ -61,7 +61,7 @@ exports.convertStyleNameToPropertyName = function(styleName) {
var propertyName = $tw.utils.unHyphenateCss(styleName);
// Then check if it needs a prefix
if($tw.browser && document.body.style[propertyName] === undefined) {
var prefixes = ["Moz","webkit"];
var prefixes = ["O","MS","Moz","webkit"];
for(var t=0; t<prefixes.length; t++) {
var prefixedName = prefixes[t] + propertyName.substr(0,1).toUpperCase() + propertyName.substr(1);
if(document.body.style[prefixedName] !== undefined) {
@@ -112,6 +112,8 @@ var eventNameMappings = {
correspondingCssProperty: "transition",
mappings: {
transition: "transitionend",
OTransition: "oTransitionEnd",
MSTransition: "msTransitionEnd",
MozTransition: "transitionend",
webkitTransition: "webkitTransitionEnd"
}
@@ -120,6 +122,8 @@ var eventNameMappings = {
correspondingCssProperty: "animation",
mappings: {
animation: "animationend",
OAnimation: "oAnimationEnd",
MSAnimation: "msAnimationEnd",
MozAnimation: "animationend",
webkitAnimation: "webkitAnimationEnd"
}
@@ -152,15 +156,19 @@ exports.getFullScreenApis = function() {
result = {
"_requestFullscreen": db.webkitRequestFullscreen !== undefined ? "webkitRequestFullscreen" :
db.mozRequestFullScreen !== undefined ? "mozRequestFullScreen" :
db.msRequestFullscreen !== undefined ? "msRequestFullscreen" :
db.requestFullscreen !== undefined ? "requestFullscreen" : "",
"_exitFullscreen": d.webkitExitFullscreen !== undefined ? "webkitExitFullscreen" :
d.mozCancelFullScreen !== undefined ? "mozCancelFullScreen" :
d.msExitFullscreen !== undefined ? "msExitFullscreen" :
d.exitFullscreen !== undefined ? "exitFullscreen" : "",
"_fullscreenElement": d.webkitFullscreenElement !== undefined ? "webkitFullscreenElement" :
d.mozFullScreenElement !== undefined ? "mozFullScreenElement" :
d.msFullscreenElement !== undefined ? "msFullscreenElement" :
d.fullscreenElement !== undefined ? "fullscreenElement" : "",
"_fullscreenChange": d.webkitFullscreenElement !== undefined ? "webkitfullscreenchange" :
d.mozFullScreenElement !== undefined ? "mozfullscreenchange" :
d.msFullscreenElement !== undefined ? "MSFullscreenChange" :
d.fullscreenElement !== undefined ? "fullscreenchange" : ""
};
if(!result._requestFullscreen || !result._exitFullscreen || !result._fullscreenElement || !result._fullscreenChange) {

View File

@@ -11,6 +11,19 @@ Various static DOM-related utility functions.
var Popup = require("$:/core/modules/utils/dom/popup.js");
/*
Determines whether element 'a' contains element 'b'
Code thanks to John Resig, http://ejohn.org/blog/comparing-document-position/
*/
exports.domContains = function(a,b) {
return a.contains ?
a !== b && a.contains(b) :
!!(a.compareDocumentPosition(b) & 16);
};
exports.domMatchesSelector = function(node,selector) {
return node.matches ? node.matches(selector) : node.msMatchesSelector(selector);
};
/*
Select text in a an input or textarea (setSelectionRange crashes on certain input types)
@@ -36,6 +49,38 @@ exports.removeChildren = function(node) {
}
};
exports.hasClass = function(el,className) {
return el && el.hasAttribute && el.hasAttribute("class") && el.getAttribute("class").split(" ").indexOf(className) !== -1;
};
exports.addClass = function(el,className) {
var c = (el.getAttribute("class") || "").split(" ");
if(c.indexOf(className) === -1) {
c.push(className);
el.setAttribute("class",c.join(" "));
}
};
exports.removeClass = function(el,className) {
var c = (el.getAttribute("class") || "").split(" "),
p = c.indexOf(className);
if(p !== -1) {
c.splice(p,1);
el.setAttribute("class",c.join(" "));
}
};
exports.toggleClass = function(el,className,status) {
if(status === undefined) {
status = !exports.hasClass(el,className);
}
if(status) {
exports.addClass(el,className);
} else {
exports.removeClass(el,className);
}
};
/*
Get the first parent element that has scrollbars or use the body as fallback.
*/
@@ -252,6 +297,10 @@ exports.copyToClipboard = function(text,options) {
document.body.removeChild(textArea);
};
exports.getLocationPath = function() {
return window.location.toString().split("#")[0];
};
/*
Collect DOM variables
*/

View File

@@ -60,7 +60,7 @@ exports.repackPlugin = function(title,additionalTiddlers,excludeTiddlers) {
version += "+" + pluginVersion.build;
}
// Save the tiddler
$tw.wiki.addTiddler(new $tw.Tiddler(pluginTiddler,{text: JSON.stringify({tiddlers: plugins},null,4), version: version},$tw.wiki.getModificationFields()));
$tw.wiki.addTiddler(new $tw.Tiddler(pluginTiddler,{text: JSON.stringify({tiddlers: plugins},null,4), version: version}));
// Delete any non-shadow constituent tiddlers
$tw.utils.each(tiddlers,function(title) {
if($tw.wiki.tiddlerExists(title)) {

View File

@@ -48,6 +48,19 @@ exports.warning = function(text) {
exports.log(text,"brown/orange");
};
/*
Log a table of name: value pairs
*/
exports.logTable = function(data) {
if(console.table) {
console.table(data);
} else {
$tw.utils.each(data,function(value,name) {
console.log(name + ": " + value);
});
}
}
/*
Return the integer represented by the str (string).
Return the dflt (default) parameter if str is not a base-10 number.
@@ -66,6 +79,43 @@ exports.replaceString = function(text,search,replace) {
});
};
/*
Repeats a string
*/
exports.repeat = function(str,count) {
var result = "";
for(var t=0;t<count;t++) {
result += str;
}
return result;
};
/*
Check if a string starts with another string
*/
exports.startsWith = function(str,search) {
return str.substring(0, search.length) === search;
};
/*
Check if a string ends with another string
*/
exports.endsWith = function(str,search) {
return str.substring(str.length - search.length) === search;
};
/*
Trim whitespace from the start and end of a string
Thanks to Steven Levithan, http://blog.stevenlevithan.com/archives/faster-trim-javascript
*/
exports.trim = function(str) {
if(typeof str === "string") {
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
} else {
return str;
}
};
exports.trimPrefix = function(str,unwanted) {
if(typeof str === "string" && typeof unwanted === "string") {
if(unwanted === "") {
@@ -150,6 +200,18 @@ exports.count = function(object) {
return Object.keys(object || {}).length;
};
/*
Determine whether an array-item is an object-property
*/
exports.hopArray = function(object,array) {
for(var i=0; i<array.length; i++) {
if($tw.utils.hop(object,array[i])) {
return true;
}
}
return false;
};
/*
Remove entries from an array
array: array to modify
@@ -878,6 +940,44 @@ exports.makeDataUri = function(text,type,_canonical_uri) {
return parts.join("");
};
/*
Useful for finding out the fully escaped CSS selector equivalent to a given tag. For example:
$tw.utils.tagToCssSelector("$:/tags/Stylesheet") --> tc-tagged-\%24\%3A\%2Ftags\%2FStylesheet
*/
exports.tagToCssSelector = function(tagName) {
return "tc-tagged-" + encodeURIComponent(tagName).replace(/[!"#$%&'()*+,\-./:;<=>?@[\\\]^`{\|}~,]/mg,function(c) {
return "\\" + c;
});
};
/*
IE does not have sign function
*/
exports.sign = Math.sign || function(x) {
x = +x; // convert to a number
if(x === 0 || isNaN(x)) {
return x;
}
return x > 0 ? 1 : -1;
};
/*
IE does not have an endsWith function
*/
exports.strEndsWith = function(str,ending,position) {
if(str.endsWith) {
return str.endsWith(ending,position);
} else {
if(typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > str.length) {
position = str.length;
}
position -= ending.length;
var lastIndex = str.indexOf(ending, position);
return lastIndex !== -1 && lastIndex === position;
}
};
/*
Return system information useful for debugging
*/
@@ -904,6 +1004,10 @@ exports.parseInt = function(str) {
return parseInt(str,10) || 0;
};
exports.stringifyNumber = function(num) {
return num + "";
};
exports.makeCompareFunction = function(type,options) {
options = options || {};
// set isCaseSensitive to true if not defined in options

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-unused-vars */
/*\
title: $:/core/modules/widgets/action-log.js
type: application/javascript
@@ -33,7 +32,7 @@ LogWidget.prototype.execute = function(){
this.message = this.getAttribute("$$message","debug");
this.logAll = this.getAttribute("$$all","no") === "yes" ? true : false;
this.filter = this.getAttribute("$$filter");
};
}
/*
Refresh the widget by ensuring our attributes are up to date
@@ -52,30 +51,23 @@ LogWidget.prototype.invokeAction = function(triggeringWidget,event) {
};
LogWidget.prototype.log = function() {
var self = this,
data = {}, // Hashmap by attribute name with string or array of string values
var data = {},
dataCount,
allVars = {}, // Hashmap by variable name with string or array of string values
allVars = {},
filteredVars;
// Collect the attributes to be logged
$tw.utils.each(this.parseTreeNode.attributes,function(attribute,name) {
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.substring(0,2) !== "$$") {
var resultList = self.computeAttribute(attribute,{asList: true});
if(resultList.length <= 1) {
data[name] = resultList[0] || "";
} else {
data[name] = resultList;
}
data[name] = attribute;
}
});
// Collect values of all variables, using the source text for functions
for(var v in this.variables) {
var variable = this.parentWidget && this.parentWidget.variables[v];
if(variable && variable.isFunctionDefinition) {
allVars[v] = variable.value;
} else {
var variableInfo = this.getVariableInfo(v);
allVars[v] = variableInfo.resultList.length > 1 ? variableInfo.resultList : variableInfo.text;
allVars[v] = this.getVariable(v,{defaultValue:""});
}
}
if(this.filter) {
@@ -96,6 +88,6 @@ LogWidget.prototype.log = function() {
console.groupEnd();
}
console.groupEnd();
};
}
exports["action-log"] = LogWidget;

View File

@@ -34,10 +34,9 @@ DiffTextWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create the diff object
var dmpObject = new dmp.diff_match_patch();
dmpObject.Diff_EditCost = $tw.utils.parseNumber(this.getAttribute("editcost","4"));
var diffs = dmpObject.diff_main(this.getAttribute("source",""),this.getAttribute("dest",""));
// Create the diff
var dmpObject = new dmp.diff_match_patch(),
diffs = dmpObject.diff_main(this.getAttribute("source",""),this.getAttribute("dest",""));
// Apply required cleanup
switch(this.getAttribute("cleanup","semantic")) {
case "none":
@@ -133,7 +132,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
DiffTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.editcost) {
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup) {
this.refreshSelf();
return true;
} else {

View File

@@ -177,7 +177,7 @@ DroppableWidget.prototype.execute = function() {
DroppableWidget.prototype.assignDomNodeClasses = function() {
var classes = this.getAttribute("class","").split(" ");
classes.push("tc-droppable");
this.domNode.className = classes.join(" ").trim();
this.domNode.className = classes.join(" ");
};
/*

View File

@@ -130,7 +130,7 @@ EventWidget.prototype.execute = function() {
EventWidget.prototype.assignDomNodeClasses = function() {
var classes = this.getAttribute("class","").split(" ");
classes.push("tc-eventcatcher");
this.domNode.className = classes.join(" ").trim();
this.domNode.className = classes.join(" ");
};
/*

View File

@@ -110,7 +110,7 @@ KeyboardWidget.prototype.execute = function() {
KeyboardWidget.prototype.assignDomNodeClasses = function() {
var classes = this.getAttribute("class","").split(" ");
classes.push("tc-keyboard");
this.domNode.className = classes.join(" ").trim();
this.domNode.className = classes.join(" ");
};
/*

View File

@@ -46,7 +46,7 @@ LetWidget.prototype.computeAttributes = function() {
self = this;
this.currentValueFor = Object.create(null);
$tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(this.parseTreeNode),function(attribute) {
var value = self.computeAttribute(attribute,{asList: true}),
var value = self.computeAttribute(attribute),
name = attribute.name;
// Now that it's prepped, we're allowed to look this variable up
// when defining later variables
@@ -56,7 +56,7 @@ LetWidget.prototype.computeAttributes = function() {
});
// Run through again, setting variables and looking for differences
$tw.utils.each(this.currentValueFor,function(value,name) {
if(!$tw.utils.isArrayEqual(self.attributes[name],value)) {
if (self.attributes[name] !== value) {
self.attributes[name] = value;
self.setVariable(name,value);
changedAttributes[name] = true;
@@ -69,10 +69,8 @@ LetWidget.prototype.getVariableInfo = function(name,options) {
// Special handling: If this variable exists in this very $let, we can
// use it, but only if it's been staged.
if ($tw.utils.hop(this.currentValueFor,name)) {
var value = this.currentValueFor[name];
return {
text: value[0] || "",
resultList: value
text: this.currentValueFor[name]
};
}
return Widget.prototype.getVariableInfo.call(this,name,options);

View File

@@ -89,33 +89,13 @@ RevealWidget.prototype.positionPopup = function(domNode) {
top = this.popup.top + this.popup.height;
break;
}
// if requested, clamp the popup so that it will always be fully inside its parent (the first upstream element with position:relative), as long as the popup is smaller than its parent
// if position is absolute then clamping is done to the canvas boundary, since there is no "parent"
if(this.clampToParent !== "none") {
if(this.popup.absolute) {
var parentWidth = window.innerWidth,
parentHeight = window.innerHeight;
} else {
var parentWidth = domNode.offsetParent.offsetWidth,
parentHeight = domNode.offsetParent.offsetHeight;
}
var right = left + domNode.offsetWidth,
bottom = top + domNode.offsetHeight;
if((this.clampToParent === "both" || this.clampToParent === "right") && right > parentWidth) {
left = parentWidth - domNode.offsetWidth;
}
if((this.clampToParent === "both" || this.clampToParent === "bottom") && bottom > parentHeight) {
top = parentHeight - domNode.offsetHeight;
}
// clamping on left and top sides is taken care of by positionAllowNegative
}
if(!this.positionAllowNegative) {
left = Math.max(0,left);
top = Math.max(0,top);
}
if(this.popup.absolute) {
if (this.popup.absolute) {
// Traverse the offsetParent chain and correct the offset to make it relative to the parent node.
for(var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
for (var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
left -= offsetParentDomNode.offsetLeft;
top -= offsetParentDomNode.offsetTop;
}
@@ -143,7 +123,6 @@ RevealWidget.prototype.execute = function() {
this.openAnimation = this.animate === "no" ? undefined : "open";
this.closeAnimation = this.animate === "no" ? undefined : "close";
this.updatePopupPosition = this.getAttribute("updatePopupPosition","no") === "yes";
this.clampToParent = this.getAttribute("clamp","none");
// Compute the title of the state tiddler and read it
this.stateTiddlerTitle = this.state;
this.stateTitle = this.getAttribute("stateTitle");
@@ -162,7 +141,7 @@ Read the state tiddler
RevealWidget.prototype.readState = function() {
// Read the information from the state tiddler
var state,
defaultState = this["default"];
defaultState = this["default"];
if(this.stateTitle) {
var stateTitleTiddler = this.wiki.getTiddler(this.stateTitle);
if(this.stateField) {
@@ -224,7 +203,7 @@ RevealWidget.prototype.readPopupState = function(state) {
RevealWidget.prototype.assignDomNodeClasses = function() {
var classes = this.getAttribute("class","").split(" ");
classes.push("tc-reveal");
this.domNode.className = classes.join(" ").trim();
this.domNode.className = classes.join(" ");
};
/*
@@ -273,18 +252,18 @@ RevealWidget.prototype.updateState = function() {
this.renderChildren(domNode,null);
}
// Animate our DOM node
if(!domNode.isTiddlyWikiFakeDom && this.type === "popup" && this.isOpen) {
this.positionPopup(domNode);
$tw.utils.addClass(domNode,"tc-popup"); // Make sure that clicks don't dismiss popups within the revealed content
}
if(this.isOpen) {
domNode.removeAttribute("hidden");
// Position popup after making it visible to ensure correct dimensions
if(!domNode.isTiddlyWikiFakeDom && this.type === "popup") {
this.positionPopup(domNode);
$tw.utils.addClass(domNode,"tc-popup"); // Make sure that clicks don't dismiss popups within the revealed content
}
$tw.anim.perform(this.openAnimation,domNode);
$tw.anim.perform(this.openAnimation,domNode);
} else {
$tw.anim.perform(this.closeAnimation,domNode,{callback: function() {
//make sure that the state hasn't changed during the close animation
self.readState();
self.readState()
if(!self.isOpen) {
domNode.setAttribute("hidden","true");
}

View File

@@ -9,376 +9,215 @@ View widget
"use strict";
const Widget = require("$:/core/modules/widgets/widget.js").widget;
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var ViewWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
==========================================
ViewHandler Base Class
==========================================
Base class for all view format handlers.
Provides common functionality and defines the interface for subclasses.
Inherit from the base widget class
*/
class ViewHandler {
constructor(widget) {
this.widget = widget;
this.wiki = widget.wiki;
this.document = widget.document;
this.viewTitle = widget.viewTitle;
this.viewField = widget.viewField;
this.viewIndex = widget.viewIndex;
this.viewSubtiddler = widget.viewSubtiddler;
this.viewTemplate = widget.viewTemplate;
this.viewMode = widget.viewMode;
}
render(parent, nextSibling) {
this.text = this.getValue();
this.createTextNode(parent, nextSibling);
}
getValue() {
return this.widget.getValueAsText();
}
createTextNode(parent, nextSibling) {
if(this.text) {
const textNode = this.document.createTextNode(this.text);
parent.insertBefore(textNode, nextSibling);
this.widget.domNodes.push(textNode);
} else {
this.widget.makeChildWidgets();
this.widget.renderChildren(parent, nextSibling);
}
}
refresh() {
var self = this;
return false;
}
}
ViewWidget.prototype = new Widget();
/*
==========================================
Wikified View Handler Base
==========================================
Base class for wikified view handlers
Render this widget into the DOM
*/
class WikifiedViewHandler extends ViewHandler {
constructor(widget) {
super(widget);
this.fakeWidget = null;
this.fakeNode = null;
}
render(parent, nextSibling) {
this.createFakeWidget();
this.text = this.getValue();
this.createWikifiedTextNode(parent, nextSibling);
}
createFakeWidget() {
this.fakeWidget = this.wiki.makeTranscludeWidget(this.viewTitle, {
document: $tw.fakeDocument,
field: this.viewField,
index: this.viewIndex,
parseAsInline: this.viewMode !== "block",
mode: this.viewMode === "block" ? "block" : "inline",
parentWidget: this.widget,
subTiddler: this.viewSubtiddler
});
this.fakeNode = $tw.fakeDocument.createElement("div");
this.fakeWidget.makeChildWidgets();
this.fakeWidget.render(this.fakeNode, null);
}
createWikifiedTextNode(parent, nextSibling) {
const textNode = this.document.createTextNode(this.text || "");
parent.insertBefore(textNode, nextSibling);
this.widget.domNodes.push(textNode);
}
refresh(changedTiddlers) {
const refreshed = this.fakeWidget.refresh(changedTiddlers);
if(refreshed) {
const newText = this.getValue();
if(newText !== this.text) {
this.widget.domNodes[0].textContent = newText;
this.text = newText;
}
}
return refreshed;
}
}
/*
==========================================
Text View Handler
==========================================
Default handler for plain text display
*/
class TextViewHandler extends ViewHandler {}
/*
==========================================
HTML Wikified View Handler
==========================================
Handler for wikified HTML content
*/
class HTMLWikifiedViewHandler extends WikifiedViewHandler {
getValue() {
return this.fakeNode.innerHTML;
}
}
/*
==========================================
Plain Wikified View Handler
==========================================
Handler for wikified plain text content
*/
class PlainWikifiedViewHandler extends WikifiedViewHandler {
getValue() {
return this.fakeNode.textContent;
}
}
/*
==========================================
HTML Encoded Plain Wikified View Handler
==========================================
Handler for HTML-encoded wikified plain text
*/
class HTMLEncodedPlainWikifiedViewHandler extends WikifiedViewHandler {
getValue() {
return $tw.utils.htmlEncode(this.fakeNode.textContent);
}
}
/*
==========================================
HTML Encoded View Handler
==========================================
Handler for HTML-encoded text
*/
class HTMLEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.htmlEncode(this.widget.getValueAsText());
}
}
/*
==========================================
HTML Text Encoded View Handler
==========================================
Handler for HTML text-encoded content
*/
class HTMLTextEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.htmlTextEncode(this.widget.getValueAsText());
}
}
/*
==========================================
URL Encoded View Handler
==========================================
Handler for URL-encoded text
*/
class URLEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.encodeURIComponentExtended(this.widget.getValueAsText());
}
}
/*
==========================================
Double URL Encoded View Handler
==========================================
Handler for double URL-encoded text
*/
class DoubleURLEncodedViewHandler extends ViewHandler {
getValue() {
const text = this.widget.getValueAsText();
return $tw.utils.encodeURIComponentExtended($tw.utils.encodeURIComponentExtended(text));
}
}
/*
==========================================
Date View Handler
==========================================
Handler for date formatting
*/
class DateViewHandler extends ViewHandler {
getValue() {
const format = this.viewTemplate || "YYYY MM DD 0hh:0mm";
const rawValue = this.widget.getValueAsText();
const value = $tw.utils.parseDate(rawValue);
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.formatDateString(value, format);
} else {
return "";
}
}
}
/*
==========================================
Relative Date View Handler
==========================================
Handler for relative date display
*/
class RelativeDateViewHandler extends ViewHandler {
getValue() {
const rawValue = this.widget.getValueAsText();
const value = $tw.utils.parseDate(rawValue);
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.getRelativeDate((new Date()) - (new Date(value))).description;
} else {
return "";
}
}
}
/*
==========================================
Strip Comments View Handler
==========================================
Handler for stripping comments from text
*/
class StripCommentsViewHandler extends ViewHandler {
getValue() {
const lines = this.widget.getValueAsText().split("\n");
const out = [];
for(const text of lines) {
if(!/^\s*\/\/#/.test(text)) {
out.push(text);
}
}
return out.join("\n");
}
}
/*
==========================================
JS Encoded View Handler
==========================================
Handler for JavaScript string encoding
*/
class JSEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.stringify(this.widget.getValueAsText());
}
}
/*
==========================================
ViewHandlerFactory
==========================================
Factory for creating appropriate view handlers based on format
*/
const ViewHandlerFactory = {
handlers: {
"text": TextViewHandler,
"htmlwikified": HTMLWikifiedViewHandler,
"plainwikified": PlainWikifiedViewHandler,
"htmlencodedplainwikified": HTMLEncodedPlainWikifiedViewHandler,
"htmlencoded": HTMLEncodedViewHandler,
"htmltextencoded": HTMLTextEncodedViewHandler,
"urlencoded": URLEncodedViewHandler,
"doubleurlencoded": DoubleURLEncodedViewHandler,
"date": DateViewHandler,
"relativedate": RelativeDateViewHandler,
"stripcomments": StripCommentsViewHandler,
"jsencoded": JSEncodedViewHandler
},
createHandler(format, widget) {
const HandlerClass = this.handlers[format] || this.handlers["text"];
return new HandlerClass(widget);
},
registerHandler(format, handlerClass) {
this.handlers[format] = handlerClass;
ViewWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
if(this.text) {
var textNode = this.document.createTextNode(this.text);
parent.insertBefore(textNode,nextSibling);
this.domNodes.push(textNode);
} else {
this.makeChildWidgets();
this.renderChildren(parent,nextSibling);
}
};
/*
==========================================
ViewWidget
==========================================
Main widget class that orchestrates view handlers
Compute the internal state of the widget
*/
class ViewWidget extends Widget {
constructor(parseTreeNode, options) {
super();
this.initialise(parseTreeNode, options);
ViewWidget.prototype.execute = function() {
// Get parameters from our attributes
this.viewTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.viewSubtiddler = this.getAttribute("subtiddler");
this.viewField = this.getAttribute("field","text");
this.viewIndex = this.getAttribute("index");
this.viewFormat = this.getAttribute("format","text");
this.viewTemplate = this.getAttribute("template","");
this.viewMode = this.getAttribute("mode","block");
switch(this.viewFormat) {
case "htmlwikified":
this.text = this.getValueAsHtmlWikified(this.viewMode);
break;
case "plainwikified":
this.text = this.getValueAsPlainWikified(this.viewMode);
break;
case "htmlencodedplainwikified":
this.text = this.getValueAsHtmlEncodedPlainWikified(this.viewMode);
break;
case "htmlencoded":
this.text = this.getValueAsHtmlEncoded();
break;
case "htmltextencoded":
this.text = this.getValueAsHtmlTextEncoded();
break;
case "urlencoded":
this.text = this.getValueAsUrlEncoded();
break;
case "doubleurlencoded":
this.text = this.getValueAsDoubleUrlEncoded();
break;
case "date":
this.text = this.getValueAsDate(this.viewTemplate);
break;
case "relativedate":
this.text = this.getValueAsRelativeDate();
break;
case "stripcomments":
this.text = this.getValueAsStrippedComments();
break;
case "jsencoded":
this.text = this.getValueAsJsEncoded();
break;
default: // "text"
this.text = this.getValueAsText();
break;
}
};
render(parent, nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.viewHandler = ViewHandlerFactory.createHandler(this.viewFormat, this);
this.viewHandler.render(parent, nextSibling);
}
/*
The various formatter functions are baked into this widget for the moment. Eventually they will be replaced by macro functions
*/
execute() {
this.viewTitle = this.getAttribute("tiddler", this.getVariable("currentTiddler"));
this.viewSubtiddler = this.getAttribute("subtiddler");
this.viewField = this.getAttribute("field", "text");
this.viewIndex = this.getAttribute("index");
this.viewFormat = this.getAttribute("format", "text");
this.viewTemplate = this.getAttribute("template", "");
this.viewMode = this.getAttribute("mode", "block");
}
getValue(options = {}) {
let value = options.asString ? "" : undefined;
if(this.viewIndex) {
value = this.wiki.extractTiddlerDataItem(this.viewTitle, this.viewIndex);
/*
Retrieve the value of the widget. Options are:
asString: Optionally return the value as a string
*/
ViewWidget.prototype.getValue = function(options) {
options = options || {};
var value = options.asString ? "" : undefined;
if(this.viewIndex) {
value = this.wiki.extractTiddlerDataItem(this.viewTitle,this.viewIndex);
} else {
var tiddler;
if(this.viewSubtiddler) {
tiddler = this.wiki.getSubTiddler(this.viewTitle,this.viewSubtiddler);
} else {
let tiddler;
if(this.viewSubtiddler) {
tiddler = this.wiki.getSubTiddler(this.viewTitle, this.viewSubtiddler);
tiddler = this.wiki.getTiddler(this.viewTitle);
}
if(tiddler) {
if(this.viewField === "text" && !this.viewSubtiddler) {
// Calling getTiddlerText() triggers lazy loading of skinny tiddlers
value = this.wiki.getTiddlerText(this.viewTitle);
} else {
tiddler = this.wiki.getTiddler(this.viewTitle);
}
if(tiddler) {
if(this.viewField === "text" && !this.viewSubtiddler) {
value = this.wiki.getTiddlerText(this.viewTitle);
} else {
if($tw.utils.hop(tiddler.fields, this.viewField)) {
if(options.asString) {
value = tiddler.getFieldString(this.viewField);
} else {
value = tiddler.fields[this.viewField];
}
if($tw.utils.hop(tiddler.fields,this.viewField)) {
if(options.asString) {
value = tiddler.getFieldString(this.viewField);
} else {
value = tiddler.fields[this.viewField];
}
}
} else {
if(this.viewField === "title") {
value = this.viewTitle;
}
}
} else {
if(this.viewField === "title") {
value = this.viewTitle;
}
}
return value;
}
return value;
};
getValueAsText() {
return this.getValue({asString: true});
ViewWidget.prototype.getValueAsText = function() {
return this.getValue({asString: true});
};
ViewWidget.prototype.getValueAsHtmlWikified = function(mode) {
return this.wiki.renderText("text/html","text/vnd.tiddlywiki",this.getValueAsText(),{
parseAsInline: mode !== "block",
parentWidget: this
});
};
ViewWidget.prototype.getValueAsPlainWikified = function(mode) {
return this.wiki.renderText("text/plain","text/vnd.tiddlywiki",this.getValueAsText(),{
parseAsInline: mode !== "block",
parentWidget: this
});
};
ViewWidget.prototype.getValueAsHtmlEncodedPlainWikified = function(mode) {
return $tw.utils.htmlEncode(this.wiki.renderText("text/plain","text/vnd.tiddlywiki",this.getValueAsText(),{
parseAsInline: mode !== "block",
parentWidget: this
}));
};
ViewWidget.prototype.getValueAsHtmlEncoded = function() {
return $tw.utils.htmlEncode(this.getValueAsText());
};
ViewWidget.prototype.getValueAsHtmlTextEncoded = function() {
return $tw.utils.htmlTextEncode(this.getValueAsText());
};
ViewWidget.prototype.getValueAsUrlEncoded = function() {
return $tw.utils.encodeURIComponentExtended(this.getValueAsText());
};
ViewWidget.prototype.getValueAsDoubleUrlEncoded = function() {
return $tw.utils.encodeURIComponentExtended($tw.utils.encodeURIComponentExtended(this.getValueAsText()));
};
ViewWidget.prototype.getValueAsDate = function(format) {
format = format || "YYYY MM DD 0hh:0mm";
var value = $tw.utils.parseDate(this.getValue());
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.formatDateString(value,format);
} else {
return "";
}
};
refresh(changedTiddlers) {
const changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index ||
changedAttributes.template || changedAttributes.format || changedTiddlers[this.viewTitle]) {
this.refreshSelf();
return true;
} else {
return this.viewHandler.refresh(changedTiddlers);
ViewWidget.prototype.getValueAsRelativeDate = function(format) {
var value = $tw.utils.parseDate(this.getValue());
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.getRelativeDate((new Date()) - (new Date(value))).description;
} else {
return "";
}
};
ViewWidget.prototype.getValueAsStrippedComments = function() {
var lines = this.getValueAsText().split("\n"),
out = [];
for(var line=0; line<lines.length; line++) {
var text = lines[line];
if(!/^\s*\/\/#/.test(text)) {
out.push(text);
}
}
}
return out.join("\n");
};
exports.view = ViewWidget;
ViewWidget.prototype.getValueAsJsEncoded = function() {
return $tw.utils.stringify(this.getValueAsText());
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ViewWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.template || changedAttributes.format || changedTiddlers[this.viewTitle]) {
this.refreshSelf();
return true;
} else {
return false;
}
};
exports.view = ViewWidget;

View File

@@ -80,7 +80,7 @@ Widget.prototype.execute = function() {
/*
Set the value of a context variable
name: name of the variable
value: value of the variable, can be a string or an array
value: value of the variable
params: array of {name:, default:} for each parameter
isMacroDefinition: true if the variable is set via a \define macro pragma (and hence should have variable substitution performed)
options includes:
@@ -90,10 +90,8 @@ options includes:
*/
Widget.prototype.setVariable = function(name,value,params,isMacroDefinition,options) {
options = options || {};
var valueIsArray = $tw.utils.isArray(value);
this.variables[name] = {
value: valueIsArray ? (value[0] || "") : value,
resultList: valueIsArray ? value : [value],
value: value,
params: params,
isMacroDefinition: !!isMacroDefinition,
isFunctionDefinition: !!options.isFunctionDefinition,
@@ -116,7 +114,7 @@ allowSelfAssigned: if true, includes the current widget in the context chain ins
Returns an object with the following fields:
params: array of {name:,value:,multiValue:} of parameters to be applied (name is optional)
params: array of {name:,value:} or {value:} of parameters to be applied
text: text of variable, with parameters properly substituted
resultList: result of variable evaluation as an array
srcVariable: reference to the object defining the variable
@@ -142,9 +140,7 @@ Widget.prototype.getVariableInfo = function(name,options) {
params = self.resolveVariableParameters(variable.params,actualParams);
// Substitute any parameters specified in the definition
$tw.utils.each(params,function(param) {
if("name" in param) {
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
}
value = $tw.utils.replaceString(value,new RegExp("\\$" + $tw.utils.escapeRegExp(param.name) + "\\$","mg"),param.value);
});
value = self.substituteVariableReferences(value,options);
resultList = [value];
@@ -158,20 +154,13 @@ Widget.prototype.getVariableInfo = function(name,options) {
variables[param.name] = param["default"];
}
});
// Parameters are an array of {name:, value:, multivalue:} pairs (name and multivalue are optional)
// Parameters are an array of {value:} or {name:, value:} pairs
$tw.utils.each(params,function(param) {
if(param.multiValue) {
variables[param.name] = param.multiValue;
} else {
variables[param.name] = param.value || "";
}
variables[param.name] = param.value;
});
resultList = this.wiki.filterTiddlers(value,this.makeFakeWidgetWithVariables(variables),options.source);
value = resultList[0] || "";
} else {
if(variable.resultList) {
resultList = variable.resultList;
}
params = variable.params;
}
return {
@@ -203,24 +192,22 @@ Widget.prototype.getVariable = function(name,options) {
/*
Maps actual parameters onto formal parameters, returning an array of {name:,value:} objects
formalParams - Array of {name:,default:} (default value is optional)
actualParams - Array of string values or {name:,value:,multiValue} (name and multiValue is optional)
actualParams - Array of string values or {name:,value:} (name is optional)
*/
Widget.prototype.resolveVariableParameters = function(formalParams,actualParams) {
formalParams = formalParams || [];
actualParams = actualParams || [];
var nextAnonParameter = 0, // Next candidate anonymous parameter in macro call
paramInfo, paramValue, paramMultiValue,
paramInfo, paramValue,
results = [];
// Step through each of the parameters in the macro definition
for(var p=0; p<formalParams.length; p++) {
// Check if we've got a macro call parameter with the same name
paramInfo = formalParams[p];
paramValue = undefined;
paramMultiValue = undefined;
for(var m=0; m<actualParams.length; m++) {
if(typeof actualParams[m] !== "string" && actualParams[m].name === paramInfo.name) {
paramValue = actualParams[m].value;
paramMultiValue = actualParams[m].multiValue || [paramValue]
}
}
// If not, use the next available anonymous macro call parameter
@@ -230,13 +217,11 @@ Widget.prototype.resolveVariableParameters = function(formalParams,actualParams)
if(paramValue === undefined && nextAnonParameter < actualParams.length) {
var param = actualParams[nextAnonParameter++];
paramValue = typeof param === "string" ? param : param.value;
paramMultiValue = typeof param === "string" ? [param] : (param.multiValue || [paramValue]);
}
// If we've still not got a value, use the default, if any
paramValue = paramValue || paramInfo["default"] || "";
paramMultiValue = paramMultiValue || [paramValue];
// Store the parameter name and value
results.push({name: paramInfo.name, value: paramValue, multiValue: paramMultiValue});
results.push({name: paramInfo.name, value: paramValue});
}
return results;
};
@@ -325,7 +310,7 @@ Widget.prototype.getStateQualifier = function(name) {
};
/*
Make a fake widget with specified variables, suitable for variable lookup in filters. Each variable can be a string or an array of strings
Make a fake widget with specified variables, suitable for variable lookup in filters
*/
Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
var self = this,
@@ -333,12 +318,7 @@ Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
return {
getVariable: function(name,opts) {
if($tw.utils.hop(variables,name)) {
var value = variables[name];
if($tw.utils.isArray(value)) {
return value[0];
} else {
return value;
}
return variables[name];
} else {
opts = opts || {};
opts.variables = variables;
@@ -347,18 +327,9 @@ Widget.prototype.makeFakeWidgetWithVariables = function(variables) {
},
getVariableInfo: function(name,opts) {
if($tw.utils.hop(variables,name)) {
var value = variables[name];
if($tw.utils.isArray(value)) {
return {
text: value[0],
resultList: value
};
} else {
return {
text: value,
resultList: [value]
};
}
return {
text: variables[name]
};
} else {
opts = opts || {};
opts.variables = $tw.utils.extend({},variables,opts.variables);
@@ -395,45 +366,20 @@ Widget.prototype.computeAttributes = function(options) {
return changedAttributes;
};
/*
Compute the value of a single attribute. Options include:
asList: boolean if true returns results as an array instead of a single value
*/
Widget.prototype.computeAttribute = function(attribute,options) {
options = options || {};
Widget.prototype.computeAttribute = function(attribute) {
var self = this,
value;
if(attribute.type === "filtered") {
value = this.wiki.filterTiddlers(attribute.filter,this);
if(!options.asList) {
value = value[0] || "";
}
value = this.wiki.filterTiddlers(attribute.filter,this)[0] || "";
} else if(attribute.type === "indirect") {
value = this.wiki.getTextReference(attribute.textReference,"",this.getVariable("currentTiddler"));
if(value && options.asList) {
value = [value];
}
value = this.wiki.getTextReference(attribute.textReference,"",this.getVariable("currentTiddler")) || "";
} else if(attribute.type === "macro") {
var variableInfo = this.getVariableInfo(attribute.value.name,{params: attribute.value.params});
if(options.asList) {
value = variableInfo.resultList;
} else {
value = variableInfo.text;
}
value = variableInfo.text;
} else if(attribute.type === "substituted") {
value = this.wiki.getSubstitutedText(attribute.rawValue,this) || "";
if(options.asList) {
value = [value];
}
} else { // String attribute
value = attribute.value;
if(options.asList) {
if(value === undefined) {
value = [];
} else {
value = [value];
}
}
}
return value;
};

View File

@@ -200,7 +200,7 @@ exports.generateNewTitle = function(baseTitle,options) {
c = (parseInt(options.startCount,10) > 0) ? parseInt(options.startCount,10) : 0,
prefix = (typeof(options.prefix) === "string") ? options.prefix : " ";
if(template) {
if (template) {
// "count" is important to avoid an endless loop in while(...)!!
template = (/\$count:?(\d+)?\$/i.test(template)) ? template : template + "$count$";
// .formatTitleString() expects strings as input
@@ -209,7 +209,7 @@ exports.generateNewTitle = function(baseTitle,options) {
title = $tw.utils.formatTitleString(template,{"base":baseTitle,"separator":prefix,"counter":(++c)+""});
}
} else {
if(c > 0) {
if (c > 0) {
title = baseTitle + prefix + c;
}
while(this.tiddlerExists(title) || this.isShadowTiddler(title) || this.findDraft(title)) {
@@ -532,7 +532,7 @@ exports.getTiddlerLinks = function(title) {
return self.extractLinks(parser.tree);
}
return [];
}).slice(0);
});
};
/*
@@ -551,9 +551,8 @@ exports.getTiddlerBacklinks = function(targetTitle) {
backlinks.push(title);
}
});
return backlinks;
}
return backlinks.slice(0);
return backlinks;
};
@@ -579,7 +578,7 @@ exports.extractTranscludes = function(parseTreeRoot, title) {
}
}
} else if(parseTreeNode.attributes.tiddler) {
if(parseTreeNode.attributes.tiddler.type === "string") {
if (parseTreeNode.attributes.tiddler.type === "string") {
// Old transclude widget usage
value = parseTreeNode.attributes.tiddler.value;
}
@@ -619,7 +618,7 @@ exports.getTiddlerTranscludes = function(title) {
return self.extractTranscludes(parser.tree,title);
}
return [];
}).slice(0);
});
};
/*
@@ -631,9 +630,9 @@ exports.getTiddlerBacktranscludes = function(targetTitle) {
backtranscludes = backIndexer && backIndexer.subIndexers.transclude.lookup(targetTitle);
if(!backtranscludes) {
return [];
backtranscludes = [];
}
return backtranscludes.slice(0);
return backtranscludes;
};
/*
@@ -642,7 +641,7 @@ Return a hashmap of tiddler titles that are referenced but not defined. Each val
exports.getMissingTitles = function() {
var self = this,
missing = [];
// We should cache the missing tiddler list, even if we recreate it every time any tiddler is modified
// We should cache the missing tiddler list, even if we recreate it every time any tiddler is modified
this.forEachTiddler(function(title,tiddler) {
var links = self.getTiddlerLinks(title);
$tw.utils.each(links,function(link) {
@@ -684,7 +683,7 @@ exports.getTiddlersWithTag = function(tag) {
return self.sortByList(tagmap[tag],tag);
});
}
return results.slice(0);
return results;
};
/*
@@ -735,7 +734,7 @@ exports.findListingsOfTiddler = function(targetTitle,fieldName) {
for(var i = 0; i < list.length; i++) {
var listItem = list[i],
listing = listings[listItem] || [];
if(listing.indexOf(title) === -1) {
if (listing.indexOf(title) === -1) {
listing.push(title);
}
listings[listItem] = listing;
@@ -744,7 +743,7 @@ exports.findListingsOfTiddler = function(targetTitle,fieldName) {
});
return listings;
});
return (listings[targetTitle] || []).slice(0);
return listings[targetTitle] || [];
};
/*
@@ -783,7 +782,7 @@ exports.sortByList = function(array,listTitle) {
}
}
// If a new position is specified, let's move it
if(newPos !== -1) {
if (newPos !== -1) {
// get its current Pos, and make sure
// sure that it's _actually_ in the list
// and that it would _actually_ move
@@ -1060,7 +1059,7 @@ Options include:
exports.parseText = function(type,text,options) {
text = text || "";
options = options || {};
var Parser = $tw.utils.getParser(type,options);
var Parser = $tw.utils.getParser(type,options)
// Return the parser instance
return new Parser(type,text,{
parseAsInline: options.parseAsInline,
@@ -1079,11 +1078,11 @@ exports.parseTiddler = function(title,options) {
tiddler = this.getTiddler(title),
self = this;
return tiddler ? this.getCacheForTiddler(title,cacheType,function() {
if(tiddler.hasField("_canonical_uri")) {
options._canonical_uri = tiddler.fields._canonical_uri;
}
return self.parseText(tiddler.fields.type,tiddler.fields.text,options);
}) : null;
if(tiddler.hasField("_canonical_uri")) {
options._canonical_uri = tiddler.fields._canonical_uri;
}
return self.parseText(tiddler.fields.type,tiddler.fields.text,options);
}) : null;
};
exports.parseTextReference = function(title,field,index,options) {
@@ -1139,7 +1138,7 @@ exports.getTextReferenceParserInfo = function(title,field,index,options) {
parserInfo.parserType = null;
}
return parserInfo;
};
}
/*
Parse a block of text of a specified MIME type
@@ -1165,7 +1164,7 @@ exports.getSubstitutedText = function(text,widget,options) {
});
// Substitute any variable references with their values
return output.replace(/\$\((.+?)\)\$/g, function(match,varname) {
return widget.getVariable(varname,{defaultValue: ""});
return widget.getVariable(varname,{defaultValue: ""})
});
};
@@ -1243,7 +1242,7 @@ exports.makeTranscludeWidget = function(title,options) {
name: "recursionMarker",
type: "string",
value: options.recursionMarker || "yes"
},
},
tiddler: {
name: "tiddler",
type: "string",
@@ -1386,7 +1385,7 @@ exports.search = function(text,options) {
}
}
}
// Accumulate the array of fields to be searched or excluded from the search
// Accumulate the array of fields to be searched or excluded from the search
var fields = [];
if(options.field) {
if($tw.utils.isArray(options.field)) {
@@ -1519,7 +1518,7 @@ exports.checkTiddlerText = function(title,targetText,options) {
targetText = targetText.toLowerCase();
}
return text === targetText;
};
}
/*
Execute an action string without an associated context widget
@@ -1643,7 +1642,7 @@ exports.findDraft = function(targetTitle) {
}
});
return draftTitle;
};
}
/*
Check whether the specified draft tiddler has been modified.
@@ -1670,7 +1669,7 @@ historyTitle: title of history tiddler (defaults to $:/HistoryList)
exports.addToHistory = function(title,fromPageRect,historyTitle) {
var story = new $tw.Story({wiki: this, historyTitle: historyTitle});
story.addToHistory(title,fromPageRect);
console.log("$tw.wiki.addToHistory() is deprecated since V5.1.23! Use the this.story.addToHistory() from the story-object!");
console.log("$tw.wiki.addToHistory() is deprecated since V5.1.23! Use the this.story.addToHistory() from the story-object!")
};
/*
@@ -1683,7 +1682,7 @@ options: see story.js
exports.addToStory = function(title,fromTitle,storyTitle,options) {
var story = new $tw.Story({wiki: this, storyTitle: storyTitle});
story.addToStory(title,fromTitle,options);
console.log("$tw.wiki.addToStory() is deprecated since V5.1.23! Use the this.story.addToStory() from the story-object!");
console.log("$tw.wiki.addToStory() is deprecated since V5.1.23! Use the this.story.addToStory() from the story-object!")
};
/*

View File

@@ -1,7 +1,7 @@
title: $:/core/templates/tiddlywiki5-external-js.html
<$set name="saveTiddlerAndShadowsFilter" filter="[subfilter<saveTiddlerFilter>] [subfilter<saveTiddlerFilter>plugintiddlers[]]">
<$set name="rawMarkupFilter" filter="[enlist<saveTiddlerAndShadowsFilter>] [[$:/core]plugintiddlers[]]">
<$set name="rawMarkupFilter" filter="[enlist<saveTiddlerAndShadowsFilter>] +[[$:/core]plugintiddlers[]]">
`<!doctype html>
`{{$:/core/templates/MOTW.html}}`<html lang="`<$text text={{{ [{$:/language}get[name]] }}}/>`">
<head>

View File

@@ -25,7 +25,6 @@ title: $:/core/templates/tiddlywiki5.html
`{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/core/wiki/rawmarkup]] ||$:/core/templates/plain-text-tiddler}}}
{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/tags/RawMarkup]] ||$:/core/templates/plain-text-tiddler}}}
{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/tags/RawMarkupWikified]] ||$:/core/templates/raw-static-tiddler}}}`
<!--~~ Style section start ~~-->
</head>
<body class="tc-body">
<!--~~ Raw markup for the top of the body section ~~-->

View File

@@ -49,27 +49,6 @@ title: $:/core/ui/ImportListing
\end
\whitespace trim
<$let importJson={{{ [{$:/Import}] }}}>
<$let importTitles={{{ [<importJson>jsonindexes[tiddlers]] }}}>
<$let importTypes={{{ [(importTitles)] :map[<importJson>jsonget[tiddlers],<currentTiddler>,[type]] }}}>
<$let anyMatch={{{ [all[shadows+tiddlers]tag[$:/tags/ImportOptions]get[condition]] :map[(importTypes)subfilter<currentTiddler>] +[!is[blank]limit[1]] }}}>
<%if [<anyMatch>!is[blank]] %>
<div class="tc-import-option">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/ImportOptions]]" variable="importOption">
<$let condition={{{ [<importOption>get[condition]] }}}>
<$let hasMatch={{{ [(importTypes)subfilter<condition>limit[1]] }}}>
<%if [<hasMatch>!is[blank]] %>
<$transclude tiddler=<<importOption>>/>
<%endif%>
</$let>
</$let>
</$list>
</div>
<%endif%>
</$let>
</$let>
</$let>
</$let>
<div class="tc-table-wrapper">
<table class="tc-import-table">
<tbody>

View File

@@ -1,15 +0,0 @@
title: $:/core/ui/RootStylesheet
code-body: yes
\import [subfilter{$:/core/config/GlobalImportFilter}]
\whitespace trim
<$let currentTiddler={{$:/language}} languageTitle={{!!name}}>
<style type="text/css">
<$view tiddler="$:/themes/tiddlywiki/vanilla/reset" format="text" mode="block"/>
</style>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Stylesheet]!is[draft]] -[[$:/themes/tiddlywiki/vanilla/reset]]">
<style type="text/css">
<$view format={{{ [<currentTiddler>tag[$:/tags/Stylesheet/Static]then[text]else[plainwikified]] }}} mode="block"/>
</style>
</$list>
</$let>

View File

@@ -13,6 +13,56 @@ tags: $:/tags/Macro
\define color(name) <<colour $name$>>
\define box-shadow(shadow)
``
-webkit-box-shadow: $shadow$;
-moz-box-shadow: $shadow$;
box-shadow: $shadow$;
``
\end
\define filter(filter)
``
-webkit-filter: $filter$;
-moz-filter: $filter$;
filter: $filter$;
``
\end
\define transition(transition)
``
-webkit-transition: $transition$;
-moz-transition: $transition$;
transition: $transition$;
``
\end
\define transform-origin(origin)
``
-webkit-transform-origin: $origin$;
-moz-transform-origin: $origin$;
transform-origin: $origin$;
``
\end
\define background-linear-gradient(gradient)
``
background-image: linear-gradient($gradient$);
background-image: -o-linear-gradient($gradient$);
background-image: -moz-linear-gradient($gradient$);
background-image: -webkit-linear-gradient($gradient$);
background-image: -ms-linear-gradient($gradient$);
``
\end
\define column-count(columns)
``
-moz-column-count: $columns$;
-webkit-column-count: $columns$;
column-count: $columns$;
``
\end
\procedure datauri(title)
<$macrocall $name="makedatauri" type={{{ [<title>get[type]] }}} text={{{ [<title>get[text]] }}} _canonical_uri={{{ [<title>get[_canonical_uri]] }}}/>
\end

View File

@@ -1,43 +0,0 @@
title: $:/core/macros/deprecated
tags: $:/tags/Macro
<!-- Deprecated Macros -->
<!-- DO NOT USE THESE MACROS. THEY MAY BE REMOVED AT ANY MOMENT -->
\define box-shadow(shadow)
``
box-shadow: $shadow$;
``
\end
\define filter(filter)
``
filter: $filter$;
``
\end
\define transition(transition)
``
transition: $transition$;
``
\end
\define transform-origin(origin)
``
transform-origin: $origin$;
``
\end
\define background-linear-gradient(gradient)
``
background-image: linear-gradient($gradient$);
background-image: -moz-linear-gradient($gradient$);
background-image: -webkit-linear-gradient($gradient$);
``
\end
\define column-count(columns)
``
column-count: $columns$;
``
\end

View File

@@ -2,4 +2,4 @@ title: Using TiddlyWiki as a library in another Node.js application
Node.js applications can include TiddlyWiki as a library so that they can use wikitext rendering.
See the demo at https://github.com/Jermolene/TiddlyWiki5DemoApp
See the demo at https://github.com/TiddlyWiki/TiddlyWiki5DemoApp

View File

@@ -1,12 +1,13 @@
created: 20240313100515958
modified: 20251214111324789
original-modified: 20251023154747366
modified: 20241222104855231
original-modified: 20240313103959789
tags: Editions
title: TiddlyWiki Docs PR Maker
ja-title: TiddlyWikiドキュメントPRメーカー
''~TiddlyWikiドキュメントPRメーカー''は、ドキュメントへの貢献と改善を支援するために設計された、tiddlywiki.comの特別エディションです。
https://edit.tiddlywiki.com
[[@saqimtiaz|https://github.com/saqimtiaz/]]が作成した''~TiddlyWikiドキュメントPRメーカー''は、ドキュメントへの貢献と改善を支援するために設計された、tiddlywiki.comの特別エディションです。
https://saqimtiaz.github.io/tw5-docs-pr-maker/
ドキュメントに加えられたすべての変更は、GitHubに簡単に送信できます。 -- プルリクエストは自動的に作成されるため、エディションの名前は"PRメーカー"になります。

View File

@@ -1,6 +1,6 @@
created: 20231005205623086
modified: 20251208113045167
original-modified: 20250807100434131
modified: 20241226114558500
original-modified: 20241115193649399
tags: About
title: TiddlyWiki Archive
ja-title: TiddlyWikiアーカイブ
@@ -10,7 +10,7 @@ ja-title: TiddlyWikiアーカイブ
5.1.10 5.1.11 5.1.12 5.1.13 5.1.14 5.1.15 5.1.16 5.1.17 5.1.18 5.1.19
5.1.20 5.1.21 5.1.22 5.1.23
5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7
5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8
5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6
\end
TiddlyWikiの古いバージョンは[[アーカイブ|https://github.com/TiddlyWiki/tiddlywiki.com-gh-pages/tree/master/archive]]で入手できます:

View File

@@ -1,13 +1,31 @@
created: 20150412191004348
modified: 20251208113458455
original-modified: 20251022153208584
modified:
original-modified: 20240925114810504
tags: Community Reference
title: Developers
ja-title: 開発者
type: text/vnd.tiddlywiki
! [[GitHubの統計|https://github.com/TiddlyWiki/TiddlyWiki5/graphs/contributors]]
開発者がTiddlyWikiについて学び、開発について議論し、貢献するためのリソースがあります。
> [img[https://repobeats.axiom.co/api/embed/b92b1b363e2b5f26837ae573a60d39b4248b50a0.svg]]
* [[tiddlywiki.com/dev|https://tiddlywiki.com/dev]]は公式の開発者ドキュメントです
* [[GitHubでの開発|https://github.com/TiddlyWiki/TiddlyWiki5]]に参加する
* [[GitHubディスカッション|https://github.com/TiddlyWiki/TiddlyWiki5/discussions]]はQ&Aとオープンな形式のディスカッションです
* [[GitHubイシュー|https://github.com/TiddlyWiki/TiddlyWiki5/issues]]は、バグレポートを作成し、具体的で実現可能な新しいアイデアを提案するためのものです
* プロジェクトに貢献する方法についてのガイドラインについては、[[貢献|Contributing]]を参照してください
* 古い~TiddlyWikiDevGoogleグループは閉鎖され、[[TiddlyWikiトーク|https://talk.tiddlywiki.org/]]と[[GitHubディスカッション|https://github.com/TiddlyWiki/TiddlyWiki5/discussions]]に代わりました
** 有用なアーカイブとして残っています: https://groups.google.com/group/TiddlyWikiDev
*** 強化されたグループ検索機能は[[mail-archive.com|https://www.mail-archive.com/tiddlywikidev@googlegroups.com/]]で利用できます
* https://gitter.im/TiddlyWiki/public でチャットしてください(開発ルームは近日公開予定)
! Twitter
* 最新ニュースは[[Twitterで@TiddlyWiki|http://twitter.com/#!/TiddlyWiki]]をフォローしてください

View File

@@ -1,14 +1,88 @@
created: 20140908114400000
modified: 20251208115007037
original-modified: 20251122174540932
modified: 20241225112134741
original-modified: 20241016125145988
tags: About
title: History of TiddlyWiki
ja-title: TiddlyWikiの歴史
type: text/vnd.tiddlywiki
~TiddlyWikiの歴史をまとめています。このプロジェクトは現在進行中です。寄稿や思い出話など、ぜひお寄せください。
! ~TiddlyWikiの20年
~TiddlyWikiの20周年を祝うために、いくつかのライブストリームを開催しました。録画はここで視聴できます:
* 2024年9月19日 - https://youtube.com/live/z9slx92TyrU
* 2024年9月20日 - https://youtube.com/live/puFdN-FgOjg
* 2024年9月21日 - https://youtube.com/live/0SjsHvwjHGE
* 2024年9月22日 - https://youtube.com/live/oD7Jtq2D4lg
GitHubでは、TiddlyWikiの貢献者に記念日の感想を[[聞いて|https://github.com/TiddlyWiki/TiddlyWiki5/discussions/7983]]お祝いしました。興味深く思慮深い回答がいくつか寄せられました。たとえば、[[@FND|https://github.com/FND]]からの回答は次の通りです:
> TiddlyWikiは、私のキャリアだけでなく、価値観にも計り知れないほどの永続的な影響を与えました。今日に至るまで、私はTiddlyWikiから学んだ[[基本的なコンセプト|https://prepitaph.org/articles/creative-privacy/]] - その多くは、他では忘れられたり無視されたりしています - を頻繁に参照しています。このバックグラウンドがあることで、技術的な複雑さを崇拝したり、テクノロジーの世界に人間が存在することを思い出したりする場合でも、この業界で仕事をする上で自分の方向性を保つことができます。
> TiddlyWikiとは、人々のことです。このコミュニティや、Jeremyがその周りに築いたグループと交流し、そこから学ぶことができたのは、私にとって計り知れない特権でした。また、この特権がまったくの偶然によって私に与えられたものだということを思い出すのにも役立ちます。この恩返しをしていきたいと思います。
~TiddlyWikiを特集した最近のポッドキャスト:
* 2016年のチェンジログ ポッドキャスト - https://changelog.com/podcast/196 ~TiddlyWikiの背景について議論しています
* 2021年のFloss Weeklyの録画 - https://twit.tv/shows/floss-weekly/episodes/620
! TiddlyWikiの起源
遡ること1997年に、同僚が私に[[Ward Cunningham のオリジナル wiki|http://c2.com/cgi/wiki]]を紹介してくれました。これほど強力なものがわずか700行のPerlに収まることに感銘を受け、セキュリティとパーミッションの根本的な再考に魅了されました。他の多くの開発者と同様に、私もあらゆる機会を利用してさまざまなWikiを試し、仕事での使用法を模索しました
私にとってWikiの魅力は、印刷物中心のドキュメントやEメールの一般的なパラダイムを最終的に破壊する可能性があるという感覚でした
人々がWikiを使用する様子を数年間観察した結果、パワーユーザーは複数のブラウザタブで複数のWikiページを同時に開く機能を多用しており、ページの比較やレビュー、ページ間でのテキストのコピー、未読ページの一種のキューとして用いることが容易になっていることに気づきました
一度に複数のページを操作するこの機能がWikiをリファクタリングする機能の中心であると感じました。また、愛情を込めてリファクタリングされたWikiはより便利になる傾向があると一般に認められています。それでも、標準のWikiユーザーインターフェイスは常に、単一ページを一度に表示し操作すること専用にデザインされてきました
2004年4月にGMailを見たとき、すべての考えがまとまりました。GMailは、Ajaxを巧みに使用して個々のメールをスレッド化された会話に融合させました。
このアイデアをさらに探求するために、HTMLとJavaScriptを試し始めました。私にはどちらの経験もなく、以前の活動で、いくつかの静的ページと単純なASPサイトをまとめただけでした。これらのクライアント側テクロジーについて理解するのは大変でした。他の皆さんと同じように、私もWebプログラミングの非互換性と矛盾がどれほど恐ろしいものであるかを知り、愕然としました
! TiddlyWikiのラウンチ
そうして、2004年9月に、私は原始的な[[TiddlyWikiの最初のバージョン|https://classic.tiddlywiki.com/firstversion.html]]をリリースしました。これは、アイデアを実証するための最小のもので、シンプルで自己完結型の静的な48KB HTMLファイルでした
TiddlyWikiの最初のバージョンをこの方法で作成することの欠点は、編集に使用するのが完全に非現実的になることでした。'変更を保存'をクリックすると、ファイルシステムにHTMLページを書き込むために、保存されるデータを示すウィンドウがポップアップ表示されるだけでした
初期のフィードバックの多くは、TiddlyWikiは優れているが、変更を適切に保存できればさらに便利になるというものでした。ブラウザで実行されているHTMLファイルがローカルファイルシステムに変更を保存することは不可能であることはわかっていると思っていたので、少しイライラしました
数か月以内に、TiddlyWikiがブラウザに変更を保存できるようにする実験的なFirefox拡張機能を目にしました。コードを調べてみると、ファイルシステムへの書き込みに使用されていたAPIは、`file://` URI経由でロードされている場合に限り、実際には通常のHTMLファイルで利用できることがわかりました
私はFirefoxコードをTiddlyWikiのコアに適合させ、すぐにInternet Explorerにも同様の機能を追加しました(MicrosoftがInternet Explorerとともに配布した古い[[ActiveX|https://en.wikipedia.org/wiki/ActiveX]]コントロールを利用しています)
! TiddlyWikiの成長
TiddlyWikiの成長における大きなマイルストーンは、Nathan Bowersによる"GTDTiddlyWiki"の作成でした。彼はバニラのTiddlyWiki製品を採用し、一般的なGetting Things Done方法論を使用してタスクをトラックするという特定のアプリケーションに適応させました。GTDTiddlyWikiはすぐに人気を博し、[[LifeHacker|https://lifehacker.com/]]などのWebサイトで熱狂的に歓迎されました
その後数年間にわたって、TiddlyWikiの人気は高まり続け、新しい機能や能力も獲得しました。1年以内に、私はTiddlyWikiでオーダーメイドの開発作業を行うことで自活できるようになり、特にWikiパイオニアである[[SocialText|https://en.wikipedia.org/wiki/Socialtext]]と協力して変更をオンラインサーバと同期する機能に取り組みました
! BTの獲得
2007年5月に、[[BT]]は私のコンサルティング会社である[[Osmosoft]]を買収しました。従業員が1人で、収益がほんの少ししかない会社を買収するというのは、異例の決断でした。[[Osmosoft]]は、コミュニティの将来を保証するために私がTiddlyWikiの知的財産をUnaMesaに譲渡したため、TiddlyWikiの知的財産さえ所有していませんでした
[[BT]]の動機は、コミュニティベースのエコシステムを理解することでした。私は"オープンソースイノベーション責任者"として組織に加わり、オープンソースガバナンスの責任を負い、オープンソースコミュニティへの参加方法に関するアドバイスと専門知識を提供しました
! [[Osmosoft]]とTiddlySpace
私はBTに[[Osmosoft]]という名前でチームを作りました。私たちの目的は、オープンソースのメリットを広め、他のチームが実際にそのメリットを実感できるよう支援することでした。また、Webの使用全般、特にWeb標準の使用を普及する必要があることもわかりました
私たちのアプローチは、話すことよりも見せることに重点を置くことでした。私たちはTiddlyWikiコミュニティと協力してエコシステムを拡張し、BT用の多数の内部システムを構築しました(TiddlyWikiに基づくものもあれば、そうでないものもあります)
TiddlyWikiコミュニティへの[[Osmosoft]]の主な貢献は、TiddlyWebとTiddlySpaceの作成でした。TiddlyWebは、Tiddlerのための堅牢なインターネット規模のサーバであり、TiddlerのTiddlyWikiビューを構成することもできました。TiddlySpaceは、TiddlyWebをより直接的に使用可能な形式にパッケージ化する試みでした
! BTを離れる
2011年の終わりまでに、私はBTという企業の枠外でTiddlyWikiの可能性を実現するのがより適切な立場にあると感じるようになりました。そうして、私は退職して独立した開発者として働き始め、主にTiddlyWiki5という形でTiddlyWikiを新しくリブートすることに取り組みました
! TiddlyWiki5の開発
私は2011年11月からTiddlyWikiの新しいリリースに取り組みました。プログラマーとして、すでに書いたものの"バージョン 2.0"に取り組むことは非常に魅力的な提案です。これは、要件が完全に理解され、目的の機能をサポートするために必要なアーキテクチャの進化に集中できることを意味します
! 将来
TiddlyWiki5がついに"ベータ"ステータスを脱した今、私の希望は、それが長く存続することです。HTML5とNode.jsの標準機能のみを使用しているため、今後何年にもわたって完全に動作しない理由はありません。私の目標は、少なくとも25年は続けることです
//Jeremy Ruston, 2014年9月20日//
* [[TiddlyWiki物語|The Story of TiddlyWiki]] [[@Jermolene]]によるTiddlyWikiの物語、その起源と進化に関する個人的な記録
* https://github.com/TiddlyWiki/LaunchArchive 2004年のTiddlyWiki立ち上げ時からのブログとツイート
* [[TiddlyWiki記念日|TiddlyWiki Anniversaries]] TiddlyWikiの主要な記念日のお祝いイベントの記録
* [[フィルタシンタックスの歴史|Filter Syntax History]] TiddlyWiki5におけるフィルタシンタックスの進化の簡単な歴史

View File

@@ -1,71 +0,0 @@
title: The Story of TiddlyWiki
ja-title: TiddlyWiki物語
tags: [[History of TiddlyWiki]]
modifier: Jeremy Ruston
created: 20140908114400000
modified: 20251215111120830
original-modified: 20250730154331065
これは、2004年9月20日の最初のリリース以来のTiddlyWikiの起源と進化のストーリーについての個人的な記録です。
! TiddlyWikiの起源
遡ること1997年に、同僚が私に[[Ward Cunningham のオリジナル wiki|http://c2.com/cgi/wiki]]を紹介してくれました。これほど強力なものがわずか700行のPerlに収まることに感銘を受け、セキュリティとパーミッションの根本的な再考に魅了されました。他の多くの開発者と同様に、私もあらゆる機会を利用してさまざまなWikiを試し、仕事での使用法を模索しました
私にとってWikiの魅力は、印刷物中心のドキュメントやEメールの一般的なパラダイムを最終的に破壊する可能性があるという感覚でした
人々がWikiを使用する様子を数年間観察した結果、パワーユーザーは複数のブラウザタブで複数のWikiページを同時に開く機能を多用しており、ページの比較やレビュー、ページ間でのテキストのコピー、未読ページの一種のキューとして用いることが容易になっていることに気づきました
一度に複数のページを操作するこの機能がWikiをリファクタリングする機能の中心であると感じました。また、愛情を込めてリファクタリングされたWikiはより便利になる傾向があると一般に認められています。それでも、標準のWikiユーザーインターフェイスは常に、単一ページを一度に表示し操作すること専用にデザインされてきました
2004年4月にGMailを見たとき、すべての考えがまとまりました。GMailは、Ajaxを巧みに使用して個々のメールをスレッド化された会話に融合させました。
このアイデアをさらに探求するために、HTMLとJavaScriptを試し始めました。私にはどちらの経験もなく、以前の活動で、いくつかの静的ページと単純なASPサイトをまとめただけでした。これらのクライアント側テクロジーについて理解するのは大変でした。他の皆さんと同じように、私もWebプログラミングの非互換性と矛盾がどれほど恐ろしいものであるかを知り、愕然としました
! TiddlyWikiのラウンチ
そうして、2004年9月に、私は原始的な[[TiddlyWikiの最初のバージョン|https://classic.tiddlywiki.com/firstversion.html]]をリリースしました。これは、アイデアを実証するための最小のもので、シンプルで自己完結型の静的な48KB HTMLファイルでした
TiddlyWikiの最初のバージョンをこの方法で作成することの欠点は、編集に使用するのが完全に非現実的になることでした。'変更を保存'をクリックすると、ファイルシステムにHTMLページを書き込むために、保存されるデータを示すウィンドウがポップアップ表示されるだけでした
初期のフィードバックの多くは、TiddlyWikiは優れているが、変更を適切に保存できればさらに便利になるというものでした。ブラウザで実行されているHTMLファイルがローカルファイルシステムに変更を保存することは不可能であることはわかっていると思っていたので、少しイライラしました
数か月以内に、TiddlyWikiがブラウザに変更を保存できるようにする実験的なFirefox拡張機能を目にしました。コードを調べてみると、ファイルシステムへの書き込みに使用されていたAPIは、`file://` URI経由でロードされている場合に限り、実際には通常のHTMLファイルで利用できることがわかりました
私はFirefoxコードをTiddlyWikiのコアに適合させ、すぐにInternet Explorerにも同様の機能を追加しました(MicrosoftがInternet Explorerとともに配布した古い[[ActiveX|https://en.wikipedia.org/wiki/ActiveX]]コントロールを利用しています)
! TiddlyWikiの成長
TiddlyWikiの成長における大きなマイルストーンは、Nathan Bowersによる"GTDTiddlyWiki"の作成でした。彼はバニラのTiddlyWiki製品を採用し、一般的なGetting Things Done方法論を使用してタスクをトラックするという特定のアプリケーションに適応させました。GTDTiddlyWikiはすぐに人気を博し、[[LifeHacker|https://lifehacker.com/]]などのWebサイトで熱狂的に歓迎されました
その後数年間にわたって、TiddlyWikiの人気は高まり続け、新しい機能や能力も獲得しました。1年以内に、私はTiddlyWikiでオーダーメイドの開発作業を行うことで自活できるようになり、特にWikiパイオニアである[[SocialText|https://en.wikipedia.org/wiki/Socialtext]]と協力して変更をオンラインサーバと同期する機能に取り組みました
! BTの獲得
2007年5月に、[[BT]]は私のコンサルティング会社である[[Osmosoft]]を買収しました。従業員が1人で、収益がほんの少ししかない会社を買収するというのは、異例の決断でした。[[Osmosoft]]は、コミュニティの将来を保証するために私がTiddlyWikiの知的財産をUnaMesaに譲渡したため、TiddlyWikiの知的財産さえ所有していませんでした
[[BT]]の動機は、コミュニティベースのエコシステムを理解することでした。私は"オープンソースイノベーション責任者"として組織に加わり、オープンソースガバナンスの責任を負い、オープンソースコミュニティへの参加方法に関するアドバイスと専門知識を提供しました
! [[Osmosoft]]とTiddlySpace
私はBTに[[Osmosoft]]という名前でチームを作りました。私たちの目的は、オープンソースのメリットを広め、他のチームが実際にそのメリットを実感できるよう支援することでした。また、Webの使用全般、特にWeb標準の使用を普及する必要があることもわかりました
私たちのアプローチは、話すことよりも見せることに重点を置くことでした。私たちはTiddlyWikiコミュニティと協力してエコシステムを拡張し、BT用の多数の内部システムを構築しました(TiddlyWikiに基づくものもあれば、そうでないものもあります)
TiddlyWikiコミュニティへの[[Osmosoft]]の主な貢献は、TiddlyWebとTiddlySpaceの作成でした。TiddlyWebは、Tiddlerのための堅牢なインターネット規模のサーバであり、TiddlerのTiddlyWikiビューを構成することもできました。TiddlySpaceは、TiddlyWebをより直接的に使用可能な形式にパッケージ化する試みでした
! BTを離れる
2011年の終わりまでに、私はBTという企業の枠外でTiddlyWikiの可能性を実現するのがより適切な立場にあると感じるようになりました。そうして、私は退職して独立した開発者として働き始め、主にTiddlyWiki5という形でTiddlyWikiを新しくリブートすることに取り組みました
! TiddlyWiki5の開発
私は2011年11月からTiddlyWikiの新しいリリースに取り組みました。プログラマーとして、すでに書いたものの"バージョン 2.0"に取り組むことは非常に魅力的な提案です。これは、要件が完全に理解され、目的の機能をサポートするために必要なアーキテクチャの進化に集中できることを意味します
! 将来
2014年、 TiddlyWiki5を初めてリリースした直後に、私は次のように書きました:
> TiddlyWiki5がついに"ベータ"ステータスを脱した今、私の希望は、それが長く存続することです。HTML5とNode.jsの標準機能のみを使用しているため、今後何年にもわたって完全に動作しない理由はありません。私の目標は、少なくとも25年は続けることです
これを書いている時点で、TiddlyWiki5は目標の44%を達成しています。コミュニティの皆様のご支援と熱意により、このプロジェクトは今後も発展し、進化していくと確信しています。

View File

@@ -1,33 +0,0 @@
title: TiddlyWiki Anniversaries
ja-title: TiddlyWiki記念日
tags: [[History of TiddlyWiki]]
created: 20250730154331065
modified: 20251215105745893
original-modified: 20250730154331065
! ~TiddlyWikiの20周年
~TiddlyWikiの20周年を祝うために、いくつかのライブストリームを開催しました。録画はここで視聴できます:
* 2024年9月19日 - https://youtube.com/live/z9slx92TyrU
* 2024年9月20日 - https://youtube.com/live/puFdN-FgOjg
* 2024年9月21日 - https://youtube.com/live/0SjsHvwjHGE
* 2024年9月22日 - https://youtube.com/live/oD7Jtq2D4lg
GitHubでは、TiddlyWikiの貢献者に記念日の感想を[[聞いて|https://github.com/TiddlyWiki/TiddlyWiki5/discussions/7983]]お祝いしました。興味深く思慮深い回答がいくつか寄せられました。たとえば、[[@FND|https://github.com/FND]]からの回答は次の通りです:
> TiddlyWikiは、私のキャリアだけでなく、価値観にも計り知れないほどの永続的な影響を与えました。今日に至るまで、私はTiddlyWikiから学んだ[[基本的なコンセプト|https://prepitaph.org/articles/creative-privacy/]] - その多くは、他では忘れられたり無視されたりしています - を頻繁に参照しています。このバックグラウンドがあることで、技術的な複雑さを崇拝したり、テクノロジーの世界に人間が存在することを思い出したりする場合でも、この業界で仕事をする上で自分の方向性を保つことができます。
> TiddlyWikiとは、人々のことです。このコミュニティや、Jeremyがその周りに築いたグループと交流し、そこから学ぶことができたのは、私にとって計り知れない特権でした。また、この特権がまったくの偶然によって私に与えられたものだということを思い出すのにも役立ちます。この恩返しをしていきたいと思います。
~TiddlyWikiを特集した最近のポッドキャスト:
* 2016年のチェンジログ ポッドキャスト - https://changelog.com/podcast/196 ~TiddlyWikiの背景について議論しています
* 2021年のFloss Weeklyの録画 - https://twit.tv/shows/floss-weekly/episodes/620
! ~TiddlyWikiの10周年
2014年9月20日に行われた、TiddlyWikiの10周年を祝うライブストリームはここで視聴できます:
https://www.youtube.com/watch?v=f_02ZV0J9NY

View File

@@ -1,11 +1,13 @@
created: 20130909151600000
modified: 20251210110939585
original-modified: 20250909171928024
modified: 20241002113817654
original-modified: 20210322152237662
tags: TableOfContents Welcome
title: Community
ja-title: コミュニティ
type: text/vnd.tiddlywiki
TiddlyWikiコミュニティは、TiddlyWikiをより良くするために協力し、お互いにベストを尽せるよう支援する熱心なユーザーと開発者のグループです。
<<.tip "最新の有益なリンクが[[コミュニティリンク収集|Community Links Aggregator]]に集められています。">>
<<tabs "[[TiddlyWiki Project]] [[TiddlyWiki People]] Forums" "TiddlyWiki Project">>
すべての関連リンクがこれらのエントリに書かれると、メインのtiddlywiki.comサイトからは削除されます。
<<tabs "Forums Latest Tutorials [[Community Editions]] [[Community Plugins]] [[Community Themes]] [[Community Palettes]] [[Other Resources]] Examples Articles Meetups" "Latest">>

View File

@@ -1,9 +1,9 @@
color: #808
created: 20241009150445080
icon: $:/core/images/link
list: TalkTiddlyWiki [[TiddlyWiki on YouTube]] [[TiddlyWiki on Reddit]] [[TiddlyWiki on Discord]] [[TiddlyWiki on GitHub]] [[TiddlyWiki on Mastodon]] [[TiddlyWiki on Open Collective]]
modified: 20251210112417726
original-modified: 20241115170824144
list: TalkTiddlyWiki [[TiddlyWiki on YouTube]] [[TiddlyWiki on Reddit]] [[TiddlyWiki on Discord]] [[TiddlyWiki on GitHub]] [[TiddlyWiki on Mastodon]] [[TiddlyWiki on Twitter]] [[TiddlyWiki on Gitter]] [[TiddlyWiki on Open Collective]]
modified: 20241010114936568
original-modified: 20241009150453139
tags: Welcome
title: TiddlyWiki on the Web
ja-title: ウェブ上のTiddlyWiki

View File

@@ -1,6 +1,6 @@
created: 20140610213500000
modified: 20251212111127961
original-modified: 20250217154855572
modified: 20241209112247651
original-modified: 20241030132047048
tags: Concepts Features
title: ExternalImages
ja-title: 外部画像
@@ -25,28 +25,22 @@ TiddlyWikiの外部画像は、画像データすべてを埋め込むのでは
参照される外部画像を含む''images''フォルダーを伴うWikiの静的HTMLファイルバージョンを作成するには、次の手順を使用します:
# 通常の方法でTiddlyWikiFoldersに画像Tiddlerを作成します
# 画像を別ファイルとして保存します (慣例により、''/images''という名前のサブフォルダに保存します)
# 画像を別ファイルとして保存します (慣例により、''images''という名前のサブフォルダに保存します)
# ''_canonical_uri''フィールドを追加して画像Tiddlerを外部化します
# メインのHTMLファイルを保存します
画像ファイルは外部化する前に保存する必要があることに注意してください。外部化すると、Wikiストアのメモリ内コピーの''text''フィールドが破壊され、保存の試みが失敗します。
!! 外部画像の構成
たとえば、''tiddlywiki.info''ファイル内に、''externalimages''ビルドターゲットを作成します:
たとえば、''tw5.com'' Wikiの''externalimages''ビルドターゲットを参照してください:
```
"build": {
"externalimages": [
--save [is[image]] images
--setfield [is[image]] _canonical_uri $:/core/templates/canonical-uri-external-image text/plain
--setfield [is[image]] text "" text/plain
--render $:/core/save/all externalimages.html text/plain
]
}
--save [is[image]] images
--setfield [is[image]] _canonical_uri $:/core/templates/canonical-uri-external-image text/plain
--setfield [is[image]] text "" text/plain
--render $:/core/save/all externalimages.html text/plain
```
!! 画像Tiddlerの外部化
!! 個別の画像ファイルを保存する
次の`--save`コマンド ([[Saveコマンド|SaveCommand]]を参照)を使用すると、Wikiの画像を''images''サブフォルダーに保存できます:
@@ -54,6 +48,8 @@ TiddlyWikiの外部画像は、画像データすべてを埋め込むのでは
--save [is[image]] images
```
!! 画像Tiddlerの外部化
2つの`--setfield`コマンドが使用されています: 最初のコマンドは、''_canonical_uri''フィールドをTiddlerのタイトルから派生したURIに設定し、2番目のコマンドはtextフィールドをクリアします。
```
@@ -71,20 +67,6 @@ TiddlyWikiの外部画像は、画像データすべてを埋め込むのでは
これらの操作により、Wikiストア内のTiddlerが変更されるため、後続のコマンド操作に影響する可能性があることに注意してください。
!! 外部画像をビルドするためのNode.jsコマンド
次のコマンドは、`myWiki/output`フォルダー内に外部画像を作成します。
```
tiddlywiki myWiki --build externalimages
```
Windowsでは、次のコマンドを実行すると、[[tw5.comエディション|https://github.com/TiddlyWiki/TiddlyWiki5/blob/master/editions/tw5.com/tiddlywiki.info#L26]]の一部である外部画像が作成されます。ファイルは出力ディレクトリに作成されます。
```
tiddlywiki .\editions\tw5.com --build index
```
! 外部画像の使用について
URIフィールドを別の画像を指すように変更しない限り、ブラウザで外部画像を直接編集することはできません。

View File

@@ -1,6 +1,6 @@
created: 20150124182127000
modified: 20251213102731461
original-modified: 20250731101041336
modified: 20250222110925130
original-modified: 20230710074414361
tags: [[Filter Run]]
title: Filter Step
ja-title: フィルタステップ
@@ -13,10 +13,10 @@ type: text/vnd.tiddlywiki
<$railroad text="""
\start none
\end none
["!"]
[:"!"]
( / "省略の場合のデフォルト: title" /|:
( :[[<"オペレータ">|"Filter Operators"]] )
[ {":" [: [[<"サフィックス">|"Filter Operators"]] ] }] )
( - | :[[<"オペレータ">|"Filter Operators"]] )
{ [:":" [[<"サフィックス">|"Filter Operators"]] ] } )
{ [[<"パラメータ">|"Filter Parameter"]] + "," }
"""/>

View File

@@ -1,8 +1,8 @@
color: #880
created: 20241009150347613
icon: $:/core/images/help
modified: 20251213103718012
original-modified: 20241115170824144
modified: 20241010114029686
original-modified: 20241009150430229
tags: Welcome
title: Find Out More
ja-title: さらに詳しく

View File

@@ -1,41 +1,19 @@
created: 20130822170200000
icon: $:/core/icon
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: 20251213104120189
original-modified: 20250807084952911
modified: 20241010112232871
original-modified: 20241009150333146
tags: Welcome
title: HelloThere
ja-title: こんにちは
type: text/vnd.tiddlywiki
<h2
style="
background: red;
padding: 0.5em;
color: white;
font-weight: bold;
text-align: center;
border-radius: 0.5em;
box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
background-image: linear-gradient(90deg, rgb(34, 132, 224), rgb(95, 174, 248), rgb(34, 132, 224));
">
メモを有効活用する
</h2>
<h2
class="tc-hero-heading"
style="
text-align: center;
">
TiddlyWikiへようこそ。 TiddlyWikiは複雑な情報を[[収集|Creating and editing tiddlers]]し、[[整理|Structuring TiddlyWiki]]し、[[共有|Sharing your tiddlers with others]]するためのユニークな[[非線形|Philosophy of Tiddlers]]ノートブックです
</h2>
!!.tc-hero-heading ''TiddlyWikiへようこそ。 TiddlyWikiは複雑な情報を[[収集|Creating and editing tiddlers]]し、[[整理|Structuring TiddlyWiki]]し、[[共有|Sharing your tiddlers with others]]するためのユニークな[[非線形|Philosophy of Tiddlers]]ノートブックです。''
[[ToDo リスト|TaskManagementExample]]を管理したり、[[エッセイや小説|"TiddlyWiki for Scholars" by Alberto Molina]]を練ったり、結婚式を準備したりするために使えます。頭をよぎるすべての考えを記録し、柔軟で応答性の高いWebサイトを構築できます。
* ~TiddlyWikiはデータとコードを単一のHTMLファイルに保存し、インストールや外部依存を必要とせず、Webブラウザのみで動作します
* ~TiddlyWikiを使用すると、データの保存場所を選択でき、今日とったメモを今後数十年も[[使用できること|Future Proof]]が保証されます
* ~TiddlyWikiを使用すると、データの保存場所を選択でき、今日とったメモを今後数十年も[[使用できること|Future Proof]]が保証されます
* ~TiddlyWikiは、新しい機能を追加する多くのプラグインにより、無限にカスタマイズ、拡張可能です。
* ~TiddlyWikiは、新しい機能を追加する多くのプラグインにより、無限にカスタマイズ、拡張可能です
* ~TiddlyWikiは、大規模なユーザーコミュニティの一部である開発者集団の製品です
* ~TiddlyWikiは、大規模なユーザーコミュニティの一部である開発者集団の製品です

View File

@@ -1,7 +1,7 @@
color: #088
icon: $:/core/images/star-filled
modified: 20251214104051278
original-modified: 20241115170824144
modified: 20241010114508408
original-modified: 20241001141521924
tags: Welcome
title: Testimonials and Reviews
ja-title: 利用者の声とレビュー

View File

@@ -1,10 +1,8 @@
list: HelloThere [[Quick Start]] [[Find Out More]] [[TiddlyWiki on the Web]] [[Testimonials and Reviews]] GettingStarted Community
tags: TableOfContents
list-before:
title: Welcome
ja-title: ようこそ
type: text/vnd.tiddlywiki
<$transclude $tiddler="HelloThere"/>
''詳細については、トピックを選択してください:''
<div class="tc-table-of-contents"><<toc-selective-expandable "Welcome">></div>
<<list-links filter:"[tag<currentTiddler>]" >>

View File

@@ -2,8 +2,8 @@ color: #cc9
created: 20241009163451663
icon: $:/core/images/tip
list: GettingStarted [[Getting Started Video]] [[Find Out More]] [[TiddlyWiki on the Web]] [[Testimonials and Reviews]]
modified: 20251214103541254
original-modified: 20241115170824144
modified: 20241010112536263
original-modified: 20241009163521037
tags: Welcome
title: Quick Start
ja-title: クイックスタート

View File

@@ -1,9 +1,9 @@
created: 20240907042443909
modified: 20251214104453831
original-modified: 20241120225606237
modified: 20241116104031988
original-modified: 20240907042629405
tags: [[Hidden Settings]]
title: Hidden Setting: Default Tiddler Colour
ja-title: 隠し設定: TIddlerのデフォルト色
type: text/vnd.tiddlywiki
デフォルトのtag-tiddler色は、$:/config/DefaultTiddlerColourというTiddlerを作成し、CSSの色の値を含むことによって指定できます。詳細については、[[Tiddlerカラーカスケード|Tiddler Colour Cascade]]を参照してください
デフォルトのTiddler色は、$:/config/DefaultTiddlerColourというTiddlerを作成し、CSSの色の値を含むことによって指定できます。

View File

@@ -1,7 +1,7 @@
created: 20201228143125000
modified: 20251214105341696
original-modified: 20250302051857380
tags: OfficialPlugins [[Plugin Editions]]
modified: 20241222103744408
original-modified: 20201228143125000
tags: OfficialPlugins
title: Share Plugin
ja-title: シェアプラグイン
type: text/vnd.tiddlywiki
@@ -11,6 +11,4 @@ type: text/vnd.tiddlywiki
この実験的なプラグインは、URL経由でTiddlerを共有するためのツールを提供します。これには以下が含まれます:
* 起動時にブラウザのロケーションハッシュからTiddlerのグループをロードする機能
* TiddlerのグループからURLを作成するためのウィザードとテンプレート
デモは[ext[https://tiddlywiki.com/share|share]]を参照してください
* TiddlerのグループからURLを作成するためのウィザードとテンプレート

View File

@@ -1,12 +1,12 @@
created: 20130825160900000
modified: 20251214105948181
original-modified: 20241106165307259
modified: 20241110103519303
original-modified: 20160610083350724
tags: Features [[Working with TiddlyWiki]]
title: Encryption
ja-title: 暗号化
type: text/vnd.tiddlywiki
TiddlyWiki5を単一のHTMLファイルとして使用すると、[[Stanford JavaScript Crypto Library]]を使用してCCMモードのAES 128ビット暗号化でコンテンツを暗号化できます。
TiddlyWiki5を単一のHTMLファイルとして使用すると、[[Stanford JavaScript Crypto Library]]を使用してコンテンツを暗号化できます。
# サイドバーの''ツール''タブに切り替えて、南京錠アイコンのボタンを探します
# ボタンに<<.icon $:/core/images/unlocked-padlock>> ''パスワードの設定''と表示されている場合、現在のウィキは暗号化されていません。ボタンをクリックすると、以降の保存を暗号化するために使用されるパスワードの入力を求められます

View File

@@ -4,8 +4,7 @@ created: 20160216191710789
delivery: Protocol
description: SharePointなどの製品で利用できる標準Webプロトコル
method: save
modified: 20251214110658333
original-modified: 20220615155048712
modified: 20220615155048712
tags: Android Chrome Firefox [[Internet Explorer]] Linux Mac Opera PHP Safari Saving Windows iOS Edge
title: Saving via WebDAV
ja-title: WebDAV経由の保存

View File

@@ -1,6 +1,6 @@
created: 20140908163900000
modified: 20251214112408533
original-modified: 20230803052125981
modified: 20241016111248572
original-modified: 20201228143412000
tags: Learning
title: Sharing your tiddlers with others
ja-title: Tiddlerを他の人と共有する
@@ -12,7 +12,7 @@ type: text/vnd.tiddlywiki
* ~TiddlyWikiをオンラインで公開し、リンクを取得して他の人に送信、または、伝言できます:
** ~TiddlyWikiファイル全体のWebアドレスへのリンク
** 特定のTiddlerへの[[パーマリンク|PermaLinks]](<<.icon $:/core/images/permalink-button>>)
** 現在開いているすべてのTiddlerの[[パーマビュー|PermaLinks]](<<.icon $:/core/images/permaview-button>>)リンク
** 現在開いているすべてのTiddlerの[[パーマビュー|PermaViews]](<<.icon $:/core/images/permaview-button>>)リンク
* [[TiddlyWikiへのDropboxリンクを共有|Sharing a TiddlyWiki on Dropbox]]できます
* テキスト、静的HTML、カンマ区切り値(つまり、スプレッドシート互換)などのさまざまな形式で[[Tiddlerをエクスポート|How to export tiddlers]](<<.icon $:/core/images/export-button>>)できます
* また、~TiddlyWikiを他の人がアクセスできるようにするだけで、例えば、オンラインで公開して、そこから[[Tiddlerをインポート|Importing Tiddlers]]できるようにするだけで、Tiddlerを共有できます

View File

@@ -10,4 +10,4 @@ HelloThere
[[TiddlyWiki on the Web]]
[[Testimonials and Reviews]]
GettingStarted
Community
Community

View File

@@ -27,4 +27,4 @@ Block forced inline
+
title: ExpectedResult
<div class="tc-reveal"><p>Block</p></div><div class="tc-reveal"><p>Block forced block</p></div><span class="tc-reveal"><p>Block forced inline</p></span><p><span class="tc-reveal">Inline</span><div class="tc-reveal">Inline forced block</div><span class="tc-reveal">Inline forced inline</span></p>
<div class=" tc-reveal"><p>Block</p></div><div class=" tc-reveal"><p>Block forced block</p></div><span class=" tc-reveal"><p>Block forced inline</p></span><p><span class=" tc-reveal">Inline</span><div class=" tc-reveal">Inline forced block</div><span class=" tc-reveal">Inline forced inline</span></p>

View File

@@ -1,12 +0,0 @@
title: LetFilterRunPrefix/ResultList
description: Using the "let" filter run prefix to store result lists, not just single values
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$text text={{{ [all[tiddlers]] :let[[varname]] [(varname)sort[]join[,]] }}}/>
+
title: ExpectedResult
<p>$:/core,ExpectedResult,Output</p>

View File

@@ -1,12 +0,0 @@
title: LetFilterRunPrefix/ResultListUnnamedVariable
description: Using the "let" filter run prefix to store result lists, not just single values
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$text text={{{ [all[tiddlers]] :let[all[]tag[nothing]] [(varname)sort[]join[,]] }}}/>
+
title: ExpectedResult
<p></p>

View File

@@ -1,12 +0,0 @@
title: LetFilterRunPrefix/ShortcutSyntax
description: Simple usage of "let" filter run prefix
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$text text={{{ [[magpie]] =>varname [<varname>] +[join[-]] }}}/>
+
title: ExpectedResult
<p>magpie</p>

View File

@@ -1,12 +0,0 @@
title: LetFilterRunPrefix/Simple
description: Simple usage of "let" filter run prefix
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$text text={{{ [[magpie]] :let[[varname]] [<varname>] +[join[-]] }}}/>
+
title: ExpectedResult
<p>magpie</p>

View File

@@ -1,18 +0,0 @@
title: MultiValuedVariables/Function
description: Multi-valued functions
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\function myfunc() [all[tiddlers]sort[]]
<$let varname=<<myfunc>>>
<$text text={{{ [(varname)] +[join[-]] }}}/>
</$let>
+
title: ExpectedResult
<p>
$:/core-ExpectedResult-Output
</p>

View File

@@ -1,12 +0,0 @@
title: MultiValuedVariables/MissingVariable
description: Using multivalued operands with a missing variable
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$text text={{{ [(varname)] }}}/>
+
title: ExpectedResult
<p></p>

View File

@@ -1,18 +0,0 @@
title: MultiValuedVariables/NegatedTitle
description: Multi-valued operands
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$let
exclude={{{ $:/core Output }}}
>
<$text text={{{ [all[tiddlers]!title(exclude)] +[join[-]] }}}/>
</$let>
+
title: ExpectedResult
<p>
ExpectedResult
</p>

View File

@@ -1,18 +0,0 @@
title: MultiValuedVariables/Operands
description: Multi-valued operands
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\function myfunc() [all[tiddlers]sort[]]
<$let varname=<<myfunc>>>
<$text text={{{ [(varname)] +[join[-]] }}}/>
</$let>
+
title: ExpectedResult
<p>
$:/core-ExpectedResult-Output
</p>

View File

@@ -1,21 +0,0 @@
title: MultiValuedVariables/Parameters
description: Multi-valued function parameters
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\function myfunc(input) [(input)sort[]]
<$let
input={{{ [all[tiddlers]] }}}
output={{{ [function[myfunc],(input)] }}}
>
<$text text={{{ [(output)] +[join[-]] }}}/>
</$let>
+
title: ExpectedResult
<p>
$:/core-ExpectedResult-Output
</p>

View File

@@ -1,21 +0,0 @@
title: MultiValuedVariables/ParametersShortcut
description: Multi-valued function parameters using shortcut syntax
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\function my.func(input) [(input)sort[]]
<$let
input={{{ [all[tiddlers]] }}}
output={{{ [my.func(input)] }}}
>
<$text text={{{ [(output)] +[join[-]] }}}/>
</$let>
+
title: ExpectedResult
<p>
$:/core-ExpectedResult-Output
</p>

View File

@@ -1,17 +0,0 @@
title: MultiValuedVariables/Simple
description: Simple usage of multivalued assignments with the "let" widget
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<$let varname={{{ [all[tiddlers]sort[]] }}}
varname2=<<varname>>>
<$text text={{{ [(varname2)] +[join[-]] }}}/>
</$let>
+
title: ExpectedResult
<p>
$:/core-ExpectedResult-Output
</p>

View File

@@ -1,12 +0,0 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/VoidElements
type: text/vnd.tiddlywiki
This tests void elements like <br/> and <br> (without `/`).
Line one<br>Line two
Line three<br/>Line four
<hr>
Images are also void: <img src="test.png">

View File

@@ -2,4 +2,4 @@ title: expected-test-tabs-horizontal-a
type: text/html
description: Horizontal tabs test - This is the expected HTML output from a test in test-wikitext-tabs-macro.js
<p><div class="tc-tab-set "><div class="tc-tab-buttons "><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">t 3</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content "><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><p>Text tab 2</p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p>
<p><div class="tc-tab-set "><div class="tc-tab-buttons "><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">t 3</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content "><div class=" tc-reveal" hidden="true"></div><div class=" tc-reveal"><p>Text tab 2</p></div><div class=" tc-reveal" hidden="true"></div><div class=" tc-reveal" hidden="true"></div></div></div></p>

View File

@@ -2,4 +2,4 @@ title: expected-test-tabs-horizontal-all
type: text/html
description: Horizontal tabs with all parameters active. This is the expected HTML output from a test in test-wikitext-tabs-macro.js
<p><div class="tc-tab-set "><div class="tc-tab-buttons "><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">desc</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content "><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><h2 class="">TabTwo</h2><p><p>Text tab 2</p></p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p>
<p><div class="tc-tab-set "><div class="tc-tab-buttons "><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">desc</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content "><div class=" tc-reveal" hidden="true"></div><div class=" tc-reveal"><h2 class="">TabTwo</h2><p><p>Text tab 2</p></p></div><div class=" tc-reveal" hidden="true"></div><div class=" tc-reveal" hidden="true"></div></div></div></p>

View File

@@ -2,4 +2,4 @@ title: expected-test-tabs-vertical
type: text/html
description: Vertical tabs test -- This is the expected HTML output from the test in test-wikitext-tabs-macro.js
<p><div class="tc-tab-set tc-vertical"><div class="tc-tab-buttons tc-vertical"><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">t 3</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider tc-vertical"></div><div class="tc-tab-content tc-vertical"><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><p>Text tab 2</p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p>
<p><div class="tc-tab-set tc-vertical"><div class="tc-tab-buttons tc-vertical"><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">t 3</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider tc-vertical"></div><div class="tc-tab-content tc-vertical"><div class=" tc-reveal" hidden="true"></div><div class=" tc-reveal"><p>Text tab 2</p></div><div class=" tc-reveal" hidden="true"></div><div class=" tc-reveal" hidden="true"></div></div></div></p>

View File

@@ -143,33 +143,6 @@ describe("json filter tests", function() {
expect(wiki.filterTiddlers("[{First}jsonset:json[notjson]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
});
it("should support the jsondelete operator", function() {
// Delete top-level object property
expect(wiki.filterTiddlers("[{First}jsondelete[a]]")).toEqual(['{"b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
expect(wiki.filterTiddlers("[{First}jsondelete[b]]")).toEqual(['{"a":"one","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
expect(wiki.filterTiddlers("[{First}jsondelete[c]]")).toEqual(['{"a":"one","b":"","d":{"e":"four","f":["five","six",true,false,null]}}']);
// Delete nested object property
expect(wiki.filterTiddlers("[{First}jsondelete[d],[e]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"f":["five","six",true,false,null]}}']);
// Delete array element
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[0]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["six",true,false,null]}}']);
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[1]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five",true,false,null]}}']);
// Delete using negative array index
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[-1]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false]}}']);
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[-2]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,null]}}']);
expect(wiki.filterTiddlers("[{First}jsondelete[d],[f],[-5]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["six",true,false,null]}}']);
// Delete from array
expect(wiki.filterTiddlers("[{Second}jsondelete[0]]")).toEqual(['["deux","trois",["quatre","cinq"]]']);
expect(wiki.filterTiddlers("[{Second}jsondelete[1]]")).toEqual(['["une","trois",["quatre","cinq"]]']);
expect(wiki.filterTiddlers("[{Second}jsondelete[-1]]")).toEqual(['["une","deux","trois"]']);
// Attempting to delete non-existent property should return unchanged
expect(wiki.filterTiddlers("[{First}jsondelete[missing-property]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
expect(wiki.filterTiddlers("[{First}jsondelete[d],[missing]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
// Attempting to delete root should return unchanged
expect(wiki.filterTiddlers("[{First}jsondelete[]]")).toEqual(['{"a":"one","b":"","c":1.618,"d":{"e":"four","f":["five","six",true,false,null]}}']);
// Non-JSON input should return unchanged
expect(wiki.filterTiddlers("[{Third}jsondelete[a]]")).toEqual(["This is not JSON"]);
});
it("should support the format:json operator", function() {
expect(wiki.filterTiddlers("[{First}format:json[]]")).toEqual(["{\"a\":\"one\",\"b\":\"\",\"c\":1.618,\"d\":{\"e\":\"four\",\"f\":[\"five\",\"six\",true,false,null]}}"]);
expect(wiki.filterTiddlers("[{First}format:json[4]]")).toEqual(["{\n \"a\": \"one\",\n \"b\": \"\",\n \"c\": 1.618,\n \"d\": {\n \"e\": \"four\",\n \"f\": [\n \"five\",\n \"six\",\n true,\n false,\n null\n ]\n }\n}"]);

View File

@@ -60,10 +60,10 @@ describe("Widget module", function() {
childNode = childNode.children[0];
}
expect(childNode.getVariableInfo("macro",{allowSelfAssigned:true}).params).toEqual([{name:"a",value:"aa",multiValue:["aa"]}]);
expect(childNode.getVariableInfo("macro",{allowSelfAssigned:true}).params).toEqual([{name:"a",value:"aa"}]);
// function params
expect(childNode.getVariableInfo("fn", {allowSelfAssigned:true}).params).toEqual([{name:"f",value:"ff",multiValue:["ff"]}]);
expect(childNode.getVariableInfo("fn", {allowSelfAssigned:true}).params).toEqual([{name:"f",value:"ff"}]);
// functions have a text and a value
expect(childNode.getVariableInfo("x", {allowSelfAssigned:true}).text).toBe("fff");
expect(childNode.getVariableInfo("x", {allowSelfAssigned:true}).srcVariable.value).toBe("[<fn>]");
@@ -73,7 +73,7 @@ describe("Widget module", function() {
expect(childNode.getVariableInfo("$my.widget", {allowSelfAssigned:true}).params).toEqual([{name:"w",default:"ww"}]);
// no params expected
expect(childNode.getVariableInfo("abc", {allowSelfAssigned:true})).toEqual({text:"def", resultList: [ "def" ]});
expect(childNode.getVariableInfo("abc", {allowSelfAssigned:true})).toEqual({text:"def"});
// debugger; Find code in browser

View File

@@ -1,13 +0,0 @@
created: 20251021142729667
modified: 20251021142729667
tags:
title: Concatenating a text reference to create a URL
type: text/vnd.tiddlywiki
!! Concatenating variables and a text reference to create a URL
<$macrocall $name=wikitext-example src="""<$let hash={{{ [<currentTiddler>encodeuricomponent[]] }}}>
<a href=`${ [{!!base-url}] }$#$(hash)$`>this tiddler on tiddlywiki.com</a>
</$let>"""/>
See: [[Substituted Attribute Values]]

View File

@@ -1,13 +0,0 @@
created: 20251021142733998
modified: 20251021142733998
tags:
title: Concatenating variables to create a URL
type: text/vnd.tiddlywiki
!! Concatenating strings and variables to create a URL
<$macrocall $name=wikitext-example src="""<$let hash={{{ [<currentTiddler>encodeuricomponent[]] }}}>
<a href=`http://tiddlywiki.com/#$(hash)$`>this tiddler on tiddlywiki.com</a>
</$let>"""/>
See: [[Substituted Attribute Values]]

View File

@@ -1,13 +0,0 @@
created: 20251015120940754
modified: 20251101092833913
tags: $:/deprecated [[Core Classes]]
title: Deprecated Core Classes
type: text/vnd.tiddlywiki
<<.warning "It is not recommended to use these classes for styling. Though tiddlywiki might still support them, they may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using them, and update existing code if possible. Be aware that this feature may cease to work at any time.">>
These [[Core Classes]] are considered deprecated. It is not recommend to use them for styling.
* `tc-tagged-*` <<.deprecated-since 5.1.16>> Use [[Custom styles by data-tags]] instead.
* `tc-reveal` <<.deprecated-since 5.3.8>> for styling purposes as it is subject to change.
* `tc-language-(language code)` <<.deprecated-since 5.3.8>> Please use [[:lang()|https://developer.mozilla.org/en-US/docs/Web/CSS/:lang]] instead.

View File

@@ -1,31 +0,0 @@
created: 20251101085817414
modified: 20251101091035398
tags: [[Core Macros]] Macros $:/deprecated
title: Deprecated core macros
type: text/vnd.tiddlywiki
<<.warning "It is discouraged to use the following macros. Though tiddlywiki might still support them, they may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible. Be aware that these macros may cease to work at any time. ">>
Most deprecated macros are defined in [[$:/core/macros/deprecated]]. It is discouraged to use them.
! Stylesheet Macros
<<.deprecated-since 5.4.0>> The following core [[macros|Macros]] used to made it easy to specify alternative browser-specific properties when constructing a [[stylesheet|Cascading Style Sheets]] tiddler. They are deprecated after 2017 baseline is supported in v5.4.0:
; `<<box-shadow shadow>>`
: for the `x-box-shadow` properties
; `<<filter filter>>`
: for the `x-filter` properties
; `<<transition transition>>`
: for the `x-transition` properties
; `<<transform-origin origin>>`
: for the `x-transition-origin` properties
; `<<background-linear-gradient gradient>>`
: for the `x-linear-gradient` values of the `background-image` property
; `<<column-count columns>>`
: for the `x-column-count` property

View File

@@ -1,12 +1,12 @@
created: 20140908114400000
modified: 20251122174540932
modified: 20250730154331065
tags: About
title: History of TiddlyWiki
type: text/vnd.tiddlywiki
Gathering the history of ~TiddlyWiki. This is an ongoing project. Contributions and reminiscences are welcome.
* [[The Story of TiddlyWiki]] A personal account from [[@Jermolene]] of the story of TiddlyWiki, its origins and evolution
* https://github.com/TiddlyWiki/LaunchArchive Blog posts and tweets from TiddlyWiki's launch in 2004
* [[TiddlyWiki Anniversaries]] Relive the celebrations of TiddlyWiki's major anniversaries
* [[Filter Syntax History]] A brief history of the evolution of the filter syntax in TiddlyWiki5
Here is a brief history of TiddlyWiki, its origins and its evolution since it was first released on 20th September 2004. Contributions and reminiscences are welcome.
* [[The Story of TiddlyWiki]] a personal account of the story of TiddlyWiki, its origins and evolution
* [[TiddlyWiki Anniversaries]] relive the celebrations of TiddlyWiki's major anniversaries
* [[Filter Syntax History]] gives a brief history of the evolution of the filter syntax in TiddlyWiki5

View File

@@ -0,0 +1,60 @@
title: TiddlyWiki Newsletter Team
modified: 20241009171916728
tags: Community
The ~TiddlyWiki Newsletter is produced by a small team of volunteers. We would love to have your help if you want to get involved.
! Team
The newsletter team currently consists of:
* [[@jeremyruston|https://talk.tiddlywiki.org/u/jeremyruston]]
* [[@CodaCoder|https://talk.tiddlywiki.org/u/codacoder]]
* [[@Springer|https://talk.tiddlywiki.org/u/springer]]
! Audience
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
Subscribing to the newsletter should give people confidence that they will not miss any important developments.
! Process
The process is:
# Determine which discussion forum threads should be included
# Decide whether to link to the thread itself or to link to the subject of the thread
# Write a 30-70 word introduction
# Optionally, choose or make an image/screenshot to illustrate the story
These steps are described in more detail below.
!! Criteria for Inclusion
The criteria for inclusion are necessarily loose. Editorial judgement is required to decide whether an item is sufficiently interesting to a broad enough audience.
Important categories of threads that should be considered:
* All announcements of new releases of TiddlyWiki and TiddlyDesktop
* Community news and developments
* New plugins
* Updates to widely used plugins
* Showcases of interesting TiddlyWiki's in the wild
!! Linking
In most cases, news items should link to the opening post in the corresponding thread. There might be situations where it makes more sense to link to the item concerned which will be listed here.
!! Writing News Items
Items would be a 30-70 word introduction with a link, and optionally an image (the newsletter looks much more inviting with some images included).
!! Images
Well chosen images can be informative and add visual interest to the newsletter as a whole. Some points to consider when choosing an image:
* Images that work best of all are those that trigger an emotional response by including a human face. It is fairly unlikely that a ~TiddlyWiki news story would have a reason to be illustrated by a picture of a smiling baby, but we should strive to do so if we can
* If using a screenshot, remember that the image will be displayed fairly small in the newsletter so it is better to crop screenshots to show a smaller area of interest rather than the entire browser window
* Avoid using AI generated images

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