Compare commits

...

35 Commits

Author SHA1 Message Date
Mario Pietsch a72e5407b8
Merge 23f3362e3b into a081e58273 2024-04-25 23:45:07 +08:00
Matt Lauber a081e58273
HTTP Client: Return success calls for all 2XX response codes (#8150)
APIs especially use 2XX response codes outside of 200, 201, 204 for responding to responses.  Treat all "Successful" response codes (i.e. anything between 200-299) as successes, and pass the responseText.
2024-04-16 16:24:53 +01:00
Joshua Fontany 5f74f4c2fa
Fix bug 7878: Save command (#8140)
* first pass at fixing bug 7878, needs testing

* clarify default behaviour in comment

* fix property typo, tested and works as intended

* remove debugger
2024-04-11 21:54:46 +01:00
Joshua Fontany 9167b190d2
Fix bug 8138: server cache-control (#8141)
* cache-control no-store by default

* clarify comment spec reference

* comment typo

* fix else formatting

* Update server.js

allow route definitions to set their own cache-control
2024-04-11 19:23:32 +01:00
Cameron Fischer df8731f760
Made library boot module requirements consistent (#8083) 2024-04-10 10:52:22 +01:00
Rob Hoelz e9aa3c6c93
Add $timestamp argument for <$action-deletefield> widget (#8115)
* Start on some tests for <$action-deletefield />

* Only update modified field if we actually delete a field

…in the <$action-deletefield /> widget.

Fixes a bug where <$action-deletefield foo /> would update the modified field
if the "foo" field wasn't present on a tiddler.

* action-deletefield: Test when modified does and doesn't exist

* Add $timestamp argument to action-deletefield

To make it more consistent with other tiddler-manipulating action widgets

* Add docs for action-deletefield $timestamp
2024-04-04 16:03:15 +01:00
Jeremy Ruston 105e8195d5 Merge branch 'tiddlywiki-com' 2024-04-03 21:51:13 +01:00
Simon Huber eeb4e7a7f7
Add a "Refresh Browser" keyboard shortcut (#8121)
* Create a `refresh` keyboard shortcut

This creates a `refresh` keyboard shortcut that refreshes the page.
In TiddlyDesktop <kbd>ctrl-R</kbd> doesn't work

* Update refresh.tid

* Update shortcuts-not-mac.multids

* Update shortcuts-mac.multids

* Update ShortcutInfo.multids
2024-04-03 09:58:56 +01:00
Simon Huber 7ce85a2ddb
Update reset.tid to use modern-normalize 2.0.0 (#8120)
This PR updates the vanilla/reset stylesheet to use the newer `modern-normalize 2.0.0`
2024-04-02 17:35:10 +01:00
Crystal Person 804f227815
Signing CLA (#8126) 2024-03-31 17:08:09 +01:00
Rob Hoelz 9939759690
Report throttled refreshes (#8116)
Fixes GH #6054
2024-03-29 14:47:22 +00:00
Mario Pietsch b595651fe1
Fix hide-show button code needs to be transcluded mode=block (#8082) 2024-03-28 21:50:22 +00:00
Mario Pietsch 9cd6affcae
Minor changes to Widgets tiddler (#8107) 2024-03-28 19:29:57 +00:00
Mario Pietsch e43cd2d989
Use v5.3.x syntax for $:/core/ui/PageTemplate/pagecontrols (#8088) 2024-03-28 19:29:16 +00:00
Mario Pietsch f1e707bff4
Refactor GitHub-fork-ribbon plugin for better compatibility (#8075) 2024-03-28 19:27:58 +00:00
Mario Pietsch 2d92a6fd78
Tag picker rewritten using new v5.3.x syntax (#7978)
* tag-picker add Examples

* tag-picker - use new v5.3.x wikitext syntax

* tag-picker - more inline docs

* tag-picker - fix add button

* rename local functions: tag, userInput to _tf.getTag and _tf.getUersName to make the code and variable scopes more understandable

* tag-picker - move local variables definitions into one place: tag-picker macro

* tag-picker - replace reveal-widget with conditional IF syntax

* tag-picker - remove logs and test tag-picker - actions parameer -> OK

* tag-picker - add tag-picker Macro docs

* tag-picker docs - change \define -> \procedure

* tag-picker -- fix problem with focus loss if elements selected by mouse click

* tag-picker -- add tf. prefix only to new function definition names for backwards compatibility.

* tag-picker -- update example docs

* re-add tags: $:/tags/Macro
2024-03-28 19:09:31 +00:00
Mario Pietsch 2e0e541ebf
Add tc-tag-missing or tc-tag-exists to tag pills including docs (#7951)
* add tc-tag-missing or tc-tag-exists to tag pills including docs

* changes as requested

* macros not needed anymore - so remove

* fix the tag Macro docs
2024-03-28 19:07:54 +00:00
Mario Pietsch b4d7e34a5a
Add unusedtitle macro tests - should have full code covery (#7939)
* add unusedtitle macro tests - should have full code covery

* remove numbering from tests
2024-03-28 18:39:57 +00:00
Mario Pietsch b6eab1afd6
Add theme font size settings to Open in New Window CSS (#7945)
* add theme font size settings to Open in New Window CSS

* add DOCTYPE html to New Window startup template

* fix merge typo

* fix merge typo one more time
2024-03-28 18:36:33 +00:00
Télumire 32cbd53423
Set a proper doctype for the open window template (#8095) 2024-03-27 18:20:35 +00:00
Jeremy Ruston 90a6f31db2 Merge branch 'tiddlywiki-com' 2024-03-27 10:10:26 +00:00
Jeremy Ruston d37d6595b5 Docs: Add link to Basic Auth example 2024-03-27 10:09:46 +00:00
Jeremy Ruston e02cafb938 Add docs about using Basic Authentication in HTTP requests 2024-03-27 08:35:56 +00:00
Jeremy Ruston 801ed0ea11 Fix cycle operator crashing if step size is larger than the number of operands
See https://talk.tiddlywiki.org/t/bug-report-javascript-error-at-tw-com-within-cycle-operator-try-it/9430/1
2024-03-26 16:04:13 +00:00
Mario Pietsch 31ec1bdd50
Add tag parameter to reveal-widget to fix regression (#8084) 2024-03-18 09:08:11 +00:00
pmario 23f3362e3b description for new SystemTag: $:/tags/InjectCustomTiddlers 2024-03-11 16:52:09 +01:00
pmario 8be89ab7ef rename timestamp template to $:/core/templates/store.injected.timestamps.template 2024-03-11 16:51:34 +01:00
pmario ab53652cde rename .custom. to .injected. 2024-03-11 15:42:03 +01:00
pmario 5655d02ab3 fix template title 2024-03-11 15:31:44 +01:00
pmario 322fbdb36b rename sore.info -> store.custom, rename tag to $:/tags/InjectCustomTiddlers 2024-03-11 15:28:37 +01:00
pmario c3d19f173d Merge branch 'master' into 6684-add-last-saved-timestamp 2024-03-11 15:17:25 +01:00
pmario 7b0f23b2cc fix client-server docs 2024-01-31 11:05:50 +01:00
pmario cc569db973 add some docs to the new $:/Info/last-saved ... tiddlers 2024-01-31 10:41:35 +01:00
pmario c89b351cb4 add new store.info.template and store.info.tiddler.template tiddlers
the info.tiddler.template is tagged: $:/tags/InfoTiddlerTemplate so
several tagged tiddlers can be injected, if needed.

Important: The templates have to use the TW HTML template syntax

On branch 6684-add-last-saved-timestamp
Changes to be committed:
	new file:   core/templates/store.info.template.html.tid
	new file:   core/templates/store.info.tiddler.template.tid
2024-01-31 10:40:35 +01:00
pmario d7d9c83fea add a store.area.template to tiddlywiki5.html.tid. To work properly
it needs to go behind `{{$:/core/templates/store.info.template.html}}`

On branch 6684-add-last-saved-timestamp
Changes to be committed:
	modified:   core/templates/tiddlywiki5.html.tid
2024-01-31 10:28:51 +01:00
52 changed files with 1044 additions and 305 deletions

View File

@ -43,7 +43,9 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
directory: path.resolve(self.commander.outputPath),
pathFilters: [filenameFilter],
wiki: wiki,
fileInfo: {}
fileInfo: {
overwrite: true
}
});
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");

View File

@ -202,7 +202,7 @@ Extended filter operators to manipulate the current list.
}
if(resultsIndex !== -1) {
i = i + step;
nextOperandIndex = (i < opLength ? i : i - opLength);
nextOperandIndex = (i < opLength ? i : i % opLength);
if(operands.length > 1) {
results.splice(resultsIndex,1,operands[nextOperandIndex]);
} else {

View File

@ -140,6 +140,11 @@ function sendResponse(request,response,statusCode,headers,data,encoding) {
return;
}
}
} else {
// RFC 7231, 6.1. Overview of Status Codes:
// Browser clients may cache 200, 203, 204, 206, 300, 301,
// 404, 405, 410, 414, and 501 unless given explicit cache controls
headers["Cache-Control"] = headers["Cache-Control"] || "no-store";
}
/*
If the gzip=yes is set, check if the user agent permits compression. If so,

View File

@ -81,6 +81,8 @@ exports.startup = function() {
deferredChanges = Object.create(null);
$tw.hooks.invokeHook("th-page-refreshed");
}
var throttledRefresh = $tw.perf.report("throttledRefresh",refresh);
// Add the change event handler
$tw.wiki.addEventListener("change",$tw.perf.report("mainRefresh",function(changes) {
// Check if only tiddlers that are throttled have changed
@ -101,7 +103,7 @@ exports.startup = function() {
if(isNaN(timeout)) {
timeout = THROTTLE_REFRESH_TIMEOUT;
}
timerId = setTimeout(refresh,timeout);
timerId = setTimeout(throttledRefresh,timeout);
$tw.utils.extend(deferredChanges,changes);
} else {
$tw.utils.extend(deferredChanges,changes);

View File

@ -56,7 +56,7 @@ exports.startup = function() {
return;
}
// Initialise the document
srcDocument.write("<html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
srcDocument.write("<!DOCTYPE html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
srcDocument.close();
srcDocument.title = windowTitle;
srcWindow.addEventListener("beforeunload",function(event) {

View File

@ -283,7 +283,7 @@ exports.httpRequest = function(options) {
// Set up the state change handler
request.onreadystatechange = function() {
if(this.readyState === 4) {
if(this.status === 200 || this.status === 201 || this.status === 204) {
if(this.status >= 200 && this.status < 300) {
// Success!
options.callback(null,this[returnProp],this);
return;

View File

@ -316,11 +316,13 @@ Options include:
pathFilters: optional array of filters to be used to generate the base path
wiki: optional wiki for evaluating the pathFilters
fileInfo: an existing fileInfo object to check against
fileInfo.overwrite: if true, turns off filename clash numbers (defaults to false)
*/
exports.generateTiddlerFilepath = function(title,options) {
var directory = options.directory || "",
extension = options.extension || "",
originalpath = (options.fileInfo && options.fileInfo.originalpath) ? options.fileInfo.originalpath : "",
overwrite = options.fileInfo && options.fileInfo.overwrite || false,
filepath;
// Check if any of the pathFilters applies
if(options.pathFilters && options.wiki) {
@ -381,19 +383,20 @@ exports.generateTiddlerFilepath = function(title,options) {
filepath += char.charCodeAt(0).toString();
});
}
// Add a uniquifier if the file already exists
var fullPath, oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
// Add a uniquifier if the file already exists (default)
var fullPath = path.resolve(directory, filepath + extension);
if (!overwrite) {
var oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
count = 0;
do {
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
if(oldPath && oldPath == fullPath) {
break;
}
count++;
} while(fs.existsSync(fullPath));
do {
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
if(oldPath && oldPath == fullPath) break;
count++;
} while(fs.existsSync(fullPath));
}
// If the last write failed with an error, or if path does not start with:
// the resolved options.directory, the resolved wikiPath directory, the wikiTiddlersPath directory,
// or the 'originalpath' directory, then $tw.utils.encodeURIComponentExtended() and resolve to tiddler directory.
// or the 'originalpath' directory, then $tw.utils.encodeURIComponentExtended() and resolve to options.directory.
var writePath = $tw.hooks.invokeHook("th-make-tiddler-path",fullPath,fullPath),
encode = (options.fileInfo || {writeError: false}).writeError == true;
if(!encode) {

View File

@ -37,6 +37,7 @@ Compute the internal state of the widget
DeleteFieldWidget.prototype.execute = function() {
this.actionTiddler = this.getAttribute("$tiddler",this.getVariable("currentTiddler"));
this.actionField = this.getAttribute("$field",null);
this.actionTimestamp = this.getAttribute("$timestamp","yes") === "yes";
};
/*
@ -69,11 +70,15 @@ DeleteFieldWidget.prototype.invokeAction = function(triggeringWidget,event) {
$tw.utils.each(this.attributes,function(attribute,name) {
if(name.charAt(0) !== "$" && name !== "title") {
removeFields[name] = undefined;
hasChanged = true;
if(name in tiddler.fields) {
hasChanged = true;
}
}
});
if(hasChanged) {
this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),tiddler,removeFields,this.wiki.getModificationFields()));
var creationFields = this.actionTimestamp ? this.wiki.getCreationFields() : {};
var modificationFields = this.actionTimestamp ? this.wiki.getModificationFields() : {};
this.wiki.addTiddler(new $tw.Tiddler(creationFields,tiddler,removeFields,modificationFields));
}
}
return true; // Action was invoked

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,21 @@
title: $:/core/templates/store.injected.template.html
\whitespace trim
<!-- Unencrypted -->
<$list filter="[[$:/isEncrypted]get[text]else[no]match[no]]">
<$list filter="[[storeAreaFormat]is[variable]getvariable[]else[json]match[json]]">
<!-- New-style JSON store area -->
`<script class="tiddlywiki-tiddler-store" type="application/json">[`
<$let
newline={{{ [charcode[10]] }}}
join=`,$(newline)$`
>
<$text text=<<newline>>/>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/InjectCustomTiddlers]]">
<$transclude mode=block/>
</$list>
<$text text=<<newline>>/>
</$let>
`]</script>`
</$list>
</$list>

View File

@ -0,0 +1,23 @@
title: $:/core/templates/store.injected.timestamps.template
caption: Inject last-saved and server-created timestamps
tags: $:/tags/InjectCustomTiddlers
<!-- This template will be injected into the html file when the wiki is saved. It is activated by $:/core/templates/store.injected.template.html -->
\whitespace trim
\procedure readableFormat() [UTC]YYYY-0MM-0DD 0hh:0mm:0ss.0XXX UTC TZD
<!-- It's needed to use variables, to have the absolute same timestamp for all tiddlers -->
<$let
timestamp={{{ [<now format:[UTC]YYYY0MM0DD0hh0mm0ss0XXX>] }}}
timeReadable={{{ [<timestamp>format:date<readableFormat>] }}}
>
<% if [{$:/info/browser}match[yes]] %>
`{"title": "$:/info/last-saved/timestamp", "created":"`<<timestamp>>`", "modified":"`<<timestamp>>`", "text":"`<<timestamp>>`"}`
<$text text=<<join>>/>
`{"title": "$:/info/last-saved/date", "created":"`<<timestamp>>`", "modified":"`<<timestamp>>`", "text":"`<<timeReadable>>`"}`
<% elseif [{$:/info/node}match[yes]] %>
`{"title": "$:/info/server-created-wiki/timestamp", "created":"`<<timestamp>>`", "modified":"`<<timestamp>>`", "text":"`<<timestamp>>`"}`
<$text text=<<join>>/>
`{"title": "$:/info/server-created-wiki/date", "created":"`<<timestamp>>`", "modified":"`<<timestamp>>`", "text":"`<<timeReadable>>`"}`
<% endif %>
</$let>

View File

@ -41,6 +41,7 @@ title: $:/core/templates/tiddlywiki5.html
</noscript>
<!--~~ Ordinary tiddlers ~~-->
`{{$:/core/templates/store.area.template.html}}`
`{{$:/core/templates/store.injected.template.html}}`
<!--~~ Library modules ~~-->
<div id="libraryModules" style="display:none;">
`{{{ [is[system]type[application/javascript]library[yes]] ||$:/core/templates/javascript-tiddler}}}`

View File

@ -0,0 +1,5 @@
title: $:/core/ui/KeyboardShortcuts/refresh
tags: $:/tags/KeyboardShortcut
key: ((refresh))
<$action-sendmessage $message="tm-browser-refresh"/>

View File

@ -1,16 +1,14 @@
title: $:/core/ui/PageTemplate/pagecontrols
\whitespace trim
\define config-title() $:/config/PageControlButtons/Visibility/$(listItem)$
\function config-title() [[$:/config/PageControlButtons/Visibility/$(listItem)$]substitute[]]
<div class="tc-page-controls">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/PageControls]!has[draft.of]]" variable="listItem">
<$set name="hidden" value=<<config-title>>>
<$list filter="[<hidden>!text[hide]]" storyview="pop" variable="ignore">
<$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]">
<$transclude tiddler=<<listItem>> mode="inline"/>
</$set>
</$list>
</$set>
<$list filter="[<config-title>!text[hide]]" storyview="pop" variable="ignore">
<$let tv-config-toolbar-class={{{ [enlist<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]] +[join[ ]] }}}>
<$transclude $tiddler=<<listItem>> $mode="inline"/>
</$let>
</$list>
</$list>
</div>
</div>

View File

@ -31,7 +31,7 @@ tags: $:/tags/ViewTemplate
</$link>
</$set>
</div>
<$reveal type="nomatch" text="" default="" state=<<tiddlerInfoState>> class="tc-tiddler-info tc-popup-handle" animate="yes" retain="yes">
<$reveal tag="div" type="nomatch" text="" default="" state=<<tiddlerInfoState>> class="tc-tiddler-info tc-popup-handle" animate="yes" retain="yes">
<$list filter="[all[shadows+tiddlers]tag[$:/tags/TiddlerInfoSegment]!has[draft.of]] [[$:/core/ui/TiddlerInfo]]" variable="listItem">
<$transclude tiddler=<<listItem>> mode="block"/>
</$list>

View File

@ -35,6 +35,7 @@ new-tiddler: {{$:/language/Buttons/NewTiddler/Hint}}
picture: {{$:/language/Buttons/Picture/Hint}}
preview: {{$:/language/Buttons/Preview/Hint}}
quote: {{$:/language/Buttons/Quote/Hint}}
refresh: {{$:/language/Buttons/Refresh/Hint}}
save-tiddler: {{$:/language/Buttons/Save/Hint}}
save-wiki: {{$:/language/Buttons/SaveWiki/Hint}}
sidebar-search: {{$:/language/Buttons/SidebarSearch/Hint}}

View File

@ -6,4 +6,5 @@ underline: meta-U
new-image: ctrl-I
new-journal: ctrl-J
new-tiddler: ctrl-N
refresh: meta-R
save-wiki: meta-S

View File

@ -6,3 +6,4 @@ underline: ctrl-U
new-image: alt-I
new-journal: alt-J
new-tiddler: alt-N
refresh: ctrl-R

View File

@ -1,167 +1,182 @@
title: $:/core/macros/tag-picker
tags: $:/tags/Macro $:/tags/Global
first-search-filter: [tags[]!is[system]search:title<userInput>sort[]]
second-search-filter: [tags[]is[system]search:title<userInput>sort[]]
tags: tags: $:/tags/Macro $:/tags/Global
first-search-filter: [subfilter<tagListFilter>!is[system]search:title<userInput>sort[]]
second-search-filter: [subfilter<tagListFilter>is[system]search:title<userInput>sort[]]
\procedure get-tagpicker-focus-selector()
\function currentTiddlerCSSEscaped() [<saveTiddler>escapecss[]]
[data-tiddler-title=`$(currentTiddlerCSSEscaped)$`] .tc-add-tag-name input
<!-- first-search-filter and second-search-filter fields are not used here in the code, but they are defined as parameters for keyboard-driven-input macro -->
\whitespace trim
<!-- tf.tagpicker-dropdown-id is needed if several tap-pickers are shown in one tiddler -->
\function tf.tagpicker-dropdown-id()
[<qualify $:/state/popup/tags-auto-complete>]
[[$(saveTiddler)$-[$(tagField)$-$(tagListFilter)$]substitute[]sha256[]] +[join[/]]
\end
\procedure delete-tag-state-tiddlers() <$action-deletetiddler $filter="[<newTagNameTiddler>] [<storeTitle>] [<tagSelectionState>]"/>
\function tf.tagpicker-dropdown-class() [<tf.tagpicker-dropdown-id>sha256[]addprefix[tc-]]
\function tf.get-tagpicker-focus-selector() [<tf.tagpicker-dropdown-class>addprefix[.]] .tc-popup-handle +[join[ ]]
<!-- clean up temporary tiddlers, so the next "pick" starts with a clean input -->
<!-- This could probably be optimized / removed if we would use different temp-tiddlers
(future improvement because keeping track is comlex for humans)
-->
\procedure delete-tag-state-tiddlers()
<$action-deletetiddler $filter="[<newTagNameTiddler>] [<storeTitle>] [<tagSelectionState>]"/>
\end
<!-- trigger __toggle tag__ by keyboard -->
\procedure add-tag-actions()
\whitespace trim
<$let tag=<<tag>>>
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter='+[toggle<tag>trim[]]'/>
<$list
filter="[<tag>] :intersection[<saveTiddler>get<tagField>enlist-input[]]"
variable="ignore"
emptyMessage="<<actions>>"
/>
</$let>
<<delete-tag-state-tiddlers>>
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
\end
\procedure clear-tags-actions-inner()
\whitespace trim
<$list
filter="[<storeTitle>has[text]] ~[<newTagNameTiddler>has[text]]"
variable="ignore"
emptyMessage="<<cancel-delete-tiddler-actions 'cancel'>>"
>
<$let tag=<<_tf.getTag>> >
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter='+[toggle<tag>trim[]]'/>
<% if [<tag>] :intersection[<saveTiddler>get<tagField>enlist-input[]] %>
<!-- tag has been removed - do nothing -->
<% else %>
<<actions>>
<% endif %>
<<delete-tag-state-tiddlers>>
</$list>
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
</$let>
\end
<!-- <$action-log /> -->
<!-- ESC key removes the text from the input
The second ESC tries to close the "draft tiddler"
-->
\procedure clear-tags-actions-inner()
<% if [<storeTitle>has[text]] ~[<newTagNameTiddler>has[text]] %>
<<delete-tag-state-tiddlers>>
<% else %>
<<cancel-delete-tiddler-actions "cancel">>
<% endif %>
\end
<!-- triggered by keyboard only -->
\procedure clear-tags-actions()
\whitespace trim
<$let userInput=<<userInput>>>
<$list
filter="[<newTagNameTiddler>get[text]!match<userInput>]"
emptyMessage="<<clear-tags-actions-inner>>"
>
<$let userInput=<<_tf.getUserInput>> >
<!-- this list __cannot__ be transformed to conditional IF. The list variable is used! -->
<$list filter="[<newTagNameTiddler>get[text]!match<userInput>]" >
<$list-empty>
<<clear-tags-actions-inner>>
</$list-empty>
<$action-setfield $tiddler=<<newTagNameTiddler>> text=<<userInput>>/>
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
</$list>
</$let>
\end
<!-- similar to add-tag-actions __but__ add-only -->
\procedure add-button-actions()
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter="[<tag>trim[]]"/>
<<actions>>
<<delete-tag-state-tiddlers>>
<$action-sendmessage $message="tm-focus-selector" $param=<<get-tagpicker-focus-selector>>/>
<$action-sendmessage $message="tm-focus-selector" $param=<<tf.get-tagpicker-focus-selector>>/>
\end
<!-- <$action-log /> -->
\procedure list-tags(filter, suffix)
\whitespace trim
<$list
filter="[<userInput>minlength{$:/config/Tags/MinLength}limit[1]]"
emptyMessage="<div class='tc-search-results'>{{$:/language/Search/Search/TooShort}}</div>" variable="listItem"
>
<$list filter=<<filter>> variable="tag">
<$let
button-classes=`tc-btn-invisible ${ [<tag>addsuffix<suffix>] -[<tagSelectionState>get[text]] :then[[]] ~tc-tag-button-selected }$`
currentTiddler=<<tag>>
>
{{||$:/core/ui/TagPickerTagTemplate}}
</$let>
<!-- create dropdown list -->
\procedure tag-picker-listTags(filter, suffix)
<$let userInput=<<_tf.getUserInput>> >
<$list filter="[<userInput>minlength{$:/config/Tags/MinLength}limit[1]]"
emptyMessage="<div class='tc-search-results'>{{$:/language/Search/Search/TooShort}}</div>" variable="listItem"
>
<$list filter=<<filter>> variable="tag">
<!-- The buttonClasses filter is used to define tc-tag-button-selected state -->
<!-- tf.get-tagpicker-focus-selector has to be resolved for $:/core/ui/TagPickerTagTemplate,
othwerwise qualify in tf.tagpicker-dropdown-id causes problems -->
<$let currentTiddler=<<tag>>
button-classes=`tc-btn-invisible ${[<tag>addsuffix<suffix>] -[<tagSelectionState>get[text]] :then[[]] ~tc-tag-button-selected }$`
get-tagpicker-focus-selector=`${[<tf.get-tagpicker-focus-selector>]}$`
>
{{||$:/core/ui/TagPickerTagTemplate}}
</$let>
</$list>
</$list>
</$list>
</$let>
\end
<!-- tag-picker-inner is the main function -->
\procedure tag-picker-inner()
\whitespace trim
<div class={{{ [[tc-edit-add-tag]] [<tf.tagpicker-dropdown-class>] +[join[ ]] }}}>
<div class="tc-edit-add-tag-ui">
<span class="tc-add-tag-name tc-small-gap-right">
<$macrocall $name="keyboard-driven-input"
tiddler=<<newTagNameTiddler>>
storeTitle=<<storeTitle>>
refreshTitle=<<refreshTitle>>
selectionStateTitle=<<tagSelectionState>>
inputAcceptActions=<<add-tag-actions>>
inputCancelActions=<<clear-tags-actions>>
tag="input"
placeholder={{$:/language/EditTemplate/Tags/Add/Placeholder}}
focusPopup=<<tf.tagpicker-dropdown-id>>
class="tc-edit-texteditor tc-popup-handle"
tabindex=<<tabIndex>>
focus={{{ [{$:/config/AutoFocus}match[tags]then[true]] ~[[false]] }}}
filterMinLength={{$:/config/Tags/MinLength}}
cancelPopups=<<cancelPopups>>
configTiddlerFilter="[[$:/core/macros/tag-picker]]"
/>
</span>
<$button popup=<<tf.tagpicker-dropdown-id>> class="tc-btn-invisible tc-btn-dropdown"
tooltip={{$:/language/EditTemplate/Tags/Dropdown/Hint}} aria-label={{$:/language/EditTemplate/Tags/Dropdown/Caption}}
>
{{$:/core/images/down-arrow}}
</$button>
<% if [<storeTitle>has[text]] %>
<$button actions=<<delete-tag-state-tiddlers>> class="tc-btn-invisible tc-small-gap tc-btn-dropdown"
tooltip={{$:/language/EditTemplate/Tags/ClearInput/Hint}} aria-label={{$:/language/EditTemplate/Tags/ClearInput/Caption}}
>
{{$:/core/images/close-button}}
</$button>
<% endif %>
<span class="tc-add-tag-button tc-small-gap-left">
<$let tag=<<_tf.getTag>>>
<$button set=<<newTagNameTiddler>> actions=<<add-button-actions>> >
{{$:/language/EditTemplate/Tags/Add/Button}}
</$button>
</$let>
</span>
</div>
<div class="tc-block-dropdown-wrapper">
<% if [<tf.tagpicker-dropdown-id>has[text]] %>
<div class="tc-block-dropdown tc-block-tags-dropdown">
<$macrocall $name="tag-picker-listTags" filter=<<nonSystemTagsFilter>> suffix="-primaryList" />
<hr>
<$macrocall $name="tag-picker-listTags" filter=<<systemTagsFilter>> suffix="-secondaryList" />
</div>
<% endif %>
</div>
</div>
\end
<!-- prepare all variables for tag-picker keyboard handling -->
\procedure tag-picker(actions, tagField:"tags", tiddler, tagListFilter:"[tags[]]")
\function _tf.getUserInput() [<storeTitle>get[text]]
\function _tf.getTag() [<newTagNameTiddler>get[text]]
<!-- keep those variables because they may "blead" into macros using old syntax -->
<$let
newTagNameInputTiddlerQualified=<<qualify "$:/temp/NewTagName/input">>
newTagNameSelectionTiddlerQualified=<<qualify "$:/temp/NewTagName/selected-item">>
fallbackTarget={{{ [<palette>getindex[tag-background]] }}}
palette={{$:/palette}}
colourA={{{ [<palette>getindex[foreground]] }}}
colourB={{{ [<palette>getindex[background]] }}}
fallbackTarget={{{ [<palette>getindex[tag-background]] }}}
storeTitle={{{ [<newTagNameInputTiddler>!match[]] ~[<newTagNameInputTiddlerQualified>] }}}
saveTiddler={{{ [<tiddler>is[blank]then<currentTiddler>else<tiddler>] }}}
newTagNameTiddler={{{ [[$:/temp/NewTagName]] [<tagField>!match[tags]] +[join[/]] [<qualify>] +[join[]] }}}
storeTitle={{{ [[$:/temp/NewTagName/input]] [<tagField>!match[tags]] +[join[/]] [<qualify>] +[join[]] }}}
newTagNameSelectionTiddlerQualified=<<qualify "$:/temp/NewTagName/selected-item">>
tagSelectionState={{{ [<newTagNameSelectionTiddler>!match[]] ~[<newTagNameSelectionTiddlerQualified>] }}}
tagAutoComplete=<<qualify "$:/state/popup/tags-auto-complete">>
refreshTitle=<<qualify "$:/temp/NewTagName/refresh">>
nonSystemTagsFilter="[tags[]!is[system]search:title<userInput>sort[]]"
systemTagsFilter="[tags[]is[system]search:title<userInput>sort[]]"
>
<div class="tc-edit-add-tag">
<div>
<span class="tc-add-tag-name tc-small-gap-right">
<$transclude
$variable="keyboard-driven-input"
tiddler=<<newTagNameTiddler>>
storeTitle=<<storeTitle>>
refreshTitle=<<refreshTitle>>
selectionStateTitle=<<tagSelectionState>>
inputAcceptActions=<<add-tag-actions>>
inputCancelActions=<<clear-tags-actions>>
tag="input"
placeholder={{$:/language/EditTemplate/Tags/Add/Placeholder}}
focusPopup=<<tagAutoComplete>>
class="tc-edit-texteditor tc-popup-handle"
tabindex=<<tabIndex>>
focus={{{ [{$:/config/AutoFocus}match[tags]then[true]] ~[[false]] }}}
filterMinLength={{$:/config/Tags/MinLength}}
cancelPopups=<<cancelPopups>>
configTiddlerFilter="[[$:/core/macros/tag-picker]]"
/>
</span>
<$button popup=<<tagAutoComplete>>
class="tc-btn-invisible tc-btn-dropdown"
tooltip={{$:/language/EditTemplate/Tags/Dropdown/Hint}}
aria-label={{$:/language/EditTemplate/Tags/Dropdown/Caption}}
>
{{$:/core/images/down-arrow}}
</$button>
<$reveal state=<<storeTitle>> type="nomatch" text="">
<$button actions=<<delete-tag-state-tiddlers>>
class="tc-btn-invisible tc-small-gap tc-btn-dropdown"
tooltip={{$:/language/EditTemplate/Tags/ClearInput/Hint}}
aria-label={{$:/language/EditTemplate/Tags/ClearInput/Caption}}
>
{{$:/core/images/close-button}}
</$button>
</$reveal>
<span class="tc-add-tag-button tc-small-gap-left">
<$let tag=<<tag>>>
<$button set=<<newTagNameTiddler>> setTo=""
actions=<<add-button-actions>>
>
{{$:/language/EditTemplate/Tags/Add/Button}}
</$button>
</$let>
</span>
</div>
<div class="tc-block-dropdown-wrapper">
<$reveal state=<<tagAutoComplete>> type="nomatch" text="">
<div class="tc-block-dropdown tc-block-tags-dropdown">
<$let userInput=<<userInput>>>
<$transclude $variable="list-tags" filter=<<nonSystemTagsFilter>> suffix="-primaryList" />
<hr>
<$transclude $variable="list-tags" filter=<<systemTagsFilter>> suffix="-secondaryList" />
</$let>
</div>
</$reveal>
</div>
</div>
</$let>
\end
refreshTitle=<<qualify "$:/temp/NewTagName/refresh">>
\procedure tag-picker(actions, tagField:"tags")
\function userInput() [<storeTitle>get[text]]
\function tag() [<newTagNameTiddler>get[text]]
\whitespace trim
<$let
saveTiddler=<<currentTiddler>>
palette={{$:/palette}}
qualified=<<qualify "$:/temp/NewTagName">>
newTagNameTiddler={{{ [<newTagNameTiddler>!match[]] ~[<qualified>] }}}
nonSystemTagsFilter="[subfilter<tagListFilter>!is[system]search:title<userInput>sort[]]"
systemTagsFilter="[subfilter<tagListFilter>is[system]search:title<userInput>sort[]]"
cancelPopups="yes"
>
<$transclude $variable="tag-picker-inner" />
<$macrocall $name="tag-picker-inner"/>
</$let>
\end
\end

View File

@ -21,7 +21,9 @@ color:$(foregroundColor)$;
>
<<__actions__>>
<$transclude tiddler=<<__icon__>>/>
<$view tiddler=<<__tag__>> field="title" format="text" />
<span class={{{ [<__tag__>is[missing]then[tc-tag-missing]else[tc-tag-exists]] }}}>
<$view tiddler=<<__tag__>> field="title" format="text" />
</span>
</$element-tag$>
</$let>
\end

View File

@ -0,0 +1,27 @@
title: Macros/unusedtitle/basic-draft-exists
description: test <<unusedtitle>> with basic macro parameters but they are empty
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Draft of 'test'
draft.of: test
draft.title: test
+
title: Draft of 'asdf 0'
draft.of: asdf 0
draft.title: asdf 0
+
title: Output
<!-- hanled in wiki.js -->
<<unusedtitle baseName:"test">>
<!-- handled in unusedtitle.js -->
<<unusedtitle baseName:"asdf" separator:" " template:"$basename$$separator$$count:1$">>
+
title: ExpectedResult
<p>test 1</p><p>asdf 1</p>

View File

@ -0,0 +1,23 @@
title: Macros/unusedtitle/basic-params-empty-tiddler-exists
description: test <<unusedtitle>> with basic macro parameters but they are empty
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: New Tiddler
+
title: Output
<!-- hanled in wiki.js -->
<<unusedtitle separator:"">>
<!-- handled in unusedtitle.js -->
<<unusedtitle baseName:"">>
<!-- handled in wiki.js -->
<<unusedtitle template:"">>
+
title: ExpectedResult
<p>New Tiddler 1</p><p>New Tiddler 1</p><p>New Tiddler 1</p>

View File

@ -0,0 +1,20 @@
title: Macros/unusedtitle/basic-params-empty
description: test <<unusedtitle>> with basic macro parameters but they are empty
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<!-- hanled in wiki.js -->
<<unusedtitle separator:"">>
<!-- handled in unusedtitle.js -->
<<unusedtitle baseName:"">>
<!-- handled in wiki.js -->
<<unusedtitle template:"">>
+
title: ExpectedResult
<p>New Tiddler</p><p>New Tiddler</p><p>New Tiddler</p>

View File

@ -0,0 +1,28 @@
title: Macros/unusedtitle/basic-params-tiddlers-exist
description: test <<unusedtitle>> with basic macro parameters, where new-name tiddlers already exist
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: New Tiddler
+
title: anotherBase
+
title: About
+
title: Output
<<unusedtitle>>
<<unusedtitle separator:"-">>
<<unusedtitle baseName:"anotherBase">>
<<unusedtitle baseName:"About" separator:"-">>
+
title: ExpectedResult
<p>New Tiddler 1</p><p>New Tiddler-1</p><p>anotherBase 1</p><p>About-1</p>

View File

@ -0,0 +1,20 @@
title: Macros/unusedtitle/basic-params
description: test <<unusedtitle>> with basic macro parameters
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<<unusedtitle>>
<!-- EDGECASE: separator is ignored if tiddler title does not exist -->
<<unusedtitle separator:"-">>
<<unusedtitle baseName:"anotherBase">>
<<unusedtitle baseName:"About" separator:"-">>
+
title: ExpectedResult
<p>New Tiddler</p><p>New Tiddler</p><p>anotherBase</p><p>About</p>

View File

@ -0,0 +1,50 @@
title: Macros/unusedtitle/template-empty-params-tiddler-exist
description: test <<unusedtitle>> with templates where parameters are empty
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: New Tiddler
+
title: xxx
+
title: 00-New Tiddler
+
title: 0000 asdf
+
title: 0001 asdf
+
title: 0000 abc
+
title: Output
<!-- empty template - no template handling at all -->
<<unusedtitle template:"">>
<!--
uses basename AND separator if tiddler exists
because it uses default naming build rules - no template handling
-->
<<unusedtitle template:"" separator:"-y-" baseName:"xxx">>
<<unusedtitle baseName:"" template:"$count:2$-$basename$">>
<!--
EDGECASE: if separator is empty it will be initialized with a single space " "
to have the same rules for templates and default title creation
-->
<<unusedtitle baseName:"asdf" separator:"" template:"$count:4$$separator$$basename$">>
<!-- separator = " " -->
<<unusedtitle baseName:"abc" separator:" " template:"$count:4$$separator$$basename$">>
+
title: ExpectedResult
<p>New Tiddler 1</p><p>xxx-y-1</p><p>01-New Tiddler</p><p>0002 asdf</p><p>0001 abc</p>

View File

@ -0,0 +1,24 @@
title: Macros/unusedtitle/template-empty-params
description: test <<unusedtitle>> with templates where parameters are empty
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<!-- empty template -->
<<unusedtitle template:"">>
<!--
uses basename but ignores separator,
because it uses default naming build rules -- no template handling is active
-->
<<unusedtitle template:"" separator:"-x-" baseName:"xxx">>
<<unusedtitle baseName:"" template:"$count:2$-$basename$">>
<<unusedtitle baseName:"asdf" separator:"" template:"$count:4$$separator$$basename$">>
+
title: ExpectedResult
<p>New Tiddler</p><p>xxx</p><p>00-New Tiddler</p><p>0000 asdf</p>

View File

@ -0,0 +1,28 @@
title: Macros/unusedtitle/template
description: test <<unusedtitle>> with templates
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
<!-- empty template - standard rules are used -->
<<unusedtitle template:"">>
<<unusedtitle template:"count-missing">>
<<unusedtitle template:"$count:2$-new">>
<!-- template is handled using $tw.utils.formatTitleString -->
<<unusedtitle baseName:"base" template:"$count:2$-$basename$">>
<<unusedtitle baseName:"" template:"$count:2$-$basename$">>
<!-- UPPERCASES are intentional in template strings. They should be case-insensistive -->
<<unusedtitle baseName:"asdf" separator:"-" template:"$coUNT:2$$sepaRATor$$baseName$">>
<<unusedtitle baseName:"asdf" separator:"" template:"$count:2$$separator$$basename$">>
+
title: ExpectedResult
<p>New Tiddler</p><p>count-missing</p><p>00-new</p><p>00-base</p><p>00-New Tiddler</p><p>00-asdf</p><p>00 asdf</p>

View File

@ -0,0 +1,176 @@
/*\
title: test-action-deletefield.js
type: application/javascript
tags: [[$:/tags/test-spec]]
Tests <$action-deletefield />.
\*/
(function(){
/* jslint node: true, browser: true */
/* eslint-env node, browser, jasmine */
/* eslint no-mixed-spaces-and-tabs: ["error", "smart-tabs"]*/
/* global $tw, require */
"use strict";
describe("<$action-deletefield /> tests", function() {
const TEST_TIDDLER_TITLE = "TargetTiddler";
const TEST_TIDDLER_MODIFIED = "20240313114828368";
function setupWiki(condition, targetField, wikiOptions) {
// Create a wiki
var wiki = new $tw.Wiki({});
var tiddlers = [{
title: "Root",
text: "Some dummy content"
}];
var tiddler;
if(condition.targetTiddlerExists) {
var fields = {
title: TEST_TIDDLER_TITLE,
};
if(condition.modifiedFieldExists) {
fields.modified = TEST_TIDDLER_MODIFIED;
}
if(condition.targetFieldExists) {
fields[targetField] = "some text";
}
var tiddler = new $tw.Tiddler(fields);
tiddlers.push(tiddler);
}
wiki.addTiddlers(tiddlers);
wiki.addIndexersToWiki();
var widgetNode = wiki.makeTranscludeWidget("Root",{document: $tw.fakeDocument, parseAsInline: true});
var container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
return {
wiki: wiki,
widgetNode: widgetNode,
contaienr: container,
tiddler: tiddler,
};
}
function generateTestConditions() {
var conditions = [];
$tw.utils.each([true, false], function(tiddlerArgumentIsPresent) {
$tw.utils.each([true, false], function(targetTiddlerExists) {
$tw.utils.each([true, false], function(targetFieldExists) {
$tw.utils.each([true, false], function(fieldArgumentIsUsed) {
$tw.utils.each([true, false], function(modifiedFieldExists) {
$tw.utils.each(["", "yes", "no"], function(timestampArgument) {
conditions.push({
tiddlerArgumentIsPresent: tiddlerArgumentIsPresent,
targetTiddlerExists: targetTiddlerExists,
targetFieldExists: targetFieldExists,
fieldArgumentIsUsed: fieldArgumentIsUsed,
modifiedFieldExists: modifiedFieldExists,
timestampArgument: timestampArgument,
});
});
});
});
});
});
});
return conditions;
}
function generateActionWikitext(condition, targetField) {
var actionPieces = [
"<$action-deletefield",
(condition.tiddlerArgumentIsPresent ? "$tiddler='" + TEST_TIDDLER_TITLE + "'" : ""),
(condition.fieldArgumentIsUsed ? "$field='" + targetField + "'" : targetField),
(condition.timestampArgument !== "" ? "$timestamp='" + condition.timestampArgument + "'" : ""),
"/>",
];
return actionPieces.join(" ");
}
function generateTestContext(action, tiddler) {
var expectationContext = "action: " + action + "\ntiddler:\n\n";
if(tiddler) {
expectationContext += tiddler.getFieldStringBlock({exclude: ["text"]});
if(tiddler.text) {
expectationContext += "\n\n" + tiddler.text;
}
expectationContext += "\n\n";
} else {
expectationContext += "null";
}
return expectationContext;
}
it("should correctly delete fields", function() {
var fields = ['caption', 'description', 'text'];
var conditions = generateTestConditions();
$tw.utils.each(conditions, function(condition) {
$tw.utils.each(fields, function(field) {
var info = setupWiki(condition, field);
var originalTiddler = info.tiddler;
var invokeActions = function(actions) {
info.widgetNode.invokeActionString(actions,info.widgetNode,null,{
currentTiddler: TEST_TIDDLER_TITLE,
});
};
var action = generateActionWikitext(condition,field);
invokeActions(action);
var testContext = generateTestContext(action,originalTiddler);
var tiddler = info.wiki.getTiddler(TEST_TIDDLER_TITLE);
if(originalTiddler) {
// assert that the tiddler doesn't have the target field anymore
expect(tiddler.hasField(field)).withContext(testContext).toBeFalsy();
var targetFieldWasPresent = originalTiddler.hasField(field);
var updateTimestamps = condition.timestampArgument !== "no";
// "created" should exist if it did beforehand, or if the tiddler changed and we asked the widget to update timestamps
var createdFieldShouldExist = originalTiddler.hasField("created") || (targetFieldWasPresent && updateTimestamps);
// "created" should change only if it didn't exist beforehand and the tiddler changed and we asked the widget to update timestamps
var createdFieldShouldChange = !originalTiddler.hasField("created") && (targetFieldWasPresent && updateTimestamps);
// "modified" should exist if it did beforehand, or if the tiddler changed and we asked the widget to update timestamps
var modifiedFieldShouldExist = originalTiddler.hasField("modified") || (targetFieldWasPresent && updateTimestamps);
// "modified" should change if the tiddler changed and we asked the widget to update timestamps
var modifiedFieldShouldChange = targetFieldWasPresent && updateTimestamps;
expect(tiddler.hasField("created")).withContext(testContext).toBe(createdFieldShouldExist);
expect(tiddler.hasField("modified")).withContext(testContext).toBe(modifiedFieldShouldExist);
if(createdFieldShouldChange) {
expect(tiddler.fields.created).withContext(testContext).not.toEqual(originalTiddler.fields.created);
} else {
expect(tiddler.fields.created).withContext(testContext).toEqual(originalTiddler.fields.created);
}
if(modifiedFieldShouldChange) {
expect(tiddler.fields.modified).withContext(testContext).not.toEqual(originalTiddler.fields.modified);
} else {
expect(tiddler.fields.modified).withContext(testContext).toEqual(originalTiddler.fields.modified);
}
} else {
// assert that the tiddler didn't get created if it didn't exist already
expect(tiddler).withContext(testContext).toBeUndefined();
}
});
});
});
});
})();

View File

@ -0,0 +1,12 @@
caption: $:/tags/InjectCustomTiddlers
created: 20240311144347147
description: marks JSON serialized tiddlers to be injected into a custom store prior to a save-file action
modified: 20240311153411624
tags: SystemTags
title: SystemTag: $:/tags/InjectCustomTiddlers
type: text/vnd.tiddlywiki
The [[system tag|SystemTags]] `$:/tags/InjectCustomTiddlers` marks JSON serialized tiddlers to be injected [[into a custom store section|$:/core/templates/store.injected.template.html]] in the generated HTML file.
Note that the wiki must be saved and reloaded in order for the tiddlers to be seen. More implementation details can be found in the [[developers wiki|https://tiddlywiki.com/dev/#SystemTag%3A %24%3A%2Ftags%2FInjectCustomTiddlers]].

View File

@ -1,6 +1,6 @@
caption: tag
created: 20141206130540337
modified: 20230725201240201
modified: 20240228131301798
tags: Macros [[Core Macros]]
title: tag Macro
type: text/vnd.tiddlywiki
@ -11,7 +11,35 @@ The <<.def tag>> [[macro|Macros]] generates a tag pill for a specified tag. Clic
!! Parameters
;tag
; tag
: The title of the tag, defaulting to the [[current tiddler|Current Tiddler]]
!! CSS classes
<<.from-version "v5.3.4">>
; `tc-tag-missing`
: This class is defined if a tag does ''not exist'' as a tiddler.
; `tc-tag-exists`
: This class is defined if a tag does exist as a tiddler
!!! Defining the class
To define the `tc-tag-missing` class a stylesheet tiddler needs to be created. The default font-style for missing tiddler links is //italic//, so it's used for the example code below. Eg:
''title:'' `myTagsStylesheet`<br>
''tag:'' `$:/tags/Stylesheet`
<<copy-to-clipboard-above-right src:"""
.tc-tag-missing {
font-style: italic;
}
""">>
```
.tc-tag-missing {
font-style: italic;
}
```
<<.macro-examples "tag">>

View File

@ -1,5 +1,5 @@
created: 20150221211317000
modified: 20230725203751870
modified: 20240228131331605
tags: [[tag Macro]] [[Macro Examples]]
title: tag Macro (Examples)
type: text/vnd.tiddlywiki
@ -7,22 +7,26 @@ type: text/vnd.tiddlywiki
<$macrocall $name=".example" n="1" eg="""<<tag>>"""/>
<$macrocall $name=".example" n="2" eg="""<<tag Concepts>>"""/>
The Following tag can be shown with a font-style: //italic// if the corresponding stylesheet exists. See: [[tag Macro]]
<$macrocall $name=".example" n="3" eg="""<<tag "Does not exist">>"""/>
If a [[list widget|ListWidget]] generates multiple tag macros for the same tag, clicking any of them opens dropdowns on all of them, as in the example below. This is usually unwanted.
<$macrocall $name=".example" n="3" eg="""<$list filter="[tag[HelloThere]]">
<$macrocall $name=".example" n="4" eg="""<$list filter="[tag[HelloThere]]">
* <$link/> is tagged with: <$list filter="[<currentTiddler>tags[]]"> <<tag>> </$list>
</$list>"""/>
Adding the `counter="transclusion"` attribute to the list widget that generates multiple identical tag macros causes each of them to be identified as a unique one. Clicking on any of them opens only a single dropdown.
<$macrocall $name=".example" n="4" eg="""<$list filter="[tag[HelloThere]]" counter="transclusion">
<$macrocall $name=".example" n="5" eg="""<$list filter="[tag[HelloThere]]" counter="transclusion">
* <$link/> is tagged with: <$list filter="[<currentTiddler>tags[]]"> <<tag>> </$list>
</$list>"""/>
A slightly more performant option is to use the `variable="transclusion"` attribute in the list widget. In this case, the variable `<<transclusion>>` has to be used inside the list widget instead of the `<<currentTiddler>>` .
<$macrocall $name=".example" n="5" eg="""<$list filter="[tag[HelloThere]]" variable="transclusion">
<$macrocall $name=".example" n="6" eg="""<$list filter="[tag[HelloThere]]" variable="transclusion">
* <$link to=<<transclusion>>/> is tagged with: <$list filter="[<transclusion>tags[]]"> <<tag>> </$list>

View File

@ -1,6 +1,6 @@
caption: tag-picker
created: 20161128191316701
modified: 20161128191435641
modified: 20230616114543787
tags: Macros [[Core Macros]]
title: tag-picker Macro
type: text/vnd.tiddlywiki
@ -9,9 +9,17 @@ The <<.def tag-picker>> [[macro|Macros]] generates a combination of a text box a
!! Parameters
;actions
: Action widgets to be triggered when the pill is clicked. Within the text, the variable ''tag'' contains the title of the selected tag.
;tagField
: <<.from-version 5.1.23>> The ''field'' that gets updated with the selected tag. Defaults to ''tags''.
; actions
: Action widgets to be triggered when the pill is clicked. Within the text, the variable <<.var tag>> contains the title of the selected tag.
; tagField
: <<.from-version 5.1.23>> The specified ''field'' that gets updated with the selected tag. Defaults to `tags`.
; tiddler
: <<.from-version 5.3.4>> Defines the target tiddler, which should be manipulated. Defaults to: <<.var currentTiddler>>.
; tagListFilter
: <<.from-version 5.3.4>> This parameter defaults to: `[tags[]]` which creates a list of all existing tags. If the tag list should come from a different source the filter should look similar to eg: `[<listSource>get[field-name]enlist-input[]]`.
<<.macro-examples "tag-picker">>

View File

@ -1,5 +1,5 @@
created: 20140720164948099
modified: 20201124185829706
modified: 20240131100514913
tags: Mechanisms
title: InfoMechanism
type: text/vnd.tiddlywiki
@ -13,7 +13,7 @@ System tiddlers in the namespace `$:/info/` are used to expose information about
! Information Tiddlers
|!Title |!Description |
|[[$:/info/startup-timestamp]] |<<.from-version "5.1.23">> Startup timestamp in TiddlyWiki date format |
|[[$:/info/startup-timestamp]] |<<.from-version "5.1.23">> Startup timestamp in ~TiddlyWiki date format |
|[[$:/info/browser]] |Running in the browser? ("yes" or "no") |
|[[$:/info/mobile]] |<<.from-version "5.2.3">> Is running on a mobile device? ("yes" or "no" - eg, ''<<example full>>'') |
|[[$:/info/browser/language]] |<<.from-version "5.1.20">> Language as reported by browser (note that some browsers report two character codes such as `en` while others report full codes such as `en-GB`) |
@ -29,3 +29,41 @@ System tiddlers in the namespace `$:/info/` are used to expose information about
|[[$:/info/url/protocol]] |<<.from-version "5.1.14">> Protocol portion of URL of wiki (eg, ''<<example protocol>>'') |
|[[$:/info/url/search]] |<<.from-version "5.1.14">> Search portion of URL of wiki (eg, ''<<example search>>'') |
|[[$:/info/darkmode]] |<<.from-version "5.1.23">> Is dark mode enabled? ("yes" or "no") |
!! Last Saved -- Single File Wiki
The following tiddlers will be "injected" into the HTML file when the wiki is saved. Tagged template tiddlers are used to create the info tiddlers. Those tiddlers will be overwritten with the next automatic or manual save action.
`$:/info/last-saved/*` will not be created on a server if used with a client-server configuration. They will be created, if a "snapshot" is saved to the disk.
|! Title |! Description |
|$:/info/last-saved/timestamp |<<.from-version "5.3.4">> This tiddler will be created when a single file wiki is saved. It uses ~TiddlyWiki DateFormat |
|$:/info/last-saved/date |<<.from-version "5.3.4">> Shows the same last-saved timestamp in human readable form. Eg: "2024-01-30 15:36:04.430 UTC +01:00"<br>using the following format: `[UTC]YYYY-0MM-0DD 0hh:0mm:0ss.0XXX UTC TZD` |
!! Client Server Configuration
<<.warning """If a client server configuration is used, the TW template is used to create the wiki file on the server. So the timestamps saved to the "server-created" info tiddlers are generated by the server. Depending on the server "local time" this timestamp ''can be different'' to the current "user time". Whenever the wiki file is created, the values will be set. `server-created-*` tiddlers will ''not'' be deleted if saved as a single file. The information may have some value""">>
|! Title |! Description |
|$:/info/server-created-wiki/timestamp |<<.from-version "5.3.4">> This tiddler will be created when the server creates a wiki to be transferred to the client, ''ore'' if as single-file wiki is created by the server using the `--build index` command. It uses ~TiddlyWiki DateFormat |
|$:/info/server-created-wiki/date |<<.from-version "5.3.4">> Shows the same timestamp in human readable form |
!! Additional information
By default ~TiddlyWiki does not save the full URL information to the file, due to privacy concerns. Eg: `$:/info/last-saved/full/url` can contain private information. Users are free to include the following code into their wiki, if they decide to do so.
<details><summary>Show code to add the full path to an info tiddler</summary>
<$codeblock code="""title: inject-full-path
tags: $:/tags/InfoTiddlerTemplate
<!-- This template will be injected into the html file when the wiki is saved. It is activated by $:/core/templates/store.info.template.html -->
\whitespace trim
\function timestamp() [<now format:[UTC]YYYY0MM0DD0hh0mm0ss0XXX>]
<% if [{$:/info/browser}match[yes]] %>
<$text text=<<join>>/>
`{"title": "$:/info/last-saved/full/url", "created":"`<<timestamp>>`", "modified":"`<<timestamp>>`", "text":"`{{$:/info/url/full}}`"}`
<% endif %>
"""/>
</details>

View File

@ -0,0 +1,34 @@
title: WidgetMessage: tm-http-request Example - Basic Authentication
tags: $:/tags/Global
!! HTTP Basic Authentication
[[HTTP Basic Authentication|https://en.wikipedia.org/wiki/Basic_access_authentication]] is a simple scheme for HTTP clients pass a username and password to an HTTP server.
The credentials are passed via the "Authorization" header as the string "Basic " (note the space) followed by the base64-encoded username and password joined with a colon.
Here is a simple, illustrative example:
```
\procedure get-tiddler-list-from-tiddlywiki-server(url,username,password)
\procedure completion-get-json()
\import [subfilter{$:/core/config/GlobalImportFilter}]
<$action-log msg="In completion-get-json"/>
<$action-log/>
\end completion-get-json
<$action-sendmessage
$message="tm-http-request"
url=<<url>>
method="GET"
header-Authorization={{{ [<username>addsuffix[:]addsuffix<password>encodebase64[]addprefix[Basic ]] }}}
oncompletion=<<completion-get-json>>
/>
\end get-tiddler-list-from-tiddlywiki-server
<$button>
<<get-tiddler-list-from-tiddlywiki-server url:"http://127.0.0.1:8080" username:"Joe" password:"Bloggs">>
Download
</$button>
```

View File

@ -51,3 +51,4 @@ Note that the state tiddler $:/state/http-requests contains a number representin
* [[Zotero's|https://www.zotero.org/]] API for retrieving reference items: [[WidgetMessage: tm-http-request Example - Zotero]]
* [[Random Dog's|https://random.dog/]] API for retrieving random pictures of dogs showing how to retrieve binary data: [[WidgetMessage: tm-http-request Example - Random Dog]]
* Example of using HTTP Basic Authentication: [[WidgetMessage: tm-http-request Example - Basic Authentication]]

View File

@ -1,8 +1,8 @@
code-body: yes
created: 20150117152607000
modified: 20240229155550000
modified: 20240317091700545
tags: $:/tags/Macro
title: $:/editions/tw5.com/doc-macros
code-body: yes
type: text/vnd.tiddlywiki
\whitespace trim
@ -165,7 +165,7 @@ This is an example tiddler. See [[Table-of-Contents Macros (Examples)]].
<dd><$button set=<<.state>> setTo="">Hide</$button></dd>
</dl>
<blockquote class="doc-example-result">
<<eg>>
<$transclude $variable="eg" $mode="block"/>
</blockquote>
</$reveal>
</$list>

View File

@ -0,0 +1,69 @@
created: 20230616104546608
modified: 20240214174032498
tags: [[tag-picker Macro]] [[Macro Examples]]
title: tag-picker Macro (Examples)
type: text/vnd.tiddlywiki
<<.warning """The first example will set the tag of the <<.tid currentTiddler>> so you should copy / paste it to a new tiddler for testing. Otherwise you'll change "this tiddler" """>>
<$macrocall $name=".example" n="1"
eg="""Use all existing tags and set the ''tags'' field here: <<tag-picker>>
"""/>
----
<$let transclusion=test>
<<.tip """The following examples use a temporary tiddler: $:/temp/test/tag-picker. So this tiddler will not be changed """>>
<$macrocall $name=".example" n="2"
eg="""$:/temp/test/tag-picker ''tags'': <$text text={{{ [[$:/temp/test/tag-picker]get[tags]enlist-input[]join[, ]else[n/a]] }}}/>
Use all existing tags and set the $:/temp/test/tag-picker ''tags'' field: <<tag-picker tiddler:"$:/temp/test/tag-picker">>
"""/>
----
<<.tip """Use the following example to populate the $:/temp/test/tag-picker ''foo''-field, which are needed by some examples below """>>
<$macrocall $name=".example" n="3"
eg="""$:/temp/test/tag-picker ''foo'': <$text text={{{ [[$:/temp/test/tag-picker]get[foo]enlist-input[]join[, ]else[n/a]] }}}/>
Use all existing tags and set the $:/temp/test/tag-picker ''foo'' field: <<tag-picker tagField:"foo" tiddler:"$:/temp/test/tag-picker">>
"""/>
----
<<.tip """The following example expects some values in the "foo" field of the tiddler $:/temp/test/tag-picker, which can be created by the example above.""">>
<$macrocall $name=".example" n="4" eg="""\procedure listSource() $:/temp/test/tag-picker
$:/temp/test/tag-picker foo: <$text text={{{ [[$:/temp/test/tag-picker]get[foo]enlist-input[]join[, ]else[n/a]] }}}/><br>
$:/temp/test/tag-picker bar: <$text text={{{ [[$:/temp/test/tag-picker]get[bar]enlist-input[]join[, ]else[n/a]] }}}/>
Use $:/temp/test/tag-picker ''foo'' field as source and set ''bar'': <<tag-picker tagField:"bar" tagListFilter:"[<listSource>get[foo]enlist-input[]]" tiddler:"$:/temp/test/tag-picker">>
"""/>
----
<<.tip """The following example expects some values in the "foo" field of the tiddler $:/temp/test/tag-picker, which can be created by the example above.<br>
It will also add completely new tags to the bar-field and the source tiddlers foo-field. New tags can be entered by typing into the tag-name input
""">>
<$macrocall $name=".example" n="5" eg="""
\procedure listSource() $:/temp/test/tag-picker
\procedure listSourceField() foo
\procedure addNewTagToSource()
<$action-listops $tiddler=<<listSource>> $field=<<listSourceField>> $subfilter='[<listSource>get<listSourceField>enlist-input[]] [<tag>trim[]]'/>
\end
$:/temp/test/tag-picker foo: <$text text={{{ [[$:/temp/test/tag-picker]get[foo]enlist-input[]join[, ]else[n/a]] }}}/><br>
$:/temp/test/tag-picker ''bar'': <$text text={{{ [[$:/temp/test/tag-picker]get[bar]enlist-input[]join[, ]else[n/a]] }}}/>
Use $:/temp/test/tag-picker ''foo'' field as source and set ''bar'': <$macrocall $name="tag-picker" tagField="bar" tagListFilter="[<listSource>get<listSourceField>enlist-input[]]" tiddler="$:/temp/test/tag-picker" actions=<<addNewTagToSource>>/>
"""/>
</$let>

View File

@ -16,6 +16,7 @@ The ''action-deletefield'' widget is invisible. Any content within it is ignored
|!Attribute |!Description |
|$tiddler |The title of the tiddler whose fields are to be modified (if not provided defaults to the [[current tiddler|Current Tiddler]]) |
|$field |Optional name of a field to delete |
|$timestamp |<<.from-version "5.3.4">> Specifies whether the timestamp(s) of the target tiddler will be updated (''modified'' and ''modifier'', plus ''created'' and ''creator'' for newly created tiddlers). Can be "yes" (the default) or "no" |
|//{any attributes not starting with $}// |Each attribute name specifies a field to be deleted. The attribute value is ignored and need not be specified |
! Examples

View File

@ -1,14 +1,14 @@
created: 20140908130500000
modified: 20150219182745000
modified: 20240326164134356
tags: Concepts Reference
title: Widgets
type: text/vnd.tiddlywiki
~TiddlyWiki's display is driven by an underlying collection of <<.def widgets>>. These are organised into a tree structure: each widget has a parent widget and zero or more child widgets.
~TiddlyWiki generates this <<.def "widget tree">> by parsing the WikiText of tiddlers. Each component of the WikiText syntax, including even the trivial case of ordinary text, generates a corresponding widget. The widget tree is an intermediate representation that is subsequently rendered into the actual display.
~TiddlyWiki generates this <<.def "widget tree">> by parsing the ~WikiText of tiddlers. Each component of the ~WikiText syntax, including even the trivial case of ordinary text, generates a corresponding widget. The widget tree is an intermediate representation that is subsequently rendered into the actual display.
Widgets are analogous to elements in an HTML document. Indeed, HTML tags in WikiText generate dedicated <<.def "element widgets">>.
Widgets are analogous to elements in an HTML document. Indeed, HTML tags in ~WikiText generate dedicated <<.def "element widgets">>.
Each class of widget contributes a specific ability to the overall functionality, such as the ability to <<.wlink2 "display an image" ImageWidget>> or <<.wlink2 "a button" ButtonWidget>>, to <<.wlink2 "call a macro" MacroCallWidget>> or <<.wlink2 "transclude text from elsewhere" TranscludeWidget>>, or to [[mark a piece of text as a heading|HTML in WikiText]].
@ -16,4 +16,4 @@ The more specialised widgets use a general-purpose [[widget syntax|Widgets in Wi
The following classes of widget are built into the core:
<<list-links "[tag[Widgets]]">>
<<list-links "[tag[Widgets]]" class:"multi-columns">>

View File

@ -563,3 +563,5 @@ John Long, @drevarr, 2023/12/12
Ed Holsinger, @eschlon, 2024/02/08
Kim I. McKinley, @PotOfCoffee2Go, 2024/03/16
@Jinix6, 2024/03/31

View File

@ -4,8 +4,6 @@ This plugin provides a diagonal ribbon across the corner of the window. It resem
The ribbon can be positioned over any corner, and can incorporate user defined text, colours and a link.
The CSS stylesheet is adapted from work by Simon Whitaker:
The CSS stylesheet is adapted from work by [[Simon Whitaker|https://github.com/simonwhitaker/github-fork-ribbon-css/]]
https://github.com/simonwhitaker/github-fork-ribbon-css/
[[Source code|https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/github-fork-ribbon]]
[[Plugin source code|https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/github-fork-ribbon]]

View File

@ -1,5 +1,4 @@
title: $:/plugins/tiddlywiki/github-fork-ribbon/styles
tags: [[$:/tags/Stylesheet]]
/* Left will inherit from right (so we don't need to duplicate code */
.github-fork-ribbon {
@ -10,7 +9,7 @@ tags: [[$:/tags/Stylesheet]]
padding: 2px 0;
/* Set the base colour */
background-color: #a00;
background-color: <<color>>;
/* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.00)), to(rgba(0, 0, 0, 0.15)));
@ -25,7 +24,7 @@ tags: [[$:/tags/Stylesheet]]
-webkit-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5);
box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5);
z-index: 999;
z-index: 700;
pointer-events: auto;
}
@ -61,8 +60,8 @@ tags: [[$:/tags/Stylesheet]]
height: 150px;
position: absolute;
overflow: hidden;
top: 0;
z-index: 999;
top: <<top>>;
z-index: 700;
pointer-events: none;
}
@ -71,25 +70,25 @@ tags: [[$:/tags/Stylesheet]]
}
.github-fork-ribbon-wrapper.left {
left: 0;
left: <<left>>;
}
.github-fork-ribbon-wrapper.right {
right: 0;
right: <<right>>;
}
.github-fork-ribbon-wrapper.left-bottom {
position: fixed;
top: inherit;
bottom: 0;
left: 0;
bottom: <<bottom>>;
left: <<left>>;
}
.github-fork-ribbon-wrapper.right-bottom {
position: fixed;
top: inherit;
bottom: 0;
right: 0;
bottom: <<bottom>>;
right: <<right>>;
}
.github-fork-ribbon-wrapper.right .github-fork-ribbon {

View File

@ -0,0 +1,26 @@
title: $:/plugins/tiddlywiki/github-fork-ribbon/template
<!-- Parameters:
position: "right", "left", "right-bottom" and "left-bottom"
url: link target
text: ribbon text
color: defaults to "#aa0000" - dark red
top: offset from the top in px - eg: "30px"
bottom: offset from the bottom in px - No ;
left: offset from left in px - No ;
right: offset from right in px - No ;
fixed: "fixed" .. If ribbon is at the top, it can be "fixed". Bottom is always fixed
-->
\parameters (position:"right", url:"https://github.com/Jermolene/TiddlyWiki5", text:"Fork me on ~GitHub" color:"#aa0000" top:"0" bottom:"0" left:"0" right:"0" fixed:"")
<style>
{{$:/plugins/tiddlywiki/github-fork-ribbon/styles}}
</style>
<div class={{{ github-fork-ribbon-wrapper [<position>] [<fixed>] +[join[ ]] }}}>
<div class="github-fork-ribbon">
<a href=<<url>>>
<<text>>
</a>
</div>
</div>

View File

@ -1,26 +1,81 @@
title: $:/plugins/tiddlywiki/github-fork-ribbon/usage
Copy appropriate chunks on a new tiddler and tag it `$:/tags/PageControls`. Name of the new tiddler does not matter. Only the tag matters.
\procedure ribbonCode()
\whitespace trim
<$transclude $tiddler="$:/plugins/tiddlywiki/github-fork-ribbon/template" top="30px" fixed=fixed color="green"/>
\end
```
<!-- TOP RIGHT RIBBON: START COPYING HERE -->
<div class="github-fork-ribbon-wrapper right"><div class="github-fork-ribbon"><a href="https://github.com/simonwhitaker/github-fork-ribbon-css">Fork me on ~GitHub</a></div>
</div>
<!-- TOP RIGHT RIBBON: END COPYING HERE -->
\procedure ribbonCreateActions()
<% if [[$:/github-ribbon]!is[tiddler]] %>
<$action-setfield $tiddler="$:/github-ribbon" $field="text" $value=<<ribbonCode>>
tags="$:/tags/PageTemplate"
code-body="yes" />
<% endif %>
<$action-navigate $to="$:/github-ribbon" />
\end
<!-- TOP LEFT RIBBON: START COPYING HERE -->
<div class="github-fork-ribbon-wrapper left"><div class="github-fork-ribbon"><a href="https://github.com/simonwhitaker/github-fork-ribbon-css">Fork me on ~GitHub</a></div>
</div>
<!-- TOP LEFT RIBBON: END COPYING HERE -->
\procedure createRibbon()
<$button actions=<<ribbonCreateActions>> >
<%if [[$:/github-ribbon]!is[tiddler]] %>
Create
<% else %>
Show
<% endif %> ~$:/github-ribbon
</$button>
\end
\procedure ribbonToggleTagActions()
<$action-listops $tiddler="$:/github-ribbon" $field="tags" $subfilter="+[toggle[$:/tags/PageTemplate]]" />
\end
\procedure ribbonToggleTag() <$button actions=<<ribbonToggleTagActions>> >Toggle Tag</$button>
<!-- BOTTOM RIGHT RIBBON: START COPYING HERE -->
<div class="github-fork-ribbon-wrapper right-bottom"><div class="github-fork-ribbon"><a href="https://github.com/simonwhitaker/github-fork-ribbon-css">Fork me on ~GitHub</a></div>
</div>
<!-- BOTTOM RIGHT RIBBON: END COPYING HERE -->
`$:/plugins/tiddlywiki/github-fork-ribbon/template` is a template tiddler, that can be used with a transclusion and parameters.
<!-- BOTTOM LEFT RIBBON: START COPYING HERE -->
<div class="github-fork-ribbon-wrapper left-bottom"><div class="github-fork-ribbon"><a href="https://github.com/simonwhitaker/github-fork-ribbon-css">Fork me on ~GitHub</a></div>
</div>
<!-- BOTTOM LEFT RIBBON: END COPYING HERE -->
```
!! Usage
* Create a new tiddler eg: $:/github-ribbon
* Tag it `$:/tags/PageTemplate`
* Copy the code below
<pre><$text text=<<ribbonCode>>/></pre>
<<createRibbon>> <<ribbonToggleTag>>
!! Parameters
; position
: "right" (default), "left", "right-bottom" and "left-bottom"
; url
: Target URL, default: https://github.com/Jermolene/TiddlyWiki5
; text
: Ribbon text. default: `Fork me on ~GitHub`
; color
: Ribbon background color: default: `#aa0000`
; top
: Offset from the top if postion is top. default: `0` eg: `30px`, if the menu-toolbar plugin is installed
; bottom
: Offset from the bottom in px
; left
: Offset from the left in px
; right
: Offset from the right in px
; fixed
: If position is ''top'', the ribbon will scroll out of the viewport by default
: If the parameter `fixed="fixed"` it will be fixed
!! Remove the Ribbon
* Disable the plugin
* ''Remove the tag'' from $:/github-ribbon tiddler
* Delete the $:/github-ribbon tiddler
* <<ribbonToggleTag>>

View File

@ -931,6 +931,7 @@ button.tc-btn-invisible.tc-remove-tag-button {
.tc-page-controls {
margin-top: 14px;
margin-bottom: 14px;
font-size: 1.5em;
}
@ -1335,6 +1336,7 @@ canvas.tc-edit-bitmapeditor {
clear: both;
}
.tc-single-tiddler-window .tc-tiddler-body,
.tc-tiddler-frame .tc-tiddler-body {
font-size: {{$:/themes/tiddlywiki/vanilla/metrics/bodyfontsize}};
line-height: {{$:/themes/tiddlywiki/vanilla/metrics/bodylineheight}};
@ -1344,6 +1346,11 @@ canvas.tc-edit-bitmapeditor {
overflow: hidden; /* https://github.com/Jermolene/TiddlyWiki5/issues/282 */
}
/*
* Tiddler in a new window.
* Also see: .tc-single-tiddler-window .tc-tiddler-body, above
*/
html body.tc-body.tc-single-tiddler-window {
margin: 1em;
background: <<colour tiddler-background>>;

View File

@ -1,7 +1,7 @@
title: $:/themes/tiddlywiki/vanilla/reset
type: text/css
/*! modern-normalize v1.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
/*! modern-normalize v2.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
/*
Document
@ -13,28 +13,26 @@ Use a better box model (opinionated).
*/
*,
*::before,
*::after {
box-sizing: border-box;
::before,
::after {
box-sizing: border-box;
}
/**
Use a more readable tab size (opinionated).
*/
:root {
-moz-tab-size: 4;
tab-size: 4;
}
/**
1. Correct the line height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
/* Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */
font-family:
system-ui,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji';
line-height: 1.15; /* 1. Correct the line height in all browsers. */
-webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */
-moz-tab-size: 4; /* 3. Use a more readable tab size (opinionated). */
tab-size: 4; /* 3 */
}
/*
@ -42,29 +40,8 @@ Sections
========
*/
/**
Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)
*/
body {
font-family:
system-ui,
-apple-system, /* Firefox supports this but not yet `system-ui` */
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji';
margin: 0; /* Remove the margin in all browsers. */
}
/*
@ -78,8 +55,8 @@ Grouping content
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
height: 0; /* 1 */
color: inherit; /* 2 */
}
/*
@ -92,7 +69,7 @@ Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr[title] {
text-decoration: underline dotted;
text-decoration: underline dotted;
}
/**
@ -101,7 +78,7 @@ Add the correct font weight in Edge and Safari.
b,
strong {
font-weight: bolder;
font-weight: bolder;
}
/**
@ -113,14 +90,14 @@ code,
kbd,
samp,
pre {
font-family:
ui-monospace,
SFMono-Regular,
Consolas,
'Liberation Mono',
Menlo,
monospace; /* 1 */
font-size: 1em; /* 2 */
font-family:
ui-monospace,
SFMono-Regular,
Consolas,
'Liberation Mono',
Menlo,
monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
@ -128,7 +105,7 @@ Add the correct font size in all browsers.
*/
small {
font-size: 80%;
font-size: 80%;
}
/**
@ -137,18 +114,18 @@ Prevent 'sub' and 'sup' elements from affecting the line height in all browsers.
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
bottom: -0.25em;
}
sup {
top: -0.5em;
top: -0.5em;
}
/*
@ -158,12 +135,12 @@ Tabular data
/**
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
2. Correct table border color inheritance in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
}
/*
@ -181,20 +158,19 @@ input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
Remove the inheritance of text transform in Edge and Firefox.
1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
select {
text-transform: none;
}
/**
@ -205,7 +181,7 @@ button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button;
-webkit-appearance: button;
}
/**
@ -213,8 +189,8 @@ Remove the inner border and padding in Firefox.
*/
::-moz-focus-inner {
border-style: none;
padding: 0;
border-style: none;
padding: 0;
}
/**
@ -222,7 +198,7 @@ Restore the focus styles unset by the previous rule.
*/
:-moz-focusring {
outline: 1px dotted ButtonText;
outline: 1px dotted ButtonText;
}
/**
@ -231,7 +207,7 @@ See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d4
*/
:-moz-ui-invalid {
box-shadow: none;
box-shadow: none;
}
/**
@ -239,7 +215,7 @@ Remove the padding so developers are not caught out when they zero out 'fieldset
*/
legend {
padding: 0;
padding: 0;
}
/**
@ -247,7 +223,7 @@ Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
vertical-align: baseline;
}
/**
@ -256,7 +232,7 @@ Correct the cursor style of increment and decrement buttons in Safari.
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
height: auto;
}
/**
@ -265,8 +241,8 @@ Correct the cursor style of increment and decrement buttons in Safari.
*/
[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
@ -274,7 +250,7 @@ Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
-webkit-appearance: none;
}
/**
@ -283,8 +259,8 @@ Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/*
@ -297,5 +273,5 @@ Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
display: list-item;
}