mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-06-18 11:18:52 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0539edcb54 |
@@ -3,4 +3,3 @@
|
||||
tmp/
|
||||
output/
|
||||
node_modules/
|
||||
.claude/
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.4.1.
|
||||
TW5_BUILD_VERSION=v5.4.0
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -156,13 +156,14 @@ Fix the height of textarea to fit content
|
||||
FramedEngine.prototype.fixHeight = function() {
|
||||
// Make sure styles are updated
|
||||
this.copyStyles();
|
||||
if(this.widget.editTag === "textarea") {
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
this.iframeNode.style.height = newHeight + "px";
|
||||
}
|
||||
} else if(!this.widget.editRows) {
|
||||
} else {
|
||||
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
|
||||
fixedHeight = Math.max(fixedHeight,20);
|
||||
this.domNode.style.height = fixedHeight + "px";
|
||||
|
||||
@@ -100,12 +100,13 @@ SimpleEngine.prototype.getText = function() {
|
||||
Fix the height of textarea to fit content
|
||||
*/
|
||||
SimpleEngine.prototype.fixHeight = function() {
|
||||
if(this.widget.editTag === "textarea") {
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
}
|
||||
} else if(!this.widget.editRows) {
|
||||
} else {
|
||||
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
|
||||
fixedHeight = Math.max(fixedHeight,20);
|
||||
this.domNode.style.height = fixedHeight + "px";
|
||||
|
||||
@@ -327,7 +327,7 @@ exports.parseMacroParameterAsAttribute = function(source,pos) {
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'`=:]+)/y,
|
||||
reStrictIdentifier = /^[A-Za-z0-9\-_]+$/,
|
||||
reUnquotedAttribute = /(?!<<)((?:(?:>(?!>))|[^\s>"'])+)/y,
|
||||
reUnquotedAttribute = /((?:(?:>(?!>))|[^\s>"'])+)/y,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/y,
|
||||
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
|
||||
|
||||
@@ -40,8 +40,6 @@ exports.startup = function() {
|
||||
// The rest of the startup process here is not strictly to do with loading modules, but are needed before other startup
|
||||
// modules are executed. It is easier to put them here than to introduce a new startup module
|
||||
// --------------------------
|
||||
// Set up the performance framework
|
||||
$tw.perf = new $tw.Performance($tw.wiki.getTiddlerText(PERFORMANCE_INSTRUMENTATION_CONFIG_TITLE,"no") === "yes");
|
||||
// Create a root widget for attaching event handlers. By using it as the parentWidget for another widget tree, one can reuse the event handlers
|
||||
$tw.rootWidget = new widget.widget({
|
||||
type: "widget",
|
||||
@@ -50,6 +48,8 @@ exports.startup = function() {
|
||||
wiki: $tw.wiki,
|
||||
document: $tw.browser ? document : $tw.fakeDocument
|
||||
});
|
||||
// Set up the performance framework
|
||||
$tw.perf = new $tw.Performance($tw.wiki.getTiddlerText(PERFORMANCE_INSTRUMENTATION_CONFIG_TITLE,"no") === "yes");
|
||||
// Kick off the filter tracker
|
||||
$tw.filterTracker = new $tw.FilterTracker($tw.wiki);
|
||||
$tw.wiki.addEventListener("change",function(changes) {
|
||||
|
||||
@@ -3,43 +3,18 @@ title: $:/core/modules/utils/deprecated.js
|
||||
type: application/javascript
|
||||
module-type: utils
|
||||
|
||||
Deprecated util functions. These preserve the pre-5.4.0 signatures and
|
||||
behaviour for backwards compatibility with plugins and external scripts.
|
||||
Prefer modern alternatives in new code (Array.prototype methods, classList,
|
||||
Math.sign, String.prototype.repeat, etc.).
|
||||
Deprecated util functions
|
||||
|
||||
\*/
|
||||
|
||||
exports.logTable = (data) => console.table(data);
|
||||
|
||||
/*
|
||||
Repeats a string
|
||||
*/
|
||||
exports.repeat = function(str,count) {
|
||||
var result = "";
|
||||
for(var t=0;t<count;t++) {
|
||||
result += str;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
exports.repeat = (str,count) => str.repeat(count);
|
||||
|
||||
/*
|
||||
Check if a string starts with another string
|
||||
*/
|
||||
exports.startsWith = function(str,search) {
|
||||
return str.substring(0, search.length) === search;
|
||||
};
|
||||
exports.startsWith = (str,search) => str.startsWith(search);
|
||||
|
||||
/*
|
||||
Check if a string ends with another string
|
||||
*/
|
||||
exports.endsWith = function(str,search) {
|
||||
return str.substring(str.length - search.length) === search;
|
||||
};
|
||||
exports.endsWith = (str,search) => str.endsWith(search);
|
||||
|
||||
/*
|
||||
Trim whitespace from the start and end of a string
|
||||
*/
|
||||
exports.trim = function(str) {
|
||||
if(typeof str === "string") {
|
||||
return str.trim();
|
||||
@@ -54,54 +29,30 @@ exports.sign = Math.sign;
|
||||
|
||||
exports.strEndsWith = (str,ending,position) => str.endsWith(ending,position);
|
||||
|
||||
exports.stringifyNumber = function(num) {
|
||||
return num + "";
|
||||
};
|
||||
exports.stringifyNumber = (num) => num.toString();
|
||||
|
||||
// Returns the fully escaped CSS selector for a tag, e.g.
|
||||
// "$:/tags/Stylesheet" -> "tc-tagged-\%24\%3A\%2Ftags\%2FStylesheet"
|
||||
exports.tagToCssSelector = function(tagName) {
|
||||
return "tc-tagged-" + encodeURIComponent(tagName).replace(/[!"#$%&'()*+,\-./:;<=>?@[\\\]^`{\|}~,]/mg,function(c) {
|
||||
return "\\" + c;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Determines whether element 'a' contains element 'b'.
|
||||
Returns false when a === b (matches the original John Resig semantics).
|
||||
*/
|
||||
exports.domContains = function(a,b) {
|
||||
return a !== b && a.contains(b);
|
||||
};
|
||||
exports.domContains = (a,b) => a.compareDocumentPosition(b) & 16;
|
||||
|
||||
exports.domMatchesSelector = (node,selector) => node.matches(selector);
|
||||
|
||||
exports.hasClass = function(el,className) {
|
||||
return !!(el && el.classList && el.classList.contains(className));
|
||||
};
|
||||
|
||||
// addClass/removeClass/toggleClass split on whitespace to preserve the
|
||||
// original setAttribute("class", ...) acceptance of "foo bar" as two
|
||||
// classes. Regressed in #9251.
|
||||
function splitClasses(className) {
|
||||
return (typeof className === "string" && className.match(/\S+/g)) || [];
|
||||
}
|
||||
exports.hasClass = (el,className) => el.classList && el.classList.contains(className);
|
||||
|
||||
exports.addClass = function(el,className) {
|
||||
if(!el.classList) return;
|
||||
splitClasses(className).forEach(function(c) { el.classList.add(c); });
|
||||
el.classList && className && el.classList.add(className);
|
||||
};
|
||||
|
||||
exports.removeClass = function(el,className) {
|
||||
if(!el.classList) return;
|
||||
splitClasses(className).forEach(function(c) { el.classList.remove(c); });
|
||||
el.classList && className && el.classList.remove(className);
|
||||
};
|
||||
|
||||
exports.toggleClass = function(el,className,status) {
|
||||
if(!el.classList) return;
|
||||
splitClasses(className).forEach(function(c) { el.classList.toggle(c,status); });
|
||||
el.classList && className && el.classList.toggle(className, status);
|
||||
};
|
||||
|
||||
exports.getLocationPath = function() {
|
||||
return window.location.toString().split("#")[0];
|
||||
};
|
||||
exports.getLocationPath = () => window.location.origin + window.location.pathname;
|
||||
@@ -77,23 +77,10 @@ exports.resizeTextAreaToFit = function(domNode,minHeight) {
|
||||
// Measure the specified minimum height
|
||||
domNode.style.height = minHeight;
|
||||
var measuredHeight = domNode.offsetHeight || parseInt(minHeight,10);
|
||||
// Temporarily force rows=1 during auto-measurement so the intrinsic floor
|
||||
// is one row rather than the HTML default of two; restore afterwards
|
||||
var hadRowsAttr = domNode.hasAttribute("rows"),
|
||||
savedRows = hadRowsAttr ? domNode.getAttribute("rows") : null;
|
||||
if(!hadRowsAttr) {
|
||||
domNode.setAttribute("rows","1");
|
||||
}
|
||||
// Set its height to auto so that it snaps to the correct height
|
||||
domNode.style.height = "auto";
|
||||
// Calculate the revised height
|
||||
var newHeight = Math.max(domNode.scrollHeight + domNode.offsetHeight - domNode.clientHeight,measuredHeight);
|
||||
// Restore the original rows attribute state
|
||||
if(!hadRowsAttr) {
|
||||
domNode.removeAttribute("rows");
|
||||
} else {
|
||||
domNode.setAttribute("rows",savedRows);
|
||||
}
|
||||
// Only try to change the height if it has changed
|
||||
if(newHeight !== domNode.offsetHeight) {
|
||||
domNode.style.height = newHeight + "px";
|
||||
|
||||
@@ -82,11 +82,6 @@ var TW_Style = function(el) {
|
||||
// Return a Proxy to handle direct access to individual style properties
|
||||
return new Proxy(styleObject, {
|
||||
get: function(target, property) {
|
||||
// Real CSSStyleDeclaration returns undefined for non-string keys.
|
||||
// Guards against crashes when consumers probe Symbol.toPrimitive etc.
|
||||
if(typeof property !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
// If the property exists on styleObject, return it (get, set, setProperty methods)
|
||||
if(property in target) {
|
||||
return target[property];
|
||||
@@ -95,10 +90,6 @@ var TW_Style = function(el) {
|
||||
return el._style[$tw.utils.convertStyleNameToPropertyName(property)] || "";
|
||||
},
|
||||
set: function(target, property, value) {
|
||||
// Mirror the get trap: ignore non-string keys instead of crashing.
|
||||
if(typeof property !== "string") {
|
||||
return true;
|
||||
}
|
||||
// Set the property in _style
|
||||
el._style[$tw.utils.convertStyleNameToPropertyName(property)] = value;
|
||||
return true;
|
||||
|
||||
@@ -125,12 +125,13 @@ SelectWidget.prototype.setSelectValue = function() {
|
||||
values = Array.isArray(value) ? value : $tw.utils.parseStringArray(value);
|
||||
for(var i=0; i < select.children.length; i++){
|
||||
child=select.children[i];
|
||||
if(child.tagName && child.tagName.toUpperCase() === "OPTGROUP"){
|
||||
if(child.children.length === 0){
|
||||
child.selected = values.indexOf(child.value) !== -1;
|
||||
} else {
|
||||
// grouped options
|
||||
for(var y=0; y < child.children.length; y++){
|
||||
child.children[y].selected = values.indexOf(child.children[y].value) !== -1;
|
||||
}
|
||||
} else {
|
||||
child.selected = values.indexOf(child.value) !== -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/library/v5.4.1/index.html
|
||||
url: https://tiddlywiki.com/library/v5.4.0/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}}
|
||||
|
||||
{{$:/language/OfficialPluginLibrary/Hint}}
|
||||
|
||||
@@ -11,7 +11,6 @@ ja-title: TiddlyWikiアーカイブ
|
||||
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.4.0
|
||||
\end
|
||||
|
||||
TiddlyWikiの古いバージョンは[[アーカイブ|https://github.com/TiddlyWiki/tiddlywiki.com-gh-pages/tree/master/archive]]で入手できます:
|
||||
|
||||
@@ -21,5 +21,3 @@ type: text/vnd.tiddlywiki
|
||||
<<.tip """上に示したように、図に開始線と終了線が1つある場合は、リンクされた上位レベルにさらに情報があることを意味します。パンくずリストはナビゲーションに使用できます""">>
|
||||
|
||||
<<.tip """下位レベルで使用されているように、図に開始点と終了点がない場合は、読みやすさと単純さを高めるために、上位レベルのシンタックス要素が削除されていることを意味します。パンくずリストはナビゲーションに使用できます""">>
|
||||
|
||||
<<.note """フィルタ式の再帰深度は最大300です。この制限を超えて自身を再帰的に呼び出すフィルタ(例えば、<<.olink subfilter>>や<<.olink filter>>演算子を使ったもの)は、エラーメッセージ`/**-- Excessive filter recursion --**/`を返します。これは無限ループを防ぐためです。""">>
|
||||
|
||||
@@ -14,8 +14,6 @@ type: text/vnd.tiddlywiki
|
||||
"{" [: <-"間接"-> /"}以外"/] "}"
|
||||
|
|
||||
"<" [: <-"変数"-> /">以外"/] ">"
|
||||
|
|
||||
"(" [: <-"複数値変数"-> /")以外"/ ] ")" /"v5.4.0"/
|
||||
)
|
||||
"""/>
|
||||
|
||||
@@ -24,7 +22,6 @@ type: text/vnd.tiddlywiki
|
||||
;<<.def ハード>>
|
||||
: `[パラメータ例]`
|
||||
: パラメータは、角括弧内のテキストそのものです。
|
||||
|
||||
;<<.def ソフト>>
|
||||
: <<.def 間接>>
|
||||
:: `{パラメータ例}`
|
||||
@@ -33,9 +30,6 @@ type: text/vnd.tiddlywiki
|
||||
:: `<パラメータ例>`
|
||||
:: パラメータは、山括弧内の[[変数|Variables]]の現在値です。マクロパラメータは、v5.2.0まではサポートされて<<.em いません>>。
|
||||
::<<.from-version "5.2.0">> リテラルマクロパラメータがサポートされています。例: `[<now [UTC]YYYY0MM0DD0hh0mm0ssXXX>]`。
|
||||
: <<.def "複数値変数">>
|
||||
:: `(パラメータ例)`
|
||||
:: <<.from-version "5.4.0">> このパラメータは、丸括弧で囲まれた名前の[[複数値変数|Multi-Valued Variables]]に格納されている値のリスト全体に展開されます。このようにアクセスすると、フィルタ演算子は最初の値だけでなく、すべての値を受け取ります。詳細については、[[複数値変数|Multi-Valued Variables]]を参照してください。
|
||||
|
||||
<<.note """すべての[[フィルタオペレータ|filter Operator]]の後にはパラメータ式が続く必要があります。[[パラメータの無いオペレータ|Operators without parameters]]の場合、その式は空になります(`[<currentTiddler>links[]]`のフィルタオペレータ<<.olink links>>と同様)。""">>
|
||||
|
||||
@@ -43,8 +37,4 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.23">> [[フィルタステップ|Filter Step]]では、`,`文字で区切られた複数のパラメータがサポートされます。
|
||||
|
||||
例えば: `[param1],[param2]`や`<param1>,{param2}`、 `[param1],(param2)`
|
||||
|
||||
---
|
||||
|
||||
<<.warning """`/regexp/(flags)`オペランド構文は非推奨であり、ブラウザのコンソールに警告が表示されます。代わりに<<.olink regexp>>演算子を使用してください。""">>
|
||||
例えば: `[param1],[param2]`や`<param1>,{param2}`
|
||||
|
||||
@@ -24,13 +24,13 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
多くのステップでは、ステップの実行内容をさらに定義する明示的な<<.def パラメータ>>が必要です。
|
||||
|
||||
<<.def サフィックス>>は、特定のオペレータの意味を拡張する追加テキスト(多くの場合、[[フィールド|TiddlerFields]]名)です。サフィックスは`:`文字で区切られ、各サフィックスグループには、カンマで区切られた複数の値を含めることができます。例えば、`compare:number:gteq`は、最初のサフィックスは`number`で、2番目のサフィックスは`gteq`です。`:sort:string:reverse,casesensitive`は、最初のサフィックスは`string`で、2番目のサフィックスグループには`reverse`と`casesensitive`の両方が含まれます。
|
||||
<<.def サフィックス>>は、特定のオペレータの意味を拡張する追加テキスト(多くの場合、[[フィールド|TiddlerFields]]名)です。
|
||||
|
||||
ステップの<<.def オペレータ>>と<<.def サフィックス>>がすべて//省略//されている場合は、デフォルトで[[title|title Operator]]オペレータが使用されます。サフィックスが存在するが、コロンの前のオペレータ名が空の場合(例: `[:fieldname[value]]`)、オペレータはデフォルトで<<.olink field>>になります。
|
||||
ステップの<<.def オペレータ>>と<<.def サフィックス>>がすべて省略されている場合は、デフォルトで[[title|title Operator]]オペレータが使用されます。
|
||||
|
||||
<<.from-version "5.1.23">> いくつかのステップでは、`,`文字で区切られた複数の<<.def パラメータ>>を受け入れます。
|
||||
|
||||
認識されないオペレータは、<<.olink field>>オペレータのサフィックスであるかのように扱われます。<<.from-version "5.3.0">> ただし、名前に`.`(ドット)文字が含まれる認識されないオペレータは、ユーザー定義のフィルタオペレータとして扱われ、その名前の変数または関数を検索することで解決されます。.
|
||||
認識されないオペレータは、<<.olink field>>オペレータのサフィックスであるかのように扱われます。
|
||||
|
||||
フィルタオペレータはプラグインによって拡張できます。
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ type: text/vnd.tiddlywiki
|
||||
|`-[run]` |`:except[run]` |差集合 |... AND NOT ラン |
|
||||
|`~[run]` |`:else[run]` |それ以外 |... ELSE ラン |
|
||||
|`=[run]` |`:all[run]` |重複を排除しない和集合 |... OR ラン |
|
||||
|`=>[run]` |`:let[run]` |<<.from-version "5.4.0">> 結果を変数に割りあてる |... LET ラン |
|
||||
|
||||
ランのインプットは通常、Wiki内の[[隠し|ShadowTiddlers]]Tiddler以外のすべてのTiddlerタイトルのリストです(順不同)。<br>ただし、`+`プレフィックスによってこれを変更できます:
|
||||
|
||||
@@ -46,5 +45,3 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
新しいフィルタランプレフィックスを作成するには、`filterrunprefix`の[[モジュールタイプ|ModuleType]]で
|
||||
[[Javascriptモジュール|Modules]]を作成します。
|
||||
|
||||
コンパイルされたフィルタ式はパフォーマンスのためキャッシュされます。キャッシュには最大2000件のエントリが保存され、この制限を超えるとキャッシュ全体がリセットされます。
|
||||
@@ -17,15 +17,6 @@ type: text/vnd.tiddlywiki
|
||||
[["ラン"|"Filter Run"]]
|
||||
"""/>
|
||||
|
||||
前のランからのフィルタアウトプットは保留されます。`:intersection`フィルタランは、すべてのTiddlerタイトルをインプットとして開始されます。この最後のフィルタランが完了すると、最後のアウトプットが保留アウトプットと比較されます。保留アウトプットと最新アウトプットの両方に表われるタイトルのみを含む新しいアウトプットが生成されます。アウトプットにおけるタイトルの順序は、蓄積された結果から保持されます。
|
||||
|
||||
!! `:and` / `+`との違い
|
||||
|
||||
`:intersection`と`:and` (または `+`)の主な違いは、''インプット''として何を受け取るかです:
|
||||
|
||||
* `:and` / `+`は、''これまでに蓄積された結果''をフィルタランへのインプットとして渡します。ラン内のオペレータは、結果に既に含まれているタイトルのみを表示・操作できます。
|
||||
* `:intersection`は、''すべてのTiddlerタイトル''をフィルタランへのインプットとして渡し(プレフィックスなしのランと同様)、その後、蓄積された結果にも含まれるタイトルのみを保持します。
|
||||
|
||||
これは、`:intersection`がTiddlerプール全体から開始する必要のあるオペレータを使用してタイトルを照合できることを意味します。詳細については、[[交換可能なフィルタランプレフィックス|Interchangeable Filter Run Prefixes]]を参照してください。
|
||||
前のランからのフィルタアウトプットは保留されます。`:intersection`フィルタランは、すべてのTiddlerタイトルをインプットとして開始されます。この最後のフィルタランが完了すると、最後のアウトプットが保留アウトプットと比較されます。保留アウトプットと最新アウトプットの両方に表われるタイトルのみを含む新しいアウトプットが生成されます。
|
||||
|
||||
[[intersectionフィルタランプレフィックス(例)|Intersection Filter Run Prefix (Examples)]]
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
created: 20260222152853141
|
||||
modified: 20260506104906199
|
||||
original-modified: 20260222184916224
|
||||
tags: [[Let Filter Run Prefix]]
|
||||
title: Let Filter Run Prefix (Examples)
|
||||
ja-title: letフィルタランプレフィックス(例)
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.operator-example 1 "3 2 1 4 :let[[myvar]] 6 7 8 [(myvar)sort[]]" "名前付きプレフィックスを使用">>
|
||||
<<.operator-example 2 "3 2 1 4 =>myvar 6 7 8 [(myvar)sort[]]" "短縮形のプレフィックスを使用">>
|
||||
<<.operator-example 3 "3 2 1 4 =>myvar 6 7 8 [<myvar>]" "山括弧は最初の値のみを返却">>
|
||||
<<.operator-example 4 "3 2 1 4 =>mynumbers [(mynumbers)sum[]] [(mynumbers)average[]]">>
|
||||
<<.operator-example 5 '"[0-9]" =>digitsRE abc 123 de45 67fg hij :filter[regexp<digitsRE>]' "角括弧で囲まれた正規表現では、変数パラメータを使用">>
|
||||
<<.operator-example 6 '"[prefix[ca]then[ca]]" "[suffix[at]then[at]]" other =>myfilters cat can bat bug :cascade[(myfilters)]' "[[cascadeフィルタランプレフィックス|Cascade Filter Run Prefix]]で使用するフィルタを定義">>
|
||||
<<.operator-example 7 "[[⁎ ]] [[⁑ ]] [[⁂ ]] :let[[prefixList]] [tag[Learning]first[3]] :map:flat[(prefixList)addsuffix<currentTiddler>]">>
|
||||
@@ -1,32 +0,0 @@
|
||||
created: 20250307212252946
|
||||
from-version: 5.4.0
|
||||
modified: 20260502101033176
|
||||
original-modified: 20250307212252946
|
||||
rp-input: 前回のフィルタランからのすべてのタイトル
|
||||
rp-output: "let"フィルタランプレフィックスからはいつも空のタイトルリストが返されます
|
||||
rp-purpose: 前回のフィルタラン結果のタイトルリストを複数値変数へ代入
|
||||
tags: [[Named Filter Run Prefix]]
|
||||
title: Let Filter Run Prefix
|
||||
ja-title: letフィルタランプレフィックス
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<$railroad text="""
|
||||
\start none
|
||||
\end none
|
||||
( ":let" )
|
||||
[["ラン"|"Filter Run"]]
|
||||
"""/>
|
||||
|
||||
`:let`フィルタランプレフィックスは、前回のフィルタランの結果として得られたタイトルリストを[[他数値変数|Multi-Valued Variables]]に割り当てます。この変数には、フィルタランによって返された最初の結果が名前として付けられます。
|
||||
|
||||
この変数は、[[フィルタ式|Filter Expression]]内の残りの[[フィルタラン|Filter Run]]で使用可能になります。通常の方法で変数にアクセスすると、結果リストの最初の項目のみが返されます(結果リストが空の場合は空の文字列が返されます)。オペランドとして変数名を山括弧ではなく丸括弧で囲むと、結果リスト内のすべての項目が取得できます。
|
||||
|
||||
このプレフィックスには、オプションの[[ショートカット構文|Shortcut Filter Run Prefix]]記号`=>run`があります。例:
|
||||
|
||||
```
|
||||
=[<myfun1>] =[<myfun2>] =>myvar
|
||||
```
|
||||
|
||||
`:let`フィルタランプレフィックスを指定すると、常に現在の結果リストがクリアされます。
|
||||
|
||||
[[letフィルタランプレフィックス(例)|Let Filter Run Prefix (Examples)]]
|
||||
@@ -25,7 +25,6 @@ type: text/vnd.tiddlywiki
|
||||
[[<":or"> |"Or Filter Run Prefix"]] |
|
||||
[[<":reduce"> |"Reduce Filter Run Prefix"]] |
|
||||
[[<":sort"> /"v5.2.0"/ |"Sort Filter Run Prefix"]] |
|
||||
[[<":let"> /"v5.4.0"/ |"Let Filter Run Prefix"]] |
|
||||
[[<":then"> /"v5.3.0"/ |"Then Filter Run Prefix"]]) [[run|"Filter Run"]]
|
||||
"""/>
|
||||
|
||||
@@ -36,14 +35,4 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
<<.tip """フィルタランプレフィックス`:reduce`、`:sort`、`:map`、`:filter`内では、変数<<.var currentTiddler>>は処理中のTiddlerのタイトルに設定されます。<br>サブフィルタ外のcurrentTiddlerの値は、変数<<.var "..currentTiddler">>で使用できます <<.from-version "5.2.0">>""" >>
|
||||
|
||||
!! サフィックス
|
||||
|
||||
名前付きフィルタランプレフィックスは、`:`文字で区切られたサフィックスを受け入れることができ、各サフィックスにはオプションでカンマ区切りの値を含めることができます。一般的な構文は`:prefixname:suffix1:suffix2,...`です。現在、次のプレフィックスがサフィックスを受け入れます:
|
||||
|
||||
|!プレフィックス |!サフィッス |!例 |
|
||||
|`:map` |`flat` — 項目ごとに最初の結果だけでなく、すべての結果を返す |`:map:flat[...]` |
|
||||
|`:sort` |型 (''string'', ''alphanumeric'', ''number'', ''integer'', ''version'', ''date'')とフラグ (''reverse'', ''casesensitive'', ''caseinsensitive'') |`:sort:number:reverse[...]` |
|
||||
|
||||
その他の名前付きプレフィックス(`:all`, `:and`, `:cascade`, `:else`, `:except`, `:filter`, `:intersection`, `:let`, `:or`, `:reduce`, `:then`)は現在サフィックスを受け付けません。
|
||||
|
||||
参照: [[交換可能なフィルターランプレフィックス|Interchangeable Filter Run Prefixes]]
|
||||
|
||||
@@ -11,7 +11,7 @@ type: text/vnd.tiddlywiki
|
||||
<$railroad text="""
|
||||
\start none
|
||||
\end none
|
||||
(-|:"+"|"-"|"~"|"="|"=>")
|
||||
(-|:"+"|"-"|"~"|"=")
|
||||
[["ラン"|"Filter Run"]]
|
||||
"""/>
|
||||
|
||||
@@ -23,10 +23,8 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
* プレフィックス`-`は、アウトプットタイトルがフィルタのアウトプットから<<.em 取り除か>>れます(そのようなTiddlerが存在する場合)
|
||||
|
||||
* プレフィックス`~`<<.from-version "5.1.18">>は、フィルタアウトプットが空リストの場合、ランの結果のタイトルがフィルタアウトプットに[[優先的に追加|Dominant Append]]されます。フィルタアウトプットが空リストでない場合、ランは無視されます。
|
||||
* プレフィックス`~`は、フィルタアウトプットが空リストの場合、ランの結果のタイトルがフィルタアウトプットに[[優先的に追加|Dominant Append]]されます。フィルタアウトプットが空リストでない場合、ランは無視されます。<<.from-version "5.1.18">>
|
||||
|
||||
* プレフィックス`=`<<.from-version "5.1.20">>は、アウトプットタイトルが重複排除されずにフィルタのアウトプットに追加されます。
|
||||
|
||||
* プレフィックス`=>` <<.from-version "5.4.0">>は、これまでのすべてのランの累積結果は、このランの最初の結果が名前となる[[複数値変数|Multi-Valued Variables]]として割り当てられます。その後、累積結果はクリアされます。
|
||||
* プレフィックス`=`は、アウトプットタイトルが重複排除されずにフィルタのアウトプットに追加されます。<<.from-version "5.1.20">>
|
||||
|
||||
{{Interchangeable Filter Run Prefixes}}
|
||||
@@ -2,7 +2,7 @@ created: 20210618133745003
|
||||
from-version: 5.3.0
|
||||
modified: 20250423104147235
|
||||
original-modified: 20230710074225410
|
||||
rp-input: <<.olink all>>のTiddlerタイトル (前回のランのアウトプットが空でない場合にのみ評価されます)
|
||||
rp-input: <<.olink すべて>>のTiddlerタイトル
|
||||
rp-output: フィルタランのアウトプットは、空のリストでない限り、前回までのランのアウトプットを置き換えます(以下を参照)。
|
||||
rp-purpose: フィルタランへのインプットをそのアウトプットで置き換え、インプットがある場合にのみランを評価
|
||||
search:
|
||||
|
||||
@@ -20,9 +20,8 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
関数はいくつかの方法で呼び出すことができます:
|
||||
|
||||
* [[Calls]]構文を使用する:
|
||||
** 構文 `<<myfun param:"value">>` を使用して関数を直接トランスクルードする
|
||||
** 構文 `<div class=<<myfun param:"value">>>` を使用してウィジェット属性に関数を割り当てる
|
||||
* 構文 `<<myfun param:"value">>` を使用して関数を直接トランスクルードする
|
||||
* 構文 `<div class=<<myfun param:"value">>>` を使用してウィジェット属性に関数を割り当てる
|
||||
* 構文 `[function[myfun],[value],...]` を使用して [[関数オペレータ|function Operator]] を介して関数を呼び出す
|
||||
* 構文 `[my.fun[value]]` または `[.myfun[value]]` で、カスタムフィルター演算子として名前にピリオドが含まれる関数を直接呼び出す
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
caption: Internet Explorer
|
||||
created: 20140811172058274
|
||||
modified: 20241029105938082
|
||||
original-modified: 20211114031651879
|
||||
tags: GettingStarted $:/deprecated
|
||||
title: GettingStarted - Internet Explorer
|
||||
ja-title: はじめに - Internet Explorer
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
{{Saving with TiddlyIE}}
|
||||
|
||||
The [[Windows HTA Hack]] describes an alternative method of using TiddlyWiki with Internet Explorer.
|
||||
[[Windows HTAのハック|Windows HTA Hack]]では、Internet ExplorerでTiddlyWikiを使用する別の方法について説明します。
|
||||
@@ -1,8 +1,8 @@
|
||||
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: 20260430010447598
|
||||
original-modified: 20260420192600833
|
||||
modified: 20251213104120189
|
||||
original-modified: 20250807084952911
|
||||
tags: Welcome
|
||||
title: HelloThere
|
||||
ja-title: こんにちは
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20150414070451144
|
||||
list: [[HelloThumbnail - Latest Version]] [[HelloThumbnail - Donations]] [[HelloThumbnail - Newsletter]] [[HelloThumbnail - Community Survey 2025]] [[HelloThumbnail - Introduction Video]] [[HelloThumbnail - Grok TiddlyWiki]] [[HelloThumbnail - MultiWikiServer]] [[HelloThumbnail - Twenty Years of TiddlyWiki]] [[HelloThumbnail - TiddlyWiki Privacy]] [[HelloThumbnail - Marketplace]] [[HelloThumbnail - Intertwingled Innovations]] [[HelloThumbnail - TiddlyWikiLinks]]
|
||||
list: list: [[HelloThumbnail - Donations]] [[HelloThumbnail - Newsletter]] [[HelloThumbnail - Community Survey 2025]] [[HelloThumbnail - Introduction Video]] [[HelloThumbnail - Grok TiddlyWiki]] [[HelloThumbnail - Latest Version]] [[HelloThumbnail - MultiWikiServer]] [[HelloThumbnail - Twenty Years of TiddlyWiki]] [[HelloThumbnail - TiddlyWiki Privacy]] [[HelloThumbnail - Marketplace]] [[HelloThumbnail - Intertwingled Innovations]] [[HelloThumbnail - TiddlyWikiLinks]]
|
||||
modified: 20260406043045066
|
||||
original-modified: 20150414070948246
|
||||
title: HelloThumbnail
|
||||
|
||||
@@ -5,7 +5,6 @@ caption: v<<version>>の新着情報
|
||||
link: Releases
|
||||
image: New Release Banner
|
||||
color: #fff
|
||||
ribbon-text: NEW
|
||||
|
||||
\define prerelease-regexp() [0-9]+\.[0-9]+\.[0-9]+\-prerelease
|
||||
<$list filter="[<version>!regexp<prerelease-regexp>]" variable="ignore">
|
||||
|
||||
@@ -6,5 +6,6 @@ link: TiddlyWiki Newsletter
|
||||
image: TiddlyWiki Newsletter Badge
|
||||
color: #fff
|
||||
type: text/vnd.tiddlywiki
|
||||
ribbon-text: NEW
|
||||
|
||||
~TiddlyWikiコミュニティからの最も興味深く関連性のあるニュースをまとめた~TiddlyWikiニュースレターを購読できます
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
caption: HTA Hack
|
||||
color: #F06292
|
||||
created: 20131212223146250
|
||||
delivery: DIY
|
||||
description: Internet Explorerで変更を手動で直接保存する方法
|
||||
method: save
|
||||
modified: 20241012122755089
|
||||
original-modified: 20200507110355115
|
||||
tags: Saving Windows $:/deprecated
|
||||
title: Windows HTA Hack
|
||||
ja-title: Windows HTAのハック
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.deprecated-since "5.3.6">>
|
||||
Windowsでは、HTMLファイルの拡張子を`*.hta`に名前変更することで、TiddlyWikiを真のローカルアプリケーションに変換できます。その後、''fsosaver''モジュールは~ActiveX ~FileSystemObjectを使用して変更を保存できます。
|
||||
|
||||
この方法の欠点の1つは、TiddlyWikiファイルがUTF-16フォーマットで保存されるため、通常のUTF-8エンコードの場合と比べて2倍の大きさになることです。ただし、別の保存方法でファイルを開いて保存すると、ファイルはUTF-8に再エンコードされます。
|
||||
|
||||
詳細については、Wikipediaを参照してください: https://en.wikipedia.org/wiki/HTML_Application
|
||||
@@ -1,9 +1,58 @@
|
||||
caption: プロシージャ呼び出し
|
||||
created: 20221007130006705
|
||||
modified: 20260429105903754
|
||||
original-modified: 20260125212303316
|
||||
modified: 20260327114525571
|
||||
original-modified: 20230419103154329
|
||||
tags: WikiText Procedures
|
||||
title: Procedure Calls
|
||||
ja-title: プロシージャ呼び出し
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.deprecated-since "5.4.0" "Calls">>
|
||||
!! 紹介
|
||||
|
||||
このTiddlerでは、[[プロシージャ|Procedures]]を呼び出すさまざまな方法について説明します。
|
||||
|
||||
!! トランスクルージョンショートカットでのプロシージャ呼び出し
|
||||
|
||||
[[プロシージャ|Procedures]]を呼び出すには、プロシージャ名とパラメータ値を`<<`二重の山括弧で囲みます`>>`。
|
||||
|
||||
```
|
||||
<<my-procedure param:"これはパラメータ値です">>
|
||||
```
|
||||
|
||||
デフォルトでは、パラメータはプロシージャの定義と同じ順序でリストされます。パラメータに名前とコロンを付けることで、異なる順序でリストすることができます。
|
||||
|
||||
パラメータに値が指定されていない場合は、[[プロシージャ定義|Procedure Definitions]]でそのパラメータに指定されているデフォルト値が使用されます。(デフォルト値が定義されていない場合は、パラメータは空白になります。)
|
||||
|
||||
各パラメータ値は、`'`シングルクォーテーション`'`、`"`ダブルクォーテーション`"`、`"""`三重のダブルクォーテーション`"""`、`[[`二重の角括弧`]]`で囲むことができます。三重のダブルクォーテーションを使用すると、値にほぼあらゆる文字列を含めることができます。値にスペース、シングルクォーテーション、ダブルクォーテーションが含まれていない場合は、区切り文字は不要です。
|
||||
|
||||
[[パーサーモード|WikiText parser mode: macro examples]]に関する議論を参照してください。
|
||||
|
||||
!! <<.wlink TranscludeWidget>>ウィジェットでのプロシージャ呼び出し
|
||||
|
||||
ショートカット構文は、トランスクルードするプロシージャの名前を指定する`$variable`属性を持つ<<.wlink TranscludeWidget>>ウィジェットに展開されます。
|
||||
|
||||
```
|
||||
<$transclude $variable="my-procedure" param="これはパラメータ値です"/>
|
||||
```
|
||||
|
||||
ウィジェットは、ショートカット構文よりも柔軟性が高く、動的なパラメータ値を指定することも可能です。
|
||||
|
||||
!! 属性値にプロシージャ呼び出しを割り当て
|
||||
|
||||
プロシージャテキストは、ウィジェットやHTML要素の属性に直接割り当てることができます。プロシージャの結果はWiki化されないため、[[パラメータ処理|Procedure Parameter Handling]]は行われません。
|
||||
|
||||
```
|
||||
<div class=<<myclasses>>>
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
!! フィルタでのプロシージャ呼び出しの使用
|
||||
|
||||
プロシージャ呼び出しはフィルタ内で使用できます。テキストはWiki化されないため、パラメータは無視されます。
|
||||
|
||||
```
|
||||
<$list filter="[<my-procedure>]">
|
||||
...
|
||||
</$list>
|
||||
```
|
||||
@@ -1,66 +0,0 @@
|
||||
caption: 呼び出し
|
||||
created: 20221007130006705
|
||||
modified: 20260429224543285
|
||||
original-modified: 20260301030947969
|
||||
tags: WikiText Procedures Functions Macros
|
||||
title: Calls
|
||||
ja-title: 呼び出し
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
!! 紹介
|
||||
|
||||
このTiddlerでは、[[プロシージャ|Procedures]]、[[関数|Functions]]、[[マクロ|Macros]]を呼び出すさまざまな方法について説明します。構文の正式な説明については、[[呼び出し構文|Call Syntax]]を参照してください。
|
||||
|
||||
!! トランスクルージョンショートカットでの呼び出し
|
||||
|
||||
呼び出しを実行するには、呼び出し先の名前とパラメータ値を`<<`二重の山括弧で囲みます`>>`。
|
||||
|
||||
```
|
||||
<<my-procedure param:"これはパラメータ値です">>
|
||||
```
|
||||
|
||||
デフォルトでは、パラメータは定義と同じ順序で解釈されます。パラメータ値に名前と等号を付けることで、異なる順序でリストすることができます。
|
||||
|
||||
パラメータに値が指定されていない場合は、[[プロシージャ定義|Procedure Definitions]]、[[関数定義|Function Definitions]]、[[マクロ定義|Macro Definitions]]でそのパラメータに指定されているデフォルト値が使用されます。(デフォルト値が定義されていない場合は、パラメータは空白になります。)
|
||||
|
||||
各パラメータ値は、`'`シングルクォーテーション`'`、`"`ダブルクォーテーション`"`、`"""`三重のダブルクォーテーション`"""`、`[[`二重の角括弧`]]`で囲むことができます。三重のダブルクォーテーションを使用すると、値にほぼあらゆる文字列を含めることができます。値にスペース、シングルクォーテーション、ダブルクォーテーションが含まれていない場合は、区切り文字は不要です。シングルクォーテーション、または、三重のバッククォーテーションで囲まれた[[置換属性値|Substituted Attribute Values]]もサポートされています。
|
||||
|
||||
[[パーサーモード|WikiText parser mode: macro examples]]に関する議論を参照してください。
|
||||
|
||||
!!! 例
|
||||
|
||||
<<testcase TestCases/Calls/ProcedureStaticAttributes>>
|
||||
|
||||
<<testcase TestCases/Calls/ProcedureDynamicAttributes>>
|
||||
|
||||
!! <<.wlink TranscludeWidget>>ウィジェットを用いた呼び出し
|
||||
|
||||
ショートカット構文は、トランスクルードするプロシージャの名前を指定する`$variable`属性を持つ<<.wlink TranscludeWidget>>ウィジェットに展開されます。
|
||||
|
||||
```
|
||||
<$transclude $variable="my-procedure" param="これはパラメータ値です"/>
|
||||
```
|
||||
|
||||
ウィジェットは、ショートカット構文よりも柔軟性が高く、カスタムウィジェットで上書きすることも可能です。
|
||||
|
||||
!! 呼び出し結果を属性値に割り当てる
|
||||
|
||||
呼び出しから返されるテキストは、ウィジェットやHTML要素の属性に直接割り当てることができます。呼び出しの結果はWiki化されないため、[[パラメータ処理|Procedure Parameter Handling]]は行われません。
|
||||
|
||||
```
|
||||
<div class=<<myclasses>>>
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
!! フィルタでの呼び出しの使用
|
||||
|
||||
呼び出しはフィルタ内で使用できます。テキストはWiki化されないため、パラメータは無視されます。
|
||||
|
||||
//現在サポートされているのはリテラル文字列パラメータのみであることに注意してください//
|
||||
|
||||
```
|
||||
<$list filter="[<my-procedure>]">
|
||||
...
|
||||
</$list>
|
||||
```
|
||||
@@ -1,12 +1,12 @@
|
||||
created: 20130825160900000
|
||||
modified: 20260430074718157
|
||||
original-modified: 20250617140259415
|
||||
modified: 20251214105948181
|
||||
original-modified: 20241106165307259
|
||||
tags: Features [[Working with TiddlyWiki]]
|
||||
title: Encryption
|
||||
ja-title: 暗号化
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TiddlyWiki5を単一のHTMLファイルとして使用すると、[[Stanford JavaScript Crypto Library]]を使用してCCMモードのAES 256ビット暗号化でコンテンツを暗号化できます。
|
||||
TiddlyWiki5を単一のHTMLファイルとして使用すると、[[Stanford JavaScript Crypto Library]]を使用してCCMモードのAES 128ビット暗号化でコンテンツを暗号化できます。
|
||||
|
||||
# サイドバーの''ツール''タブに切り替えて、南京錠アイコンのボタンを探します
|
||||
# ボタンに<<.icon $:/core/images/unlocked-padlock>> ''パスワードの設定''と表示されている場合、現在のウィキは暗号化されていません。ボタンをクリックすると、以降の保存を暗号化するために使用されるパスワードの入力を求められます
|
||||
@@ -16,5 +16,5 @@ TiddlyWiki5を単一のHTMLファイルとして使用すると、[[Stanford Jav
|
||||
|
||||
TiddlyWikiには、パスワード/暗号化に関連する、2つの無関係な機能があることに注意してください:
|
||||
|
||||
* [[Tiddlyhost]]に保存するときにパスワードを設定する機能。これは、''コントロールパネル'' <<.icon $:/core/images/options-button>>の"保存"タブで行います。
|
||||
* [[Node.js|TiddlyWiki on Node.js]]のサーバ構成で標準のHTTP基本認証を使用する機能。これは、[[Listenコマンド|ListenCommand]]を使用してコマンドラインで実行されます。SSLと組み合わせると、GoogleやDropboxなどのオンラインサービスで得られるのと同じレベルの暗号化転送が実現されますが、ディスク上のデータは暗号化されません
|
||||
* TiddlySpotに保存するときにパスワードを設定する機能。これは、''コントロールパネル'' <<.icon $:/core/images/options-button>>の"保存"タブで行います。
|
||||
* [[Node.js|TiddlyWiki on Node.js]]のサーバ構成で標準のHTTP基本認証を使用する機能。これは、ServerCommandを使用してコマンドラインで実行されます。SSLと組み合わせると、GoogleやDropboxなどのオンラインサービスで得られるのと同じレベルの暗号化転送が実現されますが、ディスク上のデータは暗号化されません
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
caption: ~TiddlyIE
|
||||
color: #4DB6AC
|
||||
community-author: David Jade
|
||||
created: 20131211220000000
|
||||
delivery: Browser Extension
|
||||
description: Internet Explorer用のブラウザ拡張
|
||||
method: save
|
||||
modified: 20241009114650356
|
||||
original-modified: 20200507201415232
|
||||
tags: [[Internet Explorer]] Saving $:/deprecated
|
||||
title: Saving with TiddlyIE
|
||||
ja-title: TiddlyIEでの保存
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.deprecated-since "5.3.6">>
|
||||
# TiddlyIEアドオンを次の場所からインストールします:
|
||||
#* https://github.com/davidjade/TiddlyIE/releases
|
||||
# Internet Explorerを再起動します。IEはTiddlyIEアドオンを有効にするように要求します。
|
||||
#> //Microsoft Script Runtime//を有効にするプロンプトが表示される場合もあります。
|
||||
# 次のリンクを[[ダウンロード|Download]]し、空のTiddlyWikiを保存します:
|
||||
#> https://tiddlywiki.com/empty.html
|
||||
# ダウンロードしたファイルを見つけます
|
||||
#* ファイル名を変更することもできますが、拡張子`.html`か`.htm`はそのままとしてください
|
||||
# Internet Explorerでファイルを開きます
|
||||
# サイドバーの''新しいTiddlerを作成します'' <<.icon $:/core/images/new-button>>ボタンを使用して、新しいTiddlerを作成してみてください。Tiddlerのコンテンツを入力し、<<.icon $:/core/images/done-button>> ''編集内容を確定します''ボタンをクリックします
|
||||
# サイドバーの<<.icon $:/core/images/save-button-dynamic>> ''Wikiを保存します''ボタンをクリックして変更を保存します。Internet Explorerは、''名前を付けて保存''ダイアログを表示して、ファイルをローカルに保存することに同意するかどうかを確認します。
|
||||
# ブラウザウィンドウを更新して、変更が正しく保存されたことを確認してください
|
||||
|
||||
+2
-4
@@ -3,13 +3,11 @@ modified: 20260404110322627
|
||||
original-modified: 20240619210723396
|
||||
tags: [[Variable Usage]]
|
||||
title: Behaviour of variables invoked via widget attributes
|
||||
ja-title: ウィジェット属性を介して呼び出される変数の動作
|
||||
ja-title:
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
|tc-first-col-min-width|k
|
||||
|!宣言方法|!動作|
|
||||
|\define|本文テキストに対してパラメータのテキスト置換が実行されます。それ以上の処理は行われません。テキスト置換後の結果が属性の値として使用されます|
|
||||
|<<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget|本文はそのまま取得され、属性の値として使用されます|
|
||||
|\function|ファンクション(例: .myfun)が`<div class=<<.myfun>>/>`で呼び出されると、`<div class={{{[function[.myfun]]}}}/>`の同義になります。他のフィルタ付きトランスクルージョン(つまり、三重中括弧)と同様に、最初の結果以外はすべて破棄されます。最初の結果が属性の値として使用されます。この形式で呼び出された場合でも、ファンクションは再帰的に処理されることに注意してください。つまり、ファンクション内のフィルタ式は別のファンクションを呼び出すことができ、処理は継続されます|
|
||||
|
||||
<<.from-version "5.4.0">> `<<var>>`の代わりに[[複数値変数の属性|Multi-Valued Variable Attribute Values]]構文`((var))`を使用すると、最初の値だけでなく、値のリスト全体が属性に渡されます。これは主に、TranscludeWidgetを介して[[複数値変数|Multi-Valued Variables]]をプロシージャや関数のパラメーターに渡す場合に便利です。
|
||||
|\function|ファンクション(例: .myfun)が`<div class=<<.myfun>>/>`で呼び出されると、`<div class={{{[function[.myfun]]}}}/>`の同義になります。他のフィルタ付きトランスクルージョン(つまり、三重中括弧)と同様に、最初の結果以外はすべて破棄されます。最初の結果が属性の値として使用されます。この形式で呼び出された場合でも、ファンクションは再帰的に処理されることに注意してください。つまり、ファンクション内のフィルタ式は別のファンクションを呼び出すことができ、処理は継続されます|
|
||||
@@ -1,46 +1,16 @@
|
||||
caption: 説明リスト
|
||||
created: 20131205160424246
|
||||
modified: 20260409111112126
|
||||
original-modified: 20260405082055301
|
||||
modified: 20260221103246354
|
||||
original-modified: 20251229110936191
|
||||
tags: WikiText
|
||||
title: Description Lists in WikiText
|
||||
ja-title: Wikiテキストでの説明リスト
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
!! 基本的な構文
|
||||
|
||||
HTML説明リスト(<abbr title="またの名を">別名</abbr> 定義リスト)は次の構文で作成できます:
|
||||
|
||||
<<wikitext-example src:"; 説明する用語
|
||||
: その用語の説明/定義
|
||||
; 別の用語
|
||||
: 別の説明/定義
|
||||
">>
|
||||
|
||||
!! 複数の用語と説明
|
||||
|
||||
1つの用語に対して複数の説明を作成することも、1つの説明に対して複数の用語を作成することもできます:
|
||||
|
||||
<<wikitext-example src:"; ねずみ
|
||||
: 体が小さく尾が長い齧歯類
|
||||
: コンピュータを操作するために使用するポインティングデバイス
|
||||
; りんご
|
||||
; なし
|
||||
: バラ科に属する果物の一種
|
||||
">>
|
||||
|
||||
!! 入れ子になった説明リスト
|
||||
|
||||
説明リストはネストして、リストの中にリストを作成することもできます:
|
||||
|
||||
<<wikitext-example src:"; コーヒー
|
||||
: 焙煎したコーヒー豆から作られた飲み物
|
||||
:; ブラックコーヒー
|
||||
:: 添加物を一切使用しないコーヒー
|
||||
:; ミルクコーヒー
|
||||
:: コーヒーにスチームミルクやフォームミルクを加えたもの
|
||||
::; ラテ
|
||||
::: エスプレッソとスチームミルクで作ったコーヒー
|
||||
; ティー
|
||||
: 一般的に茶葉から作られる飲み物
|
||||
">>
|
||||
">>
|
||||
@@ -40,7 +40,7 @@ type: text/vnd.tiddlywiki
|
||||
|`__下線テキスト__`には二重アンダースコアを使用します|`<u>下線テキスト<u>` |
|
||||
|`^^上付き文字^^`テキストには二重サーカムフレックスアクセントを使用します |`<sup>上付き文字</sup>`テキストには二重サーカムフレックスアクセントを使用します |
|
||||
|`,,下付き文字,,`テキストには二重カンマを使用します |`<sub>下付き文字</sub>`テキストには二重カンマを使用します |
|
||||
|`~~取り消し線~~`テキストには二重チルダ記号を使用します |`<s>取り消し線</s>`テキストには二重チルダ記号を使用します |
|
||||
|`~~取り消し線~~`テキストには二重チルダ記号を使用します |`<strike>取り消し線</strike>`テキストには二重チルダ記号を使用します |
|
||||
|```等幅文字` ``には単一のバッククォートを使用します |`<code>等幅文字</code>`には単一のバッククォートを使用します |
|
||||
|`@@ハイライト@@`するには二重@記号を使用します |`<span class="tc-inline-style">ハイライト</span>`するには二重@記号を使用します |
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
caption: リスト
|
||||
created: 20131205160257619
|
||||
modified: 20260409112505342
|
||||
original-modified: 20260405094604397
|
||||
modified: 20260225114001626
|
||||
original-modified: 20160607093103220
|
||||
tags: WikiText Lists
|
||||
title: Lists in WikiText
|
||||
ja-title: Wikiテキストでのリスト
|
||||
@@ -45,10 +45,6 @@ type: text/vnd.tiddlywiki
|
||||
#** そしてもう一つ
|
||||
">>
|
||||
|
||||
! 説明リスト
|
||||
|
||||
{{Description Lists in WikiText}}
|
||||
|
||||
! CSSクラス
|
||||
|
||||
次の表記法を使用して、リストの個々のメンバーにCSSクラスを割り当てることもできます:
|
||||
|
||||
@@ -2,8 +2,59 @@ caption: マクロ呼び出し
|
||||
created: 20150220182252000
|
||||
modified: 20260321104805874
|
||||
original-modified: 20230419103154328
|
||||
tags: WikiText Macros
|
||||
title: Macro Calls
|
||||
ja-title: マクロ呼び出し
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.deprecated-since "5.4.0" "Calls">>
|
||||
!! 紹介
|
||||
|
||||
このTiddlerでは、[[マクロ|Macros]]を呼び出すさまざまな方法について説明します。
|
||||
|
||||
!! マクロ呼び出しトランスクルージョンのショートカット
|
||||
|
||||
[[マクロ|Macros]]を呼び出すには、マクロ名とパラメータ値を`<<`二重山括弧`>>`で囲みます。
|
||||
|
||||
```
|
||||
<<mymacro param:"これはパラメータ値です">>
|
||||
```
|
||||
|
||||
デフォルトでは、パラメータはマクロの定義と同じ順序でリストします。パラメータに名前とコロンを付けることで、異なる順序でリストすることも可能です。
|
||||
|
||||
パラメータに値が指定されていない場合は、[[マクロ定義|Macro Definitions]]でそのパラメータに指定されているデフォルト値が代わりに使用されます。(デフォルト値が定義されていない場合は、パラメータはブランクになります。)
|
||||
|
||||
各パラメータ値は、`'`シングルクォーテーション`'`、`"`ダブルクォーテーション`"`、`"""`三重ダブルクォーテーション`"""`、または`[[`二重角括弧`]]`で囲むことができます。三重ダブルクォーテーションを使用すると、値にほぼあらゆる文字列を含めることができます。値にスペース、シングルクォーテーション、ダブルクォーテーションが含まれていない場合は、区切り文字は必要ありません。
|
||||
|
||||
この構文の正式な[[説明|Macro Call Syntax]]も利用可能です。
|
||||
|
||||
[[パーサーモード|WikiText parser mode: macro examples]]に関する[[例|Macro Calls in WikiText (Examples)]]と議論を参照してください。
|
||||
|
||||
!! <<.wlink TranscludeWidget>>ウィジェットを用いたマクロ呼び出し
|
||||
|
||||
ショートカット構文は、トランスクルードするマクロの名前を指定する`$variable`属性を持つ<<.wlink TranscludeWidget>>ウィジェットに展開されます。
|
||||
|
||||
```
|
||||
<$transclude $variable="mymacro" param="これはパラメータ値です"/>
|
||||
```
|
||||
|
||||
ウィジェット自体は、パラメータ値を指定できるなど、ショートカット構文よりも柔軟です。
|
||||
|
||||
!! 属性値にマクロ呼び出しを割り当てる
|
||||
|
||||
マクロの実行結果は、ウィジェットやHTML要素の属性に割り当てることができます。マクロの実行結果はWiki変換されませんが、[[パラメータの置換|Macro Parameter Handling]]は実行されます。
|
||||
|
||||
```
|
||||
<div class=<<myclasses "Horizontal">>>
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
!! フィルターでマクロ呼び出しを使用する
|
||||
|
||||
マクロ呼び出しはフィルタ内で使用できます:
|
||||
|
||||
```
|
||||
<$list filter="[<mymacro param:'value'>]">
|
||||
...
|
||||
</$list>
|
||||
```
|
||||
@@ -1,39 +0,0 @@
|
||||
created: 20250208120000000
|
||||
modified: 20260507110511201
|
||||
original-modified: 20250208120000000
|
||||
tags: WikiText [[Widget Attributes]]
|
||||
title: Multi-Valued Variable Attribute Values
|
||||
ja-title: 複数値変数の属性値
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.4.0">> 複数値変数の属性値は、変数名を二重の丸括弧で囲むことで指定できるようになりました。これにより、[[複数値変数|Multi-Valued Variables]]の最初の値だけでなく、すべての値が属性に渡されます。
|
||||
|
||||
```
|
||||
<$transclude $variable="myproc" items=((myvar))/>
|
||||
```
|
||||
|
||||
これは、下位互換性のために最初の値のみを返す[[変数の属性値|Variable Attribute Values]]構文`<<var>>`の複数値版です。この関係は、`<var>`が単一の値を返し、`(var)`がすべての値を返すフィルタオペランドの既存の慣例を反映しています。
|
||||
|
||||
! 複数値変数非対応の属性
|
||||
|
||||
`((var))`が複数値変数をサポートしていないウィジェット属性([[textウィジェット|TextWidget]]の`text`属性など)で使用される場合、最初の値のみが使用されます:
|
||||
|
||||
```
|
||||
<$text text=((myvar))/>
|
||||
```
|
||||
|
||||
! プロシージャに複数値変数を渡す
|
||||
|
||||
この構文の主なユースケースは、複数の値を持つ変数を`$transclude`パイプラインを通してプロシージャや関数に渡すことです:
|
||||
|
||||
```
|
||||
\procedure showItems(itemList)
|
||||
<$text text={{{ [(itemList)join[-]] }}}/>
|
||||
\end
|
||||
|
||||
<$let items={{{ [all[tiddlers]sort[]] }}}>
|
||||
<$transclude $variable="showItems" itemList=((items))/>
|
||||
</$let>
|
||||
```
|
||||
|
||||
この例では、`items`に格納されているTiddlerタイトルの完全なリストが`showItems`プロシージャの`itemList`パラメータに渡されます。
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20220817153236691
|
||||
modified: 20260409114243582
|
||||
modified: 20260404112841923
|
||||
original-modified: 20221010074314452
|
||||
tags: [[Tables in WikiText]]
|
||||
title: Tables in WikiText CSS Utility Classes
|
||||
@@ -81,14 +81,3 @@ full-tiddler-widthである表に、左右の余白を追加するには、`tc-m
|
||||
| セル1|<$edit-text tiddler="$:/temp/test-table-input" tag="input" field="test"/> |
|
||||
|^ [[Tiddlerへのリンク|Link to a tiddler]]<br>さらに詳しい説明|<$edit-text tiddler="$:/temp/test-table-input" field="text"/> |
|
||||
""">>
|
||||
|
||||
!! 行スタイルを交互にした表
|
||||
|
||||
独自のスタイルシートを作成する必要があります。[[スタイルシートの使用|Using Stylesheets]]を参照してください。考え方は、`:nth-of-type(even/odd)`を使用してルールを作成することです。例:
|
||||
|
||||
```
|
||||
.myclass tbody tr:nth-of-type(even) { background-color: <<color tiddler-editor-fields-even>>; }
|
||||
.myclass tbody tr:nth-of-type(odd) { background-color: <<color tiddler-editor-fields-odd>>; }
|
||||
```
|
||||
|
||||
<<.note """~TiddlyWikiは、テーブルの行に`evenRow`クラスと`oddRow`クラスを自動的に適用します。ただし、これらのクラスの使用は推奨されません。行は'even'(想定とは逆)で始まり、ヘッダー、フッター、本文のいずれに表示されるかに関わらず、テーブルのすべての行は単一の結合された行セットとして扱われます。""">>
|
||||
@@ -66,28 +66,6 @@ or, when used with a template, `{{{ [tag[mechanism]]||TemplateTitle }}}` expands
|
||||
|
||||
<<.tip "//Internals//プラグインをインストールすると、生成されたウィジェットツリーをエディターのプレビューペインに表示できます">>
|
||||
|
||||
!! 複数値変数の表示
|
||||
|
||||
<<.from-version "5.4.0">> `((var))`構文をインラインで使用して、[[複数値変数|Multi-Valued Variables]]の値を、デフォルトではカンマとスペースで連結して表示できるようになりました:
|
||||
|
||||
```
|
||||
((myvar))
|
||||
((myvar||:))
|
||||
```
|
||||
|
||||
オプションの`||`区切り文字は、カスタムの区切り文字を指定します。
|
||||
|
||||
!! インラインフィルター表示
|
||||
|
||||
<<.from-version "5.4.0">> `(((filter)))`構文によりフィルタ式の結果をデフォルトではカンマとスペースで連結してインラインで表示します:
|
||||
|
||||
```
|
||||
((( [all[tiddlers]sort[]] )))
|
||||
((( [all[tiddlers]sort[]] ||: )))
|
||||
```
|
||||
|
||||
オプションの`||`区切り文字は、カスタムの区切り文字を指定します。これは、フィルタリングされたトランスクルージョン構文`{{{ }}}`に対応するインライン表示の表現です。
|
||||
|
||||
---
|
||||
|
||||
参照:
|
||||
|
||||
@@ -13,7 +13,6 @@ type: text/vnd.tiddlywiki
|
||||
* [[マクロ/変数のトランスクルージョン|Variable Attribute Values]]
|
||||
* [[フィルター式の結果として|Filtered Attribute Values]]
|
||||
* <<.from-version "5.3.0">> [[指定された文字列に対してフィルタと変数置換を実行した結果として|Substituted Attribute Values]]
|
||||
* <<.from-version "5.4.0">> [[複数値変数の参照として|Multi-Valued Variable Attribute Values]]
|
||||
|
||||
|属性タイプ|構文|h
|
||||
|リテラル |スペースを含まない値には、シングルクォーテーション、ダブルクォーテーション、トリプルクォーテーション、またはクォーテーションなし |
|
||||
@@ -21,9 +20,9 @@ type: text/vnd.tiddlywiki
|
||||
|変数 |マクロまたは変数呼び出しを囲む二重の山括弧 |
|
||||
|フィルタリング結果 |フィルター式を囲む三重の中括弧|
|
||||
|置換結果|置換処理を行うテキストの、単一または三重のバッククォート|
|
||||
|複数値変数 |変数名を囲む二重の丸括弧 |
|
||||
|
||||
<$list filter="[[Literal Attribute Values]] [[Transcluded Attribute Values]] [[Variable Attribute Values]] [[Filtered Attribute Values]] [[Substituted Attribute Values]] [[Multi-Valued Variable Attribute Values]]">
|
||||
|
||||
<$list filter="[[Literal Attribute Values]] [[Transcluded Attribute Values]] [[Variable Attribute Values]] [[Filtered Attribute Values]] [[Substituted Attribute Values]]">
|
||||
<$link><h1><$view tiddler=<<currentTiddler>> field=ja-title/></h1></$link>
|
||||
<$transclude mode="block"/>
|
||||
</$list>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/LocalPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: http://127.0.0.1:8080/prerelease/library/v5.4.1/index.html
|
||||
url: http://127.0.0.1:8080/prerelease/library/v5.4.0/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}} (Prerelease Local)
|
||||
|
||||
A locally installed version of the official ~TiddlyWiki plugin library at tiddlywiki.com for testing and debugging. //Requires a local web server to share the library//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/prerelease/library/v5.4.1/index.html
|
||||
url: https://tiddlywiki.com/prerelease/library/v5.4.0/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}} (Prerelease)
|
||||
|
||||
The prerelease version of the official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team.
|
||||
|
||||
@@ -7,7 +7,7 @@ const crossPlatformIndexPath = indexPath.replace(/^\/+/, "");
|
||||
|
||||
test("get started link", async ({ page }) => {
|
||||
// The tests can take a while to run
|
||||
const timeout = 1000 * 60;
|
||||
const timeout = 1000 * 30;
|
||||
test.setTimeout(timeout);
|
||||
|
||||
// Load the generated test TW html
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
/*\
|
||||
title: test-deprecated.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Regression-guard tests for $:/core/modules/utils/deprecated.js.
|
||||
|
||||
Locks in pre-5.4.0 tolerant behaviour of $tw.utils helpers that regressed
|
||||
in PR #9251 (one-line modern equivalents diverge on edge-case inputs).
|
||||
Without the companion restoration patch to core/modules/utils/deprecated.js:
|
||||
8 specs fail. With the patch: green.
|
||||
|
||||
The addClass/removeClass/toggleClass specs at the end were moved from
|
||||
test-utils.js — RSOD guard for the SampleWizard report (class field
|
||||
"aaa bbb" crashing classList.add with InvalidCharacterError).
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("deprecated.js — backwards-compat",function() {
|
||||
|
||||
describe("$tw.utils.repeat",function() {
|
||||
it("returns '' for zero or negative count (does not throw)",function() {
|
||||
expect($tw.utils.repeat("x",0)).toBe("");
|
||||
expect($tw.utils.repeat("x",-1)).toBe("");
|
||||
expect($tw.utils.repeat("x",-100)).toBe("");
|
||||
});
|
||||
it("coerces null/undefined str rather than throwing",function() {
|
||||
expect($tw.utils.repeat(null,3)).toBe("nullnullnull");
|
||||
expect($tw.utils.repeat(undefined,2)).toBe("undefinedundefined");
|
||||
});
|
||||
it("still works for normal inputs",function() {
|
||||
expect($tw.utils.repeat("ab",3)).toBe("ababab");
|
||||
expect($tw.utils.repeat("-",5)).toBe("-----");
|
||||
});
|
||||
});
|
||||
|
||||
describe("$tw.utils.startsWith / $tw.utils.endsWith",function() {
|
||||
it("tolerate a RegExp search argument without throwing",function() {
|
||||
// Old impl uses substring coercion; native String.prototype.startsWith
|
||||
// throws TypeError when passed a RegExp.
|
||||
expect(function() { $tw.utils.startsWith("abc",/a/); }).not.toThrow();
|
||||
expect(function() { $tw.utils.endsWith("abc",/c/); }).not.toThrow();
|
||||
});
|
||||
it("still match normal string inputs",function() {
|
||||
expect($tw.utils.startsWith("abcdef","abc")).toBe(true);
|
||||
expect($tw.utils.startsWith("abcdef","xyz")).toBe(false);
|
||||
expect($tw.utils.endsWith("abcdef","def")).toBe(true);
|
||||
expect($tw.utils.endsWith("abcdef","xyz")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("$tw.utils.stringifyNumber",function() {
|
||||
it("coerces null/undefined via string-concat rather than throwing",function() {
|
||||
expect($tw.utils.stringifyNumber(null)).toBe("null");
|
||||
expect($tw.utils.stringifyNumber(undefined)).toBe("undefined");
|
||||
});
|
||||
it("still returns a number's string form",function() {
|
||||
expect($tw.utils.stringifyNumber(42)).toBe("42");
|
||||
expect($tw.utils.stringifyNumber(-3.14)).toBe("-3.14");
|
||||
expect($tw.utils.stringifyNumber(0)).toBe("0");
|
||||
});
|
||||
});
|
||||
|
||||
describe("$tw.utils.domContains",function() {
|
||||
// Stub nodes expose both .contains() and .compareDocumentPosition() so
|
||||
// both the old (compareDocumentPosition & 16 → number) and new
|
||||
// (a !== b && a.contains(b) → boolean) forms can be observed.
|
||||
function makeNode(children) {
|
||||
children = children || [];
|
||||
var self;
|
||||
self = {
|
||||
contains: function(other) {
|
||||
if(other === self) { return true; }
|
||||
return children.some(function(c) { return c === other || c.contains(other); });
|
||||
},
|
||||
compareDocumentPosition: function(other) {
|
||||
if(other === self) { return 0; }
|
||||
return self.contains(other) ? 16 : 0;
|
||||
}
|
||||
};
|
||||
return self;
|
||||
}
|
||||
it("returns strictly boolean true/false, not a bit-mask number",function() {
|
||||
var child = makeNode();
|
||||
var parent = makeNode([child]);
|
||||
var unrelated = makeNode();
|
||||
expect($tw.utils.domContains(parent,child)).toBe(true);
|
||||
expect($tw.utils.domContains(parent,unrelated)).toBe(false);
|
||||
});
|
||||
it("returns false for domContains(x, x)",function() {
|
||||
var a = makeNode();
|
||||
expect($tw.utils.domContains(a,a)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("$tw.utils.hasClass",function() {
|
||||
it("returns false for null/undefined element without throwing",function() {
|
||||
expect(function() { $tw.utils.hasClass(null,"foo"); }).not.toThrow();
|
||||
expect($tw.utils.hasClass(null,"foo")).toBe(false);
|
||||
expect(function() { $tw.utils.hasClass(undefined,"foo"); }).not.toThrow();
|
||||
expect($tw.utils.hasClass(undefined,"foo")).toBe(false);
|
||||
});
|
||||
it("returns strictly false (not undefined) for elements without classList",function() {
|
||||
expect($tw.utils.hasClass({},"foo")).toBe(false);
|
||||
});
|
||||
it("delegates to classList.contains for real elements",function() {
|
||||
var el = { classList: { contains: function(c) { return c === "a" || c === "b"; } } };
|
||||
expect($tw.utils.hasClass(el,"a")).toBe(true);
|
||||
expect($tw.utils.hasClass(el,"b")).toBe(true);
|
||||
expect($tw.utils.hasClass(el,"c")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// getLocationPath reads window.location: specs pend in Node (no `window`
|
||||
// in the TW5 sandbox) and use history.replaceState in the browser —
|
||||
// assigning to window.location would trigger a navigation and reload.
|
||||
describe("$tw.utils.getLocationPath",function() {
|
||||
var originalUrl;
|
||||
beforeEach(function() {
|
||||
if(!$tw.browser) { return; }
|
||||
originalUrl = window.location.href;
|
||||
});
|
||||
afterEach(function() {
|
||||
if(!$tw.browser) { return; }
|
||||
history.replaceState(null,"",originalUrl);
|
||||
});
|
||||
it("preserves the query string in the returned path",function() {
|
||||
if(!$tw.browser) { pending("browser-only: requires window.location - run in browser"); return; }
|
||||
history.replaceState(null,"","?lang=de&x=1#Intro");
|
||||
var path = $tw.utils.getLocationPath();
|
||||
expect(path).toContain("?lang=de&x=1");
|
||||
expect(path).not.toContain("#Intro");
|
||||
});
|
||||
it("strips the hash fragment",function() {
|
||||
if(!$tw.browser) { pending("browser-only: requires window.location - run in browser"); return; }
|
||||
history.replaceState(null,"","#SomeTiddler");
|
||||
// Sanity check: replaceState actually changed the hash.
|
||||
expect(window.location.hash).toBe("#SomeTiddler");
|
||||
var path = $tw.utils.getLocationPath();
|
||||
expect(path).not.toContain("#");
|
||||
// Rebuild expected href without the hash — works on http(s):// and file://.
|
||||
var expected = window.location.href.split("#")[0];
|
||||
expect(path).toBe(expected);
|
||||
});
|
||||
it("includes the query string when no hash is present",function() {
|
||||
if(!$tw.browser) { pending("browser-only: requires window.location - run in browser"); return; }
|
||||
history.replaceState(null,"","?x=1");
|
||||
var path = $tw.utils.getLocationPath();
|
||||
expect(path).toMatch(/\?x=1$/);
|
||||
expect(path).not.toContain("#");
|
||||
});
|
||||
});
|
||||
|
||||
// Regression guard: classList.add/remove/toggle throw InvalidCharacterError on
|
||||
// whitespace. Manual repro: tw5-com #SampleWizard, class="aaa bbb", Done, popup
|
||||
// -> OK -> nested popup -> RSOD. Stub classList mirrors real DOM semantics
|
||||
// (reject whitespace, de-dupe on add, no-op on remove of missing token).
|
||||
describe("addClass/removeClass/toggleClass",function() {
|
||||
function makeEl() {
|
||||
var tokens = [];
|
||||
function reject(t) { if(/\s/.test(t)) { throw new Error("InvalidCharacterError: '" + t + "'"); } }
|
||||
return {
|
||||
classList: {
|
||||
add: function() {
|
||||
for(var i = 0; i < arguments.length; i++) {
|
||||
reject(arguments[i]);
|
||||
if(tokens.indexOf(arguments[i]) === -1) { tokens.push(arguments[i]); }
|
||||
}
|
||||
},
|
||||
remove: function() {
|
||||
for(var i = 0; i < arguments.length; i++) {
|
||||
reject(arguments[i]);
|
||||
var idx = tokens.indexOf(arguments[i]);
|
||||
if(idx !== -1) { tokens.splice(idx,1); }
|
||||
}
|
||||
},
|
||||
toggle: function(cls,status) {
|
||||
reject(cls);
|
||||
var has = tokens.indexOf(cls) !== -1;
|
||||
var want = status === undefined ? !has : status;
|
||||
if(want && !has) { tokens.push(cls); }
|
||||
if(!want && has) { tokens.splice(tokens.indexOf(cls),1); }
|
||||
}
|
||||
},
|
||||
_tokens: tokens
|
||||
};
|
||||
}
|
||||
|
||||
it("splits on every ASCII-whitespace flavour (space, tab, newline, CR, mixed runs, leading/trailing)",function() {
|
||||
var el = makeEl();
|
||||
$tw.utils.addClass(el," a\tb\nc\r\nd \t e ");
|
||||
expect(el._tokens).toEqual(["a","b","c","d","e"]);
|
||||
});
|
||||
|
||||
it("splits on Unicode whitespace too (U+00A0 non-breaking space, a common paste-in hazard)",function() {
|
||||
var el = makeEl();
|
||||
$tw.utils.addClass(el,"a\u00A0b");
|
||||
expect(el._tokens).toEqual(["a","b"]);
|
||||
});
|
||||
|
||||
it("de-duplicates tokens within one call and across calls",function() {
|
||||
var el = makeEl();
|
||||
$tw.utils.addClass(el,"x x y");
|
||||
$tw.utils.addClass(el,"y z");
|
||||
expect(el._tokens).toEqual(["x","y","z"]);
|
||||
});
|
||||
|
||||
it("remove is a no-op for missing tokens and tolerates mixed-presence input",function() {
|
||||
var el = makeEl();
|
||||
$tw.utils.addClass(el,"a b");
|
||||
$tw.utils.removeClass(el,"b c d");
|
||||
expect(el._tokens).toEqual(["a"]);
|
||||
});
|
||||
|
||||
it("toggle with no status flips each token independently",function() {
|
||||
var el = makeEl();
|
||||
$tw.utils.addClass(el,"a");
|
||||
$tw.utils.toggleClass(el,"a b");
|
||||
expect(el._tokens).toEqual(["b"]);
|
||||
});
|
||||
|
||||
it("toggle with status=true/false forces state regardless of current",function() {
|
||||
var el = makeEl();
|
||||
$tw.utils.addClass(el,"a");
|
||||
$tw.utils.toggleClass(el,"a b",true);
|
||||
expect(el._tokens).toEqual(["a","b"]);
|
||||
$tw.utils.toggleClass(el,"a b",false);
|
||||
expect(el._tokens).toEqual([]);
|
||||
});
|
||||
|
||||
it("is a silent no-op for whitespace-only / empty / non-string / null / undefined className",function() {
|
||||
var el = makeEl();
|
||||
var inputs = ["", " \t\n ", null, undefined, 42, {}, ["a"]];
|
||||
inputs.forEach(function(v) {
|
||||
expect(function() { $tw.utils.addClass(el,v); }).not.toThrow();
|
||||
expect(function() { $tw.utils.removeClass(el,v); }).not.toThrow();
|
||||
expect(function() { $tw.utils.toggleClass(el,v); }).not.toThrow();
|
||||
});
|
||||
expect(el._tokens).toEqual([]);
|
||||
});
|
||||
|
||||
it("is a silent no-op when element has no classList (SVG in old browsers, detached nodes, stubs)",function() {
|
||||
var el = {};
|
||||
expect(function() { $tw.utils.addClass(el,"a b"); }).not.toThrow();
|
||||
expect(function() { $tw.utils.removeClass(el,"a b"); }).not.toThrow();
|
||||
expect(function() { $tw.utils.toggleClass(el,"a b",true); }).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,138 +0,0 @@
|
||||
/*\
|
||||
title: $:/tests/test-edit-widgets/helpers
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
|
||||
Shared test helpers for the edit-text / edit-widget test suite. Every
|
||||
helper here is usable in fakedom — nothing reaches for real DOM layout,
|
||||
iframe documents, or synthetic events.
|
||||
|
||||
Import with:
|
||||
|
||||
var helpers = require("$:/tests/test-edit-widgets/helpers");
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
/*
|
||||
makeWiki: build a fresh in-memory test wiki. Pass an array of tiddler
|
||||
specs to seed. Use `seedTestTiddler: true` in the options to also add a
|
||||
convenience "TestTiddler" (empty text) that many tests default to.
|
||||
*/
|
||||
exports.makeWiki = function(tiddlers,options) {
|
||||
options = options || {};
|
||||
var wiki = $tw.test.wiki();
|
||||
if(options.seedTestTiddler) {
|
||||
wiki.addTiddlers([{title: "TestTiddler", text: ""}]);
|
||||
}
|
||||
if(tiddlers) {
|
||||
wiki.addTiddlers(tiddlers);
|
||||
}
|
||||
return wiki;
|
||||
};
|
||||
|
||||
/*
|
||||
parseAndRender: parse a wikitext snippet, build the widget tree against
|
||||
the fakedom, and render into a detached wrapper <div>. Returns both the
|
||||
top-level widgetNode (for refresh/teardown) and the wrapper (for DOM
|
||||
inspection).
|
||||
*/
|
||||
exports.parseAndRender = function(widgetText,wiki) {
|
||||
var parser = wiki.parseText("text/vnd.tiddlywiki",widgetText);
|
||||
var widgetNode = new widget.widget(
|
||||
{type: "widget", children: parser.tree},
|
||||
{wiki: wiki, document: $tw.fakeDocument}
|
||||
);
|
||||
$tw.fakeDocument.setSequenceNumber(0);
|
||||
var wrapper = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(wrapper,null);
|
||||
return {widgetNode: widgetNode, wrapper: wrapper};
|
||||
};
|
||||
|
||||
/*
|
||||
findEditTextWidget: walk a widget tree and return the first
|
||||
EditTextWidget instance (identified by having both an `engine` and an
|
||||
`editTag` property). Needed because parseAndRender returns the
|
||||
enclosing "widget" root, not the <$edit-text> itself.
|
||||
*/
|
||||
exports.findEditTextWidget = function findEditTextWidget(node) {
|
||||
if(node.engine && node.editTag !== undefined) {
|
||||
return node;
|
||||
}
|
||||
if(node.children) {
|
||||
for(var i = 0; i < node.children.length; i++) {
|
||||
var found = findEditTextWidget(node.children[i]);
|
||||
if(found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
renderFromWikitext: parse+render a wikitext snippet and return a bundle
|
||||
{ widget, root, wrapper, wiki } exposing every layer. Used by the
|
||||
attribute-propagation and refresh tests which need access to the wiki
|
||||
and wrapper after render.
|
||||
*/
|
||||
exports.renderFromWikitext = function(widgetText,wiki) {
|
||||
wiki = wiki || exports.makeWiki([{title: "TestTiddler", text: "hello"}]);
|
||||
var result = exports.parseAndRender(widgetText,wiki);
|
||||
return {
|
||||
widget: exports.findEditTextWidget(result.widgetNode),
|
||||
root: result.widgetNode,
|
||||
wrapper: result.wrapper,
|
||||
wiki: wiki
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
renderFromAttrs: build an <$edit-text> tag from an attrs object, render
|
||||
it, and return just the EditTextWidget instance (not a full bundle).
|
||||
Used by tests that only need the widget and its DOM node.
|
||||
*/
|
||||
exports.renderFromAttrs = function(attrs,wiki,tiddlerTitle) {
|
||||
wiki = wiki || exports.makeWiki(null,{seedTestTiddler: true});
|
||||
var attrStr = Object.keys(attrs).map(function(k) {
|
||||
return k + "=\"" + attrs[k] + "\"";
|
||||
}).join(" ");
|
||||
var text = "<$edit-text tiddler=\"" + (tiddlerTitle || "TestTiddler") + "\" " + attrStr + "/>";
|
||||
var rendered = exports.parseAndRender(text,wiki);
|
||||
return exports.findEditTextWidget(rendered.widgetNode);
|
||||
};
|
||||
|
||||
/*
|
||||
refresh: drive a widget-tree refresh cycle for a given list of changed
|
||||
tiddler titles, mimicking what the core does after wiki.addTiddler.
|
||||
*/
|
||||
exports.refresh = function(rootWidget,wrapper,changedTitles) {
|
||||
var changed = {};
|
||||
(changedTitles || []).forEach(function(t) { changed[t] = true; });
|
||||
rootWidget.refresh(changed,wrapper,null);
|
||||
};
|
||||
|
||||
/*
|
||||
editorValue: read the editor's current text in a way that works with
|
||||
fakedom. SimpleEngine seeds a textarea by appending a text-node child,
|
||||
while inputs use the `value` attribute. Later updates go through
|
||||
updateDomNodeText which sets `.value` on both.
|
||||
*/
|
||||
exports.editorValue = function(w) {
|
||||
var dn = w.engine.domNode;
|
||||
// If .value has been set explicitly, prefer it (covers refresh updates)
|
||||
if(dn.attributes && dn.attributes.value !== undefined) {
|
||||
return dn.value;
|
||||
}
|
||||
// Otherwise for textareas read the concatenated child text nodes
|
||||
if(dn.tag === "textarea" && dn.children && dn.children.length) {
|
||||
return dn.children.map(function(n) { return n.textContent || ""; }).join("");
|
||||
}
|
||||
return dn.value;
|
||||
};
|
||||
|
||||
// Note: jasmine-specific helpers (spies) belong in the test-spec files
|
||||
// themselves. TW library modules run in a sandbox that does not expose
|
||||
// `jasmine`, so anything that calls jasmine.createSpy must live in a
|
||||
// file tagged with $:/tags/test-spec.
|
||||
@@ -1,353 +0,0 @@
|
||||
/*\
|
||||
title: test-edit-text-widget-attributes.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Covers edit-text widget behaviour that is observable in fakedom: value
|
||||
resolution, tag/type selection, DOM attribute propagation, save-back
|
||||
and refresh paths.
|
||||
|
||||
Each spec has a "manual:" comment with a by-hand recipe so a reviewer
|
||||
can sanity-check the test against a live wiki.
|
||||
|
||||
NOT covered (need a real browser — Playwright territory):
|
||||
* `focus`, `focusSelectFromStart`/`End`, `focusPopup`, `cancelPopups` — real DOM focus + selection APIs
|
||||
* `inputActions`, `fileDrop` — synthetic events not dispatched by fakedom
|
||||
* Pixel measurement / growth of auto-height textareas — `$tw.utils.resizeTextAreaToFit` needs real layout
|
||||
* FramedEngine — requires a real iframe document
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("Edit-text widget (attribute propagation and value handling)", function() {
|
||||
|
||||
// Shared helpers live in $:/tests/test-edit-widgets/helpers. See that
|
||||
// file for what each helper prepares and where it is used across the suite.
|
||||
var helpers = require("$:/tests/test-edit-widgets/helpers");
|
||||
|
||||
// Local aliases — `render`, `editorValue` etc. read better inline
|
||||
// than `helpers.renderFromWikitext`. Each test supplies its own
|
||||
// tiddlers, so makeWiki is NOT seeded with TestTiddler here.
|
||||
var makeWiki = helpers.makeWiki;
|
||||
var render = helpers.renderFromWikitext;
|
||||
var refresh = helpers.refresh;
|
||||
var editorValue = helpers.editorValue;
|
||||
var findEditTextWidget = helpers.findEditTextWidget;
|
||||
|
||||
// spyOnSetText stays file-local because it depends on `jasmine`,
|
||||
// which is only in scope for $:/tags/test-spec modules — NOT for
|
||||
// library modules loaded via require().
|
||||
function spyOnSetText(w) {
|
||||
var spy = jasmine.createSpy("setText");
|
||||
w.engine.setText = spy;
|
||||
return spy;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Value and type resolution (getEditInfo)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("value and type resolution", function() {
|
||||
|
||||
// manual: create tiddler "TestTiddler" with text "hello", then in any
|
||||
// tiddler render <$edit-text tiddler='TestTiddler'/> — the
|
||||
// textarea should show "hello".
|
||||
it("reads the text field of an existing tiddler", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\"/>");
|
||||
expect(editorValue(w.widget)).toBe("hello");
|
||||
});
|
||||
|
||||
// manual: give a tiddler "T" a caption="Hi" field, then render
|
||||
// <$edit-text tiddler="T" field="caption"/> — input should show "Hi".
|
||||
it("reads an arbitrary named field", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "body", caption: "Hi"}]);
|
||||
var w = render("<$edit-text tiddler=\"T\" field=\"caption\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("Hi");
|
||||
});
|
||||
|
||||
// manual: create tiddler "T" without a caption field, then render
|
||||
// <$edit-text tiddler="T" field="caption" default="fallback"/> —
|
||||
// input should show "fallback".
|
||||
it("falls back to the default attribute when the field is missing", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "body"}]);
|
||||
var w = render("<$edit-text tiddler=\"T\" field=\"caption\" default=\"fallback\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("fallback");
|
||||
});
|
||||
|
||||
// manual: create tiddler "T" without a caption field, render
|
||||
// <$edit-text tiddler="T" field="caption"/> — input should be empty.
|
||||
it("falls back to an empty string when neither field nor default is present", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "body"}]);
|
||||
var w = render("<$edit-text tiddler=\"T\" field=\"caption\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("");
|
||||
});
|
||||
|
||||
// manual: ensure NO tiddler named "Missing" exists, then render
|
||||
// <$edit-text tiddler="Missing" field="title"/> — input should show
|
||||
// "Missing" (the title field of a not-yet-existing tiddler defaults
|
||||
// to the tiddler title).
|
||||
it("uses the tiddler title as the default for the title field on missing tiddlers", function() {
|
||||
var wiki = makeWiki();
|
||||
var w = render("<$edit-text tiddler=\"Missing\" field=\"title\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("Missing");
|
||||
});
|
||||
|
||||
// manual: ensure NO tiddler named "Missing" exists, then render
|
||||
// <$edit-text tiddler="Missing" default="seed"/> — textarea should
|
||||
// show "seed" until you type into it.
|
||||
it("uses default= on a missing tiddler", function() {
|
||||
var wiki = makeWiki();
|
||||
var w = render("<$edit-text tiddler=\"Missing\" default=\"seed\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("seed");
|
||||
});
|
||||
|
||||
// manual: create a data tiddler "Data" with type
|
||||
// "application/x-tiddler-dictionary" and text "one: 1\ntwo: 2",
|
||||
// then render <$edit-text tiddler="Data" index="two"/> — input
|
||||
// should show "2".
|
||||
it("reads a value from a data tiddler index", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "Data", type: "application/x-tiddler-dictionary", text: "one: 1\ntwo: 2"}
|
||||
]);
|
||||
var w = render("<$edit-text tiddler=\"Data\" index=\"two\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("2");
|
||||
});
|
||||
|
||||
// manual: with the same "Data" dictionary but no "missing" key,
|
||||
// render <$edit-text tiddler="Data" index="missing" default="none"/> —
|
||||
// input should show "none".
|
||||
it("uses default= for a missing index", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "Data", type: "application/x-tiddler-dictionary", text: "one: 1"}
|
||||
]);
|
||||
var w = render("<$edit-text tiddler=\"Data\" index=\"missing\" default=\"none\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("none");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Tag and type selection
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("tag and type selection", function() {
|
||||
|
||||
// manual: render <$edit-text tiddler="TestTiddler"/> and inspect the
|
||||
// element — it should be a <textarea>.
|
||||
it("defaults to a textarea for the text field", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\"/>");
|
||||
expect(w.widget.engine.domNode.tag).toBe("textarea");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="TestTiddler" field="caption"/>
|
||||
// and inspect the element — it should be a single-line <input>.
|
||||
it("defaults to an input for non-text fields", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\" field=\"caption\"/>");
|
||||
expect(w.widget.engine.domNode.tag).toBe("input");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="TestTiddler" tag="input"/> —
|
||||
// even though the default for the text field is textarea, this
|
||||
// should render as a single-line <input>.
|
||||
it("tag=input forces an input even for the text field", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\" tag=\"input\"/>");
|
||||
expect(w.widget.engine.domNode.tag).toBe("input");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" tag="input" type="password"/>
|
||||
// — the element should be a password input (characters masked as dots).
|
||||
it("type= sets the input type attribute", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\" tag=\"input\" type=\"password\"/>");
|
||||
expect(w.widget.engine.domNode.getAttribute("type")).toBe("password");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" type="password"/> (no tag
|
||||
// override) — the element should be a plain textarea; type is
|
||||
// silently ignored because HTML textareas have no type attribute.
|
||||
it("type= is ignored for textareas (no type attribute on textarea)", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\" type=\"password\"/>");
|
||||
expect(w.widget.engine.domNode.getAttribute("type")).toBeUndefined();
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" tag="script"/> — must NOT
|
||||
// inject a <script> element; tag should fall back to <input>. This
|
||||
// is a defence-in-depth check against wiki-authored HTML injection.
|
||||
it("unsafe tag names collapse to input", function() {
|
||||
var w = render("<$edit-text tiddler=\"TestTiddler\" tag=\"script\"/>");
|
||||
expect(w.widget.engine.domNode.tag).toBe("input");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// DOM attribute propagation
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("DOM attribute propagation", function() {
|
||||
|
||||
// manual: render <$edit-text tiddler="TestTiddler" tag="input"
|
||||
// class="my-class" placeholder="Type here" size="40" tabindex="3"
|
||||
// autocomplete="email" disabled="yes"/> — inspect the element in
|
||||
// devtools; every attribute set on the widget should appear on
|
||||
// the DOM element with the expected value. disabled="no" would
|
||||
// omit the attribute entirely.
|
||||
//
|
||||
// INFO: View as "raw HTML" in preview panel
|
||||
//
|
||||
// SimpleEngine has one independent `if(this.widget.editXxx)
|
||||
// setAttribute(...)` block per attribute. This combined test
|
||||
// exercises every such block in one shot; if any copy breaks,
|
||||
// this spec fails and the jasmine expectation report identifies
|
||||
// the offending attribute.
|
||||
it("copies class, placeholder, size, tabindex, autocomplete and disabled onto the DOM element", function() {
|
||||
var w = render(
|
||||
"<$edit-text tiddler=\"TestTiddler\" tag=\"input\" " +
|
||||
"class=\"my-class\" placeholder=\"Type here\" size=\"40\" " +
|
||||
"tabindex=\"3\" autocomplete=\"email\" disabled=\"yes\"/>"
|
||||
);
|
||||
var dn = w.widget.engine.domNode;
|
||||
expect(dn.className).toBe("my-class");
|
||||
expect(dn.getAttribute("placeholder")).toBe("Type here");
|
||||
expect(dn.getAttribute("size")).toBe("40");
|
||||
expect(dn.getAttribute("tabindex")).toBe("3");
|
||||
expect(dn.getAttribute("autocomplete")).toBe("email");
|
||||
expect(dn.getAttribute("disabled")).toBe("true");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Save-back via saveChanges
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("saving changes back to the store", function() {
|
||||
|
||||
// manual: with tiddler "T" text="old", render <$edit-text tiddler="T"/>
|
||||
// and type "new text"; open T from the sidebar — its text field
|
||||
// should update live.
|
||||
it("writes a new value to the configured text field", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "old"}]);
|
||||
var w = render("<$edit-text tiddler=\"T\"/>",wiki);
|
||||
w.widget.saveChanges("new text");
|
||||
expect(wiki.getTiddler("T").fields.text).toBe("new text");
|
||||
});
|
||||
|
||||
// manual: with tiddler "T" caption="old", render
|
||||
// <$edit-text tiddler="T" field="caption"/> and type a new caption;
|
||||
// {{T!!caption}} elsewhere should update live.
|
||||
it("writes to a non-text field", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "body", caption: "old"}]);
|
||||
var w = render("<$edit-text tiddler=\"T\" field=\"caption\"/>",wiki);
|
||||
w.widget.saveChanges("new caption");
|
||||
expect(wiki.getTiddler("T").fields.caption).toBe("new caption");
|
||||
});
|
||||
|
||||
// manual: ensure no tiddler "NewOne" exists, render
|
||||
// <$edit-text tiddler="NewOne" default=""/> and type "created" —
|
||||
// a new tiddler "NewOne" should appear in the sidebar with that
|
||||
// text.
|
||||
it("creates the tiddler if it does not exist", function() {
|
||||
var wiki = makeWiki();
|
||||
var w = render("<$edit-text tiddler=\"NewOne\" default=\"\"/>",wiki);
|
||||
w.widget.saveChanges("created");
|
||||
expect(wiki.tiddlerExists("NewOne")).toBe(true);
|
||||
expect(wiki.getTiddler("NewOne").fields.text).toBe("created");
|
||||
});
|
||||
|
||||
// manual: with dictionary tiddler "Data" containing one:1, two:2,
|
||||
// render <$edit-text tiddler="Data" index="one"/> and change the
|
||||
// value to "uno"; view Data as text — it should now read
|
||||
// "one: uno\ntwo: 2".
|
||||
it("writes to a data tiddler index", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "Data", type: "application/x-tiddler-dictionary", text: "one: 1\ntwo: 2"}
|
||||
]);
|
||||
var w = render("<$edit-text tiddler=\"Data\" index=\"one\"/>",wiki);
|
||||
w.widget.saveChanges("uno");
|
||||
expect(wiki.extractTiddlerDataItem("Data","one")).toBe("uno");
|
||||
// Other index entries preserved
|
||||
expect(wiki.extractTiddlerDataItem("Data","two")).toBe("2");
|
||||
});
|
||||
|
||||
// manual: Select the text. Copy / Paste -> modified does not change
|
||||
it("skips the store update when the value is unchanged", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "same"}]);
|
||||
var before = wiki.getTiddler("T").fields.modified;
|
||||
var w = render("<$edit-text tiddler=\"T\"/>",wiki);
|
||||
w.widget.saveChanges("same");
|
||||
expect(wiki.getTiddler("T").fields.modified).toBe(before);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Refresh behaviour
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("refresh behaviour", function() {
|
||||
|
||||
// manual: render <$edit-text tiddler="T"/>, in New Tiddler and New Tiddler 1
|
||||
// The textarea you are NOT focused on
|
||||
// should live-update to reflect the new text field.
|
||||
it("propagates an external change of the edited tiddler through engine.setText", function() {
|
||||
var wiki = makeWiki([{title: "T", text: "first"}]);
|
||||
var w = render("<$edit-text tiddler=\"T\"/>",wiki);
|
||||
expect(editorValue(w.widget)).toBe("first");
|
||||
var setTextSpy = spyOnSetText(w.widget);
|
||||
wiki.addTiddler({title: "T", text: "second"});
|
||||
refresh(w.root,w.wrapper,["T"]);
|
||||
expect(setTextSpy).toHaveBeenCalled();
|
||||
expect(setTextSpy.calls.mostRecent().args[0]).toBe("second");
|
||||
});
|
||||
|
||||
// manual:
|
||||
// 1. Create tiddlers T (text "initial") and Trigger (text "x").
|
||||
// 2. Render <$edit-text tiddler="T" refreshTitle="Trigger"/>.
|
||||
// 3. Click into the textarea (it now has focus) and type " typed".
|
||||
// 4. Open F12, in console:
|
||||
// $tw.wiki.addTiddler({title:"T",text:"external"})
|
||||
// Focus stays on textarea. Store changes, but setText skips
|
||||
// the DOM write because the node is focused — DOM diverges
|
||||
// from store (textarea still shows "initial typed").
|
||||
// 5. In console:
|
||||
// $tw.wiki.addTiddler({title:"Trigger",text:"bump"})
|
||||
// Textarea should VISIBLY flip to "external" while still
|
||||
// focused. updateDomNodeText has no focus check.
|
||||
// Without refreshTitle, step 5 does nothing — DOM stays diverged.
|
||||
it("refreshTitle triggers updateDomNodeText even when a different tiddler changes", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "T", text: "first"},
|
||||
{title: "Trigger", text: "x"}
|
||||
]);
|
||||
var w = render("<$edit-text tiddler=\"T\" refreshTitle=\"Trigger\"/>",wiki);
|
||||
// refreshTitle goes through engine.updateDomNodeText, not setText
|
||||
var updateSpy = jasmine.createSpy("updateDomNodeText");
|
||||
w.widget.engine.updateDomNodeText = updateSpy;
|
||||
wiki.addTiddler({title: "T", text: "updated"});
|
||||
refresh(w.root,w.wrapper,["Trigger"]);
|
||||
expect(updateSpy).toHaveBeenCalledWith("updated");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" class={{ClassSrc}}/> and
|
||||
// change ClassSrc's text. Inspect the textarea element in devtools
|
||||
// — the class attribute should flip to the new value. This covers
|
||||
// a full re-render (refreshSelf), not just an in-place text update.
|
||||
it("changes to attributes that require a full rerender trigger refreshSelf", function() {
|
||||
// When an attribute like `class` changes via a transcluded variable,
|
||||
// the widget should rerender itself. We simulate that by wrapping the
|
||||
// edit-text inside a transclusion where the class is indirect.
|
||||
var wiki = makeWiki([
|
||||
{title: "T", text: "body"},
|
||||
{title: "ClassSrc", text: "first-class"}
|
||||
]);
|
||||
var w = render(
|
||||
"<$edit-text tiddler=\"T\" class={{ClassSrc}}/>",
|
||||
wiki
|
||||
);
|
||||
expect(w.widget.engine.domNode.className).toBe("first-class");
|
||||
wiki.addTiddler({title: "ClassSrc", text: "second-class"});
|
||||
refresh(w.root,w.wrapper,["ClassSrc"]);
|
||||
// Re-locate the widget because a full refresh creates a new instance
|
||||
var fresh = findEditTextWidget(w.root);
|
||||
expect(fresh.engine.domNode.className).toBe("second-class");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,198 +0,0 @@
|
||||
/*\
|
||||
title: test-edit-text-widget.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Covers the `rows` / `autoHeight` / `minHeight` interaction in the
|
||||
edit-text widget. Regression guard for issue #9451 / PR #9454 follow-up
|
||||
fix (rows=1 autoHeight=yes must still grow).
|
||||
|
||||
Assertions target the routing inside SimpleEngine.fixHeight (which
|
||||
branch runs, called with which minHeight) — pixel measurement needs a
|
||||
real browser.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("Edit-text widget", function() {
|
||||
|
||||
// Shared helpers live in $:/tests/test-edit-widgets/helpers. See that
|
||||
// file for what each helper prepares and where it is used across the suite.
|
||||
var helpers = require("$:/tests/test-edit-widgets/helpers");
|
||||
|
||||
// Local wrapper: every test in THIS file seeds an empty "TestTiddler"
|
||||
// as its default binding target, so we inject that by default.
|
||||
function makeWiki(extraTiddlers) {
|
||||
return helpers.makeWiki(extraTiddlers,{seedTestTiddler: true});
|
||||
}
|
||||
|
||||
// Local alias — `renderEditText` reads more naturally than
|
||||
// `helpers.renderFromAttrs` for the routing tests.
|
||||
function renderEditText(attrs,wiki,tiddlerTitle) {
|
||||
return helpers.renderFromAttrs(attrs,wiki,tiddlerTitle);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Attribute parsing
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("attribute parsing", function() {
|
||||
|
||||
// manual: on a bare <$edit-text tiddler="T"/>, open devtools and
|
||||
// inspect the widget instance — the element should be a textarea,
|
||||
// there should be no rows attribute, and auto-height should be on.
|
||||
// Manual Preview: Also use the widget-tree
|
||||
it("defaults: tag=textarea, autoHeight=yes, no rows, minHeight=100px", function() {
|
||||
var et = renderEditText({});
|
||||
expect(et.editTag).toBe("textarea");
|
||||
expect(et.editAutoHeight).toBe(true);
|
||||
expect(et.editRows).toBeUndefined();
|
||||
expect(et.editMinHeight).toBe("100px");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" rows=5 autoHeight="no" minHeight="1em"/>
|
||||
// — the widget's internal state should reflect all three explicit
|
||||
// values, overriding the defaults verified in the previous test.
|
||||
// Manual Preview: Also use the widget-tree
|
||||
it("explicit attributes override defaults (rows, autoHeight, minHeight)", function() {
|
||||
var et = renderEditText({rows: "5", autoHeight: "no", minHeight: "1em"});
|
||||
expect(et.editRows).toBe("5");
|
||||
expect(et.editAutoHeight).toBe(false);
|
||||
expect(et.editMinHeight).toBe("1em");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" field="caption" tag="textarea"/>
|
||||
// — the element should be a multi-line textarea even though the
|
||||
// field is not `text`.
|
||||
it("tag=textarea override applies to non-text fields", function() {
|
||||
var et = renderEditText({field: "caption", tag: "textarea"});
|
||||
expect(et.editTag).toBe("textarea");
|
||||
});
|
||||
|
||||
// manual: set $:/config/TextEditor/EditorHeight/Mode = "fixed"
|
||||
// (via control panel → settings → editor toolbar, or edit the
|
||||
// tiddler directly). <$edit-text tiddler="T"/> should now behave
|
||||
// as fixed-height (scrollbar on overflow) by default.
|
||||
it("$:/config/TextEditor/EditorHeight/Mode=fixed flips default autoHeight to false", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "$:/config/TextEditor/EditorHeight/Mode", text: "fixed"}
|
||||
]);
|
||||
var et = renderEditText({},wiki);
|
||||
expect(et.editAutoHeight).toBe(false);
|
||||
});
|
||||
|
||||
// manual: with the same Mode=fixed config as above, an explicit
|
||||
// <$edit-text tiddler="T" autoHeight="yes"/> should still auto-grow
|
||||
// — the per-widget attribute wins over the global config.
|
||||
it("explicit autoHeight=yes overrides Mode=fixed config", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "$:/config/TextEditor/EditorHeight/Mode", text: "fixed"}
|
||||
]);
|
||||
var et = renderEditText({autoHeight: "yes"},wiki);
|
||||
expect(et.editAutoHeight).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// DOM node construction (SimpleEngine)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("DOM node construction (non-toolbar SimpleEngine)", function() {
|
||||
|
||||
// manual: render <$edit-text tiddler="T" rows=1/> and inspect the
|
||||
// element — it should carry rows="1". Proves SimpleEngine copies
|
||||
// widget.editRows onto the DOM element.
|
||||
it("sets the rows attribute on the DOM node when rows is specified", function() {
|
||||
var et = renderEditText({rows: "1"});
|
||||
expect(et.engine.domNode.getAttribute("rows")).toBe("1");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// fixHeight routing — the core of the fix
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe("fixHeight routing", function() {
|
||||
|
||||
var originalResize, resizeSpy;
|
||||
|
||||
beforeEach(function() {
|
||||
originalResize = $tw.utils.resizeTextAreaToFit;
|
||||
resizeSpy = jasmine.createSpy("resizeTextAreaToFit").and.returnValue(0);
|
||||
$tw.utils.resizeTextAreaToFit = resizeSpy;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
$tw.utils.resizeTextAreaToFit = originalResize;
|
||||
});
|
||||
|
||||
// Make the SimpleEngine.fixHeight think we are in a real DOM so it
|
||||
// actually reaches the $tw.utils.resizeTextAreaToFit call. Without
|
||||
// this the engine short-circuits because fakedom nodes carry
|
||||
// isTiddlyWikiFakeDom === true.
|
||||
function callFixHeight(et) {
|
||||
et.engine.domNode.isTiddlyWikiFakeDom = false;
|
||||
et.engine.fixHeight();
|
||||
}
|
||||
|
||||
// manual: render <$edit-text tiddler="T" rows=1 autoHeight=yes minHeight=1em/>
|
||||
// (the TiddlyTools idiom). In 5.4.0 pre-fix, the textarea stayed
|
||||
// a single row forever; after the fix, it starts at 1 row and
|
||||
// grows as you type newlines. This covers BRANCH A (autoHeight=yes)
|
||||
// of SimpleEngine.fixHeight: resize is called with minHeight even
|
||||
// when rows is set. Strict superset of the no-rows baseline.
|
||||
it("rows=1 autoHeight=yes minHeight=1em still calls resize (regression test for the PR #9454 follow-up fix)", function() {
|
||||
var et = renderEditText({rows: "1", autoHeight: "yes", minHeight: "1em"});
|
||||
callFixHeight(et);
|
||||
expect(resizeSpy).toHaveBeenCalled();
|
||||
expect(resizeSpy.calls.mostRecent().args[1]).toBe("1em");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" rows=5 autoHeight=no/> —
|
||||
// the textarea must stay locked at exactly 5 rows tall, even if
|
||||
// you paste in 50 lines (vertical scrollbar appears inside).
|
||||
it("rows=5 autoHeight=no does NOT call resize and does NOT apply the fixed-height fallback", function() {
|
||||
var et = renderEditText({rows: "5", autoHeight: "no"});
|
||||
callFixHeight(et);
|
||||
expect(resizeSpy).not.toHaveBeenCalled();
|
||||
// rows attribute governs height — CSS height must remain unset
|
||||
expect(et.engine.domNode.style.height).toBe("");
|
||||
});
|
||||
|
||||
// manual: set $:/config/TextEditor/EditorHeight/Height = "250px",
|
||||
// then render <$edit-text tiddler="T" autoHeight="no"/> — the
|
||||
// textarea should be exactly 250px tall regardless of content.
|
||||
it("autoHeight=no with no rows applies the fixed-height fallback from config", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "$:/config/TextEditor/EditorHeight/Height", text: "250px"}
|
||||
]);
|
||||
var et = renderEditText({autoHeight: "no"},wiki);
|
||||
callFixHeight(et);
|
||||
expect(resizeSpy).not.toHaveBeenCalled();
|
||||
expect(et.engine.domNode.style.height).toBe("250px");
|
||||
});
|
||||
|
||||
// manual: set $:/config/TextEditor/EditorHeight/Height = "5px",
|
||||
// render <$edit-text tiddler="T" autoHeight="no"/> — the textarea
|
||||
// should be 20px tall (clamped), not a sliver, so it stays usable.
|
||||
it("autoHeight=no fallback height is clamped to at least 20px", function() {
|
||||
var wiki = makeWiki([
|
||||
{title: "$:/config/TextEditor/EditorHeight/Height", text: "5px"}
|
||||
]);
|
||||
var et = renderEditText({autoHeight: "no"},wiki);
|
||||
callFixHeight(et);
|
||||
expect(et.engine.domNode.style.height).toBe("20px");
|
||||
});
|
||||
|
||||
// manual: render <$edit-text tiddler="T" field="caption" autoHeight="no"/>
|
||||
// — the element is a single-line <input> and the CSS height should
|
||||
// remain unset (no height fallback applies to inputs).
|
||||
it("tag=input: neither resize nor fixed-height fallback runs", function() {
|
||||
var et = renderEditText({field: "caption", autoHeight: "no"});
|
||||
callFixHeight(et);
|
||||
expect(resizeSpy).not.toHaveBeenCalled();
|
||||
expect(et.engine.domNode.style.height).toBe("");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -18,15 +18,4 @@ describe("fakedom tests", function() {
|
||||
expect($tw.fakeDocument.createTextNode("text").nodeType).toBe(3);
|
||||
expect($tw.fakeDocument.createTextNode("text").TEXT_NODE).toBe(3);
|
||||
});
|
||||
|
||||
// Real CSSStyleDeclaration returns undefined for Symbol property keys.
|
||||
// Without a guard, the TW_Style Proxy throws on Symbol access. This bites
|
||||
// in practice when Jasmine pretty-prints fakedom elements on failure.
|
||||
// See related TODO in test-select-widget.js
|
||||
it("returns undefined for Symbol property access on element.style", function() {
|
||||
var el = $tw.fakeDocument.createElement("div");
|
||||
expect(function() { return el.style[Symbol.toPrimitive]; }).not.toThrow();
|
||||
expect(el.style[Symbol.toPrimitive]).toBeUndefined();
|
||||
expect(function() { el.style[Symbol.iterator] = "x"; }).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/*\
|
||||
title: test-select-widget.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Tests the select widget, focused on multi-select refresh behaviour.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("Select widget", function() {
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
// Helpers reused from: test-widget.js and test-checkbox-widget.js
|
||||
function createWidgetNode(parseTreeNode,wiki) {
|
||||
return new widget.widget(parseTreeNode,{
|
||||
wiki: wiki,
|
||||
document: $tw.fakeDocument
|
||||
});
|
||||
}
|
||||
|
||||
function parseText(text,wiki,options) {
|
||||
var parser = wiki.parseText("text/vnd.tiddlywiki",text,options);
|
||||
return parser ? {type: "widget", children: parser.tree} : undefined;
|
||||
}
|
||||
|
||||
function renderWidgetNode(widgetNode) {
|
||||
$tw.fakeDocument.setSequenceNumber(0);
|
||||
var wrapper = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(wrapper,null);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function refreshWidgetNode(widgetNode,wrapper,changes) {
|
||||
var changedTiddlers = {};
|
||||
if(changes) {
|
||||
$tw.utils.each(changes,function(title) {
|
||||
changedTiddlers[title] = true;
|
||||
});
|
||||
}
|
||||
widgetNode.refresh(changedTiddlers,wrapper,null);
|
||||
}
|
||||
|
||||
// Don't pass fakedom elements to Jasmine matchers. The matchers pretty-print
|
||||
// values on assertion which walks the element.style Proxy with Symbol keys and
|
||||
// crashes inside convertStyleNameToPropertyName.
|
||||
// TODO: once issue: "fakedom style Proxy guards against non-string property keys" lands
|
||||
// revert these workarounds to idiomatic matchers (toBe(null), toBeUndefined()).
|
||||
function findSelectDom(node) {
|
||||
if(node.tag === "select") return node;
|
||||
if(node.children) {
|
||||
for(var i = 0; i < node.children.length; i++) {
|
||||
var found = findSelectDom(node.children[i]);
|
||||
if(found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function selectedFlags(parent) {
|
||||
var result = [];
|
||||
for(var i = 0; i < parent.children.length; i++) {
|
||||
result.push(!!parent.children[i].selected);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/TiddlyWiki/TiddlyWiki5/issues/9839
|
||||
// PR #8093 added <optgroup> support but used `child.children.length === 0` to
|
||||
// distinguish a plain <option> from an <optgroup>. That heuristic misfires for
|
||||
// any <option> whose contents render to inline HTML elements (e.g. tc-tiddlylink
|
||||
// auto-links generated for "$:/..." titles), so the option's `selected` state
|
||||
// was never restored on refresh.
|
||||
it("preserves multi-select state across refresh when options contain inline HTML children",function() {
|
||||
var wiki = $tw.test.wiki();
|
||||
wiki.addTiddlers([
|
||||
{title: "Picks", mylist: "foo $:/mumble"}
|
||||
]);
|
||||
// Each option has element children to mimic the auto-link case from #9839.
|
||||
// Explicit value attribute lets fakedom resolve option.value (real browsers
|
||||
// fall back to text content).
|
||||
var widgetText = "<$select tiddler='Picks' field='mylist' multiple>" +
|
||||
"<option value='foo'><span>foo</span></option>" +
|
||||
"<option value='bar'><span>bar</span></option>" +
|
||||
"<option value='$:/mumble'><a class='tc-tiddlylink'>$:/mumble</a></option>" +
|
||||
"</$select>";
|
||||
var widgetNode = createWidgetNode(parseText(widgetText,wiki),wiki);
|
||||
var wrapper = renderWidgetNode(widgetNode);
|
||||
var select = findSelectDom(wrapper);
|
||||
expect(select === null).toBe(false);
|
||||
expect(select.children.length).toBe(3);
|
||||
|
||||
// After initial render, options matching the field value should be selected.
|
||||
// foo (idx 0), bar (idx 1), $:/mumble (idx 2).
|
||||
expect(selectedFlags(select)).toEqual([true,false,true]);
|
||||
|
||||
// Change the stored field value and refresh - this is where the bug surfaced:
|
||||
// the "$:/mumble" option (with an <a> child) was wrongly skipped.
|
||||
wiki.addTiddler({title: "Picks", mylist: "bar $:/mumble"});
|
||||
refreshWidgetNode(widgetNode,wrapper,["Picks"]);
|
||||
|
||||
expect(selectedFlags(select)).toEqual([false,true,true]);
|
||||
// The inner <a> must not be touched - .selected is meaningful only on <option>.
|
||||
var innerLinkSelected = select.children[2].children[0].selected;
|
||||
expect(innerLinkSelected === undefined).toBe(true);
|
||||
});
|
||||
|
||||
it("still selects options inside <optgroup> across refresh, including $:/-prefixed entries with inline HTML",function() {
|
||||
var wiki = $tw.test.wiki();
|
||||
wiki.addTiddlers([
|
||||
{title: "Picks", mylist: "1 $:/mumble"}
|
||||
]);
|
||||
// The "high" group mixes a plain option with a $:/-prefixed option whose
|
||||
// content is wrapped in an auto-link <a> - same pattern that broke #9839
|
||||
// for top-level options, exercised here inside an <optgroup>.
|
||||
var widgetText = "<$select tiddler='Picks' field='mylist' multiple>" +
|
||||
"<optgroup label='low'>" +
|
||||
"<option value='1'>1</option>" +
|
||||
"<option value='2'>2</option>" +
|
||||
"</optgroup>" +
|
||||
"<optgroup label='high'>" +
|
||||
"<option value='4'>4</option>" +
|
||||
"<option value='$:/mumble'><a class='tc-tiddlylink'>$:/mumble</a></option>" +
|
||||
"</optgroup>" +
|
||||
"</$select>";
|
||||
var widgetNode = createWidgetNode(parseText(widgetText,wiki),wiki);
|
||||
var wrapper = renderWidgetNode(widgetNode);
|
||||
var select = findSelectDom(wrapper);
|
||||
expect(select === null).toBe(false);
|
||||
expect(select.children.length).toBe(2);
|
||||
|
||||
// Initial state: "1" and "$:/mumble" selected
|
||||
expect(selectedFlags(select.children[0])).toEqual([true,false]);
|
||||
expect(selectedFlags(select.children[1])).toEqual([false,true]);
|
||||
|
||||
wiki.addTiddler({title: "Picks", mylist: "2 4"});
|
||||
refreshWidgetNode(widgetNode,wrapper,["Picks"]);
|
||||
expect(selectedFlags(select.children[0])).toEqual([false,true]);
|
||||
expect(selectedFlags(select.children[1])).toEqual([true,false]);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -468,9 +468,5 @@ describe("WikiText parser tests", function() {
|
||||
|
||||
expect(parse(wikitext)).toEqual(expectedParseTree);
|
||||
});
|
||||
|
||||
it("should reject unquoted macro parameter values that start with <<", function() {
|
||||
var attribute = $tw.utils.parseMacroParameterAsAttribute("d=<<d> />",0);
|
||||
expect(attribute).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ title: TiddlyWiki Archive
|
||||
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.4.0
|
||||
\end
|
||||
|
||||
Older versions of TiddlyWiki are available in the [[archive|https://github.com/TiddlyWiki/tiddlywiki.com-gh-pages/tree/master/archive]]:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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: 20260420192600833
|
||||
modified: 20250807084952911
|
||||
tags: Welcome
|
||||
title: HelloThere
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20150414070451144
|
||||
list: [[HelloThumbnail - Latest Version]] [[HelloThumbnail - Donations]] [[HelloThumbnail - Newsletter]] [[HelloThumbnail - Community Survey 2025]] [[HelloThumbnail - Introduction Video]] [[HelloThumbnail - Grok TiddlyWiki]] [[HelloThumbnail - MultiWikiServer]] [[HelloThumbnail - Twenty Years of TiddlyWiki]] [[HelloThumbnail - TiddlyWiki Privacy]] [[HelloThumbnail - Marketplace]] [[HelloThumbnail - Intertwingled Innovations]] [[HelloThumbnail - TiddlyWikiLinks]]
|
||||
list: [[HelloThumbnail - Donations]] [[HelloThumbnail - Newsletter]] [[HelloThumbnail - Community Survey 2025]] [[HelloThumbnail - Introduction Video]] [[HelloThumbnail - Grok TiddlyWiki]] [[HelloThumbnail - Latest Version]] [[HelloThumbnail - MultiWikiServer]] [[HelloThumbnail - Twenty Years of TiddlyWiki]] [[HelloThumbnail - TiddlyWiki Privacy]] [[HelloThumbnail - Marketplace]] [[HelloThumbnail - Intertwingled Innovations]] [[HelloThumbnail - TiddlyWikiLinks]]
|
||||
modified: 20150414070948246
|
||||
title: HelloThumbnail
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 47 KiB |
+13
@@ -0,0 +1,13 @@
|
||||
[
|
||||
{
|
||||
"created": "20260125202948362",
|
||||
"text": "",
|
||||
"title": "$:/changenotes/5.4.0/#9609/impacts/event detail variables in eventcatcher",
|
||||
"modified": "20260125203132149",
|
||||
"tags": "$:/tags/ImpactNote",
|
||||
"type": "text/vnd.tiddlywiki",
|
||||
"changenote": "$:/changenotes/5.4.0/#9609",
|
||||
"description": "`event-detail*` variables have been removed in favour of the new `eventJSON` variable",
|
||||
"impact-type": "compatibility-break "
|
||||
}
|
||||
]
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
changenote: $:/changenotes/5.4.0/#9609
|
||||
created: 20260125202948362
|
||||
description: `event-detail*` variables have been removed in favour of the new `eventJSON` variable
|
||||
impact-type: compatibility-break
|
||||
modified: 20260428161250718
|
||||
tags: $:/tags/ImpactNote
|
||||
title: $:/changenotes/5.4.0/#9609/impacts/event detail variables in eventcatcher
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -2,7 +2,7 @@ change-category: hackability
|
||||
change-type: enhancement
|
||||
created: 20260228212206750
|
||||
description: Allows modular relinking behavior for plugin support
|
||||
github-contributors: Flibbles
|
||||
github-contributors: flibbles
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9703
|
||||
modified: 20260228212206750
|
||||
release: 5.4.0
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
title: $:/changenotes/5.4.0/#9782
|
||||
description: Update Greek translation
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: translation
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9782
|
||||
github-contributors: superuser-does
|
||||
|
||||
* Translated all new text introduced in 5.4.0
|
||||
* Changed tab captions which weren't proper nouns from __T__itle __C__ase to __S__entence __c__ase
|
||||
* Lowercased export dialog options to match that section of the UI, like in the original English version
|
||||
* Other minor changes and corrections
|
||||
@@ -1,11 +1,10 @@
|
||||
caption: 5.4.0
|
||||
created: 20260420192600833
|
||||
description: Multi Valued Variables, Nested Procedure Calls, Background Actions, New Wikitext Serializer, Bugfixes and much more
|
||||
modified: 20260420192600833
|
||||
released: 20260420192600833
|
||||
created: 20250901000000000
|
||||
modified: 20250901000000000
|
||||
tags: ReleaseNotes
|
||||
title: Release 5.4.0
|
||||
type: text/vnd.tiddlywiki
|
||||
description: Under development
|
||||
|
||||
\procedure release-introduction()
|
||||
Release v5.4.0 deliberately and forensically loosens backwards compatibility to clear the path for significant new features and fundamental improvements to be made in the future.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
caption: 5.4.1
|
||||
created: 20260508181012812
|
||||
modified: 20260508181012812
|
||||
tags: ReleaseNotes
|
||||
title: Release 5.4.1
|
||||
type: text/vnd.tiddlywiki
|
||||
description: Under development
|
||||
|
||||
\procedure release-introduction()
|
||||
Release v5.4.1 is under development.
|
||||
\end release-introduction
|
||||
|
||||
<<releasenote 5.4.1>>
|
||||
@@ -1,13 +1,13 @@
|
||||
title: Multi-Valued Variables
|
||||
created: 20250307212252946
|
||||
modified: 20250307212252946
|
||||
tags: Concepts Variables
|
||||
title: Multi-Valued Variables
|
||||
|
||||
<<.from-version "5.4.0">> In ordinary usage, [[variables|Variables]] contain a single snippet of text. With the introduction of multi-valued variables. it is now possible to store a list of multiple values in a single variable. When accessed in the usual way, only the first value is returned, but using round brackets instead of angle brackets around the variable name allows access to the complete list of the values. This makes multi-valued variables largely invisible unless you specifically need to use them.
|
||||
|
||||
! Setting Multi-Valued Variables
|
||||
|
||||
Generally, all the methods for setting variables implicitly set multi-valued variables, with the exception of the [[Set Widget|SetWidget]].
|
||||
Generally, all the methods for setting variables implicitly set multi-valued variables, with the exception of the [[Set Widget|Set Widget]].
|
||||
|
||||
!! LetWidget
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ The content of the `<$edit-text>` widget is ignored.
|
||||
|size |The size of the input field (in characters). This exact result depends on browser and font. Use the `class` attribute to style width for precise control |
|
||||
|autoHeight |Either "yes" or "no" to specify whether to automatically resize `textarea` editors to fit their content (''defaults'' to "yes"). This setting can be changed globally with an editor toolbar button|
|
||||
|minHeight |Minimum height for automatically resized `textarea` editors, specified in CSS length units such as "px", "em" or "%". Has no effect if the [[CodeMirror Plugin]] is active |
|
||||
|rows|Sets the `rows` attribute of a generated textarea. When combined with `autoHeight="yes"` (the default), it sets the ''initial'' rendered height; the textarea still grows to fit content. To force a fixed number of rows, pair `rows` with `autoHeight="no"`. |
|
||||
|rows|Sets the rows attribute of a generated textarea. `rows` ''takes precedence'' over `autoHeight`, so text areas can be defined individually |
|
||||
|cancelPopups |<<.from-version "5.1.23">> if set to "yes", cancels all popups when the input gets focus |
|
||||
|inputActions |<<.from-version 5.1.23>> Optional actions that are triggered every time an input event occurs within the input field or textarea.<br><<.from-version "5.2.1">> The variable `actionValue` is available to the `inputActions` and contains the value of the input field. |
|
||||
|refreshTitle |<<.from-version 5.1.23>> An optional tiddler title that makes the input field update whenever the specified tiddler changes |
|
||||
|
||||
@@ -15,8 +15,6 @@ Listing/Preview/TextRaw: Text - roh
|
||||
Listing/Preview/Fields: Felder
|
||||
Listing/Preview/Diff: Diff - Text
|
||||
Listing/Preview/DiffFields: Diff - Felder
|
||||
Listing/ImportOptions/Caption: Import Optionen
|
||||
Listing/ImportOptions/NoMatch: Keine Optionen aktiv für diese Files.
|
||||
Listing/Rename/Tooltip: Tiddler vorm Importieren umbenennen
|
||||
Listing/Rename/Prompt: Umbenennen in:
|
||||
Listing/Rename/ConfirmRename : Tiddler umbenennen
|
||||
@@ -33,4 +31,4 @@ Upgrader/System/Alert: Sie sind dabei einen Tiddler zu importieren, der einen "C
|
||||
Upgrader/ThemeTweaks/Created: Migrieren der "theme tweaks" von: <$text text=<<from>>/>.
|
||||
Upgrader/Tiddler/Disabled: Deaktivierter Tiddler.
|
||||
Upgrader/Tiddler/Selected: Ausgewählter Tiddler.
|
||||
Upgrader/Tiddler/Unselected: Auswahl aufgehoben.
|
||||
Upgrader/Tiddler/Unselected: Auswahl aufgehoben.
|
||||
@@ -9,10 +9,10 @@ Advanced/ShadowInfo/NotShadow/Hint: Der Tiddler: <$link to=<<infoTiddler>>><$tex
|
||||
Advanced/ShadowInfo/Shadow/Hint: Der Tiddler: <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> ist ein Schatten-Tiddler.
|
||||
Advanced/ShadowInfo/Shadow/Source: Er ist definiert im Plugin: <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>.
|
||||
Advanced/ShadowInfo/OverriddenShadow/Hint: Der originale Schatten-Tiddler wurde durch diesen Tiddler überschrieben. Wenn Sie diesen Tiddler löschen, wird der originale Schatten-Tiddler wieder aktiv. Erstellen Sie vorher eventuell eine Sicherungskopie!
|
||||
Advanced/CascadeInfo/Heading: Kaskade Details
|
||||
Advanced/CascadeInfo/Hint: ViewTemplate Kaskade - Filter Segmente getagged: <<tag "$:/tags/ViewTemplate">> sind aktiv.
|
||||
Advanced/CascadeInfo/Heading: Kascade Details
|
||||
Advanced/CascadeInfo/Hint: ViewTemplate Kaskade - Filter Segmente getagged: <<tag "$:/tags/ViewTemplate">>.
|
||||
Advanced/CascadeInfo/Detail/View: Ansicht
|
||||
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Filter - Aktive Kaskade
|
||||
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Filter - Aktive Kascade
|
||||
Advanced/CascadeInfo/Detail/Template: Template
|
||||
Fields/Caption: Felder
|
||||
List/Caption: Liste
|
||||
|
||||
@@ -5,8 +5,7 @@ Advanced/Hint: Wewnętrzne informacje na temat TiddlyWiki
|
||||
Appearance/Caption: Wyświetlanie
|
||||
Appearance/Hint: Dostosowywanie wyglądu tej TiddlyWiki
|
||||
Basics/AnimDuration/Prompt: Długość animacji
|
||||
Basics/AutoFocus/Prompt: Domyślnie zfocusowane pole przy tworzeniu nowego tiddlera
|
||||
Basics/AutoFocusEdit/Prompt: Domyślnie zfocusowane pole przy edycji istniejącego tiddlera
|
||||
Basics/AutoFocus/Prompt: Domyślne wybrane pole do edycji przy tworzeniu nowego tiddlera
|
||||
Basics/Caption: Podstawowe
|
||||
Basics/DefaultTiddlers/BottomHint: Tiddlery, które mają spację w nazie otocz [[podwójnymi nawiasami kwadratowymi]]. Możesz też ustawić, by zawsze widzieć {{ostatnio otwarte tiddlery||$:/snippets/retain-story-ordering-button}}
|
||||
Basics/DefaultTiddlers/Prompt: Domyślnie otwarte tiddlery
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
title: $:/language/Draft/
|
||||
|
||||
Attribution: Szkic '<<draft-title>>' autorstwa {{$:/status/UserName}}
|
||||
Title: Szkic '<<draft-title>>'
|
||||
@@ -15,8 +15,6 @@ Listing/Preview/TextRaw: Tekst (oryginalny)
|
||||
Listing/Preview/Fields: Pola
|
||||
Listing/Preview/Diff: Różnica
|
||||
Listing/Preview/DiffFields: Róznica (Pola)
|
||||
Listing/ImportOptions/Caption: Opcje importu
|
||||
Listing/ImportOptions/NoMatch: Żadna z opcji importu nie możę być zastosowana do tych plików.
|
||||
Listing/Rename/Tooltip: Zmień nazwę tiddlera przed importem
|
||||
Listing/Rename/Prompt: Zmień nazwę na:
|
||||
Listing/Rename/ConfirmRename: Zmień nazwę tiddlera
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
title: $:/language/
|
||||
|
||||
Alerts: Powiadomienia
|
||||
AboveStory/ClassicPlugin/Warning: Wygląda na to, że próbujesz wczytać wtyczkę zaprojektowaną dla ~TiddlyWiki Classic. Zwróc uwagę, że [[te wtyczki nie działają z TiddlyWiki 5|https://tiddlywiki.com/#TiddlyWikiClassic]]. Wykryte wtyczki ~TiddlyWiki Classic:
|
||||
BinaryWarning/Prompt: Ten tiddler zawiera binarne dane
|
||||
ClassicWarning/Hint: Ten tiddler został napisany w formacie dla TiddlyWiki Classic, który nie jest w pełni kompatybilny z TiddlyWiki 5. Więcej informacji dostępnych pod adresem https://tiddlywiki.com/static/Upgrading.html.
|
||||
|
||||
@@ -9,12 +9,6 @@ Advanced/ShadowInfo/NotShadow/Hint: Tiddler <$link to=<<infoTiddler>>><$text tex
|
||||
Advanced/ShadowInfo/Shadow/Hint: Tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> jest tiddlerem-cieniem
|
||||
Advanced/ShadowInfo/Shadow/Source: Zdefiniiowany we wtyczce <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>
|
||||
Advanced/ShadowInfo/OverriddenShadow/Hint: Nadpisany przez zwykłego tiddlera
|
||||
Advanced/CascadeInfo/Heading: Szczegóły Kaskady
|
||||
Advanced/CascadeInfo/Hint: These are the view template segments that are resolved for each of the system view template cascades
|
||||
Advanced/CascadeInfo/Hint: Lista elementów widoku, których kaskady określają szablony użyte do wyświetlenia tiddlera
|
||||
Advanced/CascadeInfo/Detail/View: Widok
|
||||
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Aktywny filtr kaskady
|
||||
Advanced/CascadeInfo/Detail/Template: Szablon
|
||||
Fields/Caption: Pola
|
||||
List/Caption: Lista
|
||||
List/Empty: Ten tiddler nie posiada żadnych list
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)
|
||||
|
||||
Copyright (c) 2004-2007, Jeremy Ruston
|
||||
Copyright (c) 2007-2026, UnaMesa Association
|
||||
Copyright (c) 2007-2025, UnaMesa Association
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -649,5 +649,3 @@ Rishu kumar, @rishu-7549, 2025/10/25
|
||||
@kjharcombe, 2026/03/16
|
||||
|
||||
Himmel, @NotHimmel, 2026/03/19
|
||||
|
||||
@sean-clayton, 2026/05/16
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "tiddlywiki",
|
||||
"version": "5.4.0",
|
||||
"version": "5.4.0-prerelease",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "tiddlywiki",
|
||||
"version": "5.4.0",
|
||||
"version": "5.4.0-prerelease",
|
||||
"license": "BSD",
|
||||
"bin": {
|
||||
"tiddlywiki": "tiddlywiki.js"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tiddlywiki",
|
||||
"preferGlobal": true,
|
||||
"version": "5.4.1-prerelease",
|
||||
"version": "5.4.0-prerelease",
|
||||
"author": "Jeremy Ruston <jeremy@jermolene.com>",
|
||||
"description": "a non-linear personal web notebook",
|
||||
"contributors": [
|
||||
|
||||
+3
-11
@@ -6,8 +6,6 @@ const { defineConfig, devices } = require('@playwright/test');
|
||||
module.exports = defineConfig({
|
||||
testDir: './editions/test/',
|
||||
|
||||
timeout: 60000,
|
||||
|
||||
// Allow parallel tests
|
||||
fullyParallel: true,
|
||||
|
||||
@@ -25,17 +23,11 @@ module.exports = defineConfig({
|
||||
|
||||
// Settings shared with all the tests
|
||||
use: {
|
||||
// Take a screenshot when the test fails
|
||||
screenshot: {
|
||||
mode: 'only-on-failure',
|
||||
fullPage: true
|
||||
},
|
||||
// Limit individual actions (like click/type) so they don't hang indefinitely
|
||||
actionTimeout: 15000,
|
||||
},
|
||||
|
||||
expect: {
|
||||
// Give expect() assertions more time to find elements like '.jasmine-overall-result'
|
||||
timeout: 20000,
|
||||
}
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
@@ -47,7 +39,7 @@ module.exports = defineConfig({
|
||||
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] }
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -256,11 +256,12 @@ CodeMirrorEngine.prototype.getText = function() {
|
||||
Fix the height of textarea to fit content
|
||||
*/
|
||||
CodeMirrorEngine.prototype.fixHeight = function() {
|
||||
if(this.widget.editAutoHeight) {
|
||||
// rows takes precedence
|
||||
if(this.widget.editRows) {
|
||||
this.cm.setSize(null,this.widget.editRows + "em");
|
||||
} else if(this.widget.editAutoHeight) {
|
||||
// Resize to fit
|
||||
this.cm.setSize(null,null);
|
||||
} else if(this.widget.editRows) {
|
||||
this.cm.setSize(null,this.widget.editRows + "em");
|
||||
} else {
|
||||
var fixedHeight = parseInt(this.widget.wiki.getTiddlerText(HEIGHT_VALUE_TITLE,"400px"),10);
|
||||
fixedHeight = Math.max(fixedHeight,20);
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,9 @@
|
||||
<h1 class="">Welcome</h1><p>Welcome to <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a>, a non-linear personal web notebook that anyone can use and keep forever, independently of any corporation.</p><p>TiddlyWiki is a complete interactive wiki in JavaScript. It can be used as a single HTML file in the browser or as a powerful Node.js application. It is highly customisable: the entire user interface is itself implemented in hackable <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/WikiText.html">WikiText</a>.</p><h2 class="">Demo</h2><p>Learn more and see it in action at <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/</a></p><h2 class="">Developer Documentation</h2><p>Developer documentation is in progress at <a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev/" rel="noopener noreferrer" target="_blank">https://tiddlywiki.com/dev/</a></p><h2 class="">Pull Request Previews</h2><p>Pull request previews courtesy of <a class="tc-tiddlylink-external" href="https://netlify.com" rel="noopener noreferrer" target="_blank">Netlify</a></p><p><a href="https://www.netlify.com" rel="noopener noreferrer" target="_blank"><img alt="Deploys by Netlify" src="https://www.netlify.com/v3/img/components/netlify-light.svg"></a></p><h1 class="">Join the Community</h1><p>
|
||||
<h2 class="">User forums</h2><h3 class="">Talk TiddlyWiki</h3><p>As the official TiddlyWiki forum, Talk TiddlyWiki is a place to talk about TiddlyWiki: requests for help, <a class="tc-tiddlylink-external" href="https://talk.tiddlywiki.org/c/announcements/20" rel="noopener noreferrer" target="_blank">announcements</a> of new releases and plugins, debating new features, or just sharing experiences. You can participate via the associated website, or subscribe via email.</p><p><a class="tc-tiddlylink-external" href="https://talk.tiddlywiki.org/" rel="noopener noreferrer" target="_blank">https://talk.tiddlywiki.org/</a></p><h3 class="">Google Groups</h3><p>For the convenience of existing users, we also continue to operate the original TiddlyWiki group (hosted on Google Groups since 2005): <a class="tc-tiddlylink-external" href="https://groups.google.com/group/TiddlyWiki" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/TiddlyWiki</a></p><h2 class="">Developer forums</h2><ul><li><a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">tiddlywiki.com/dev</a> is the official developer documentation</li><li>Get involved in the <a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5" rel="noopener noreferrer" target="_blank">development on GitHub</a></li><li><a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5/discussions" rel="noopener noreferrer" target="_blank">GitHub Discussions</a> are for Q&A and open-ended discussion</li><li><a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5/issues" rel="noopener noreferrer" target="_blank">GitHub Issues</a> are for raising bug reports and proposing specific, actionable new ideas</li><li>See <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Contributing.html">Contributing</a> for guidelines on how to contribute to the project.</li></ul><h2 class="">Other forums</h2><ul><li><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> Subreddit: <a class="tc-tiddlylink-external" href="https://www.reddit.com/r/TiddlyWiki5/" rel="noopener noreferrer" target="_blank">/r/TiddlyWiki5</a></li><li>Chat on Discord at <a class="tc-tiddlylink-external" href="https://discord.gg/HFFZVQ8" rel="noopener noreferrer" target="_blank">https://discord.gg/HFFZVQ8</a></li></ul>
|
||||
</p><hr><h1 class="">Installing TiddlyWiki on Node.js</h1><p>TiddlyWiki is a <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/SingleFileApplication.html">SingleFileApplication</a>, which is easy to use. For advanced users and developers there is a possibility to use a Node.js client / server configuration. This configuration is also used to build the TiddlyWiki <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/SinglePageApplication.html">SinglePageApplication</a></p><ol><li>Install <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Node.js.html">Node.js</a><ul><li>Linux: <blockquote><div><em>Debian/Ubuntu</em>:<br><code>apt install nodejs</code><br>May need to be followed up by:<br><code>apt install npm</code></div><div><em>Arch Linux</em><br><code>yay -S tiddlywiki</code> <br>(installs node and tiddlywiki)</div></blockquote></li><li>Mac<blockquote><div><code>brew install node</code></div></blockquote></li><li>Android<blockquote><div><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Serving%2520TW5%2520from%2520Android.html">Termux for Android</a></div></blockquote></li><li>Other <blockquote><div>See <a class="tc-tiddlylink-external" href="http://nodejs.org" rel="noopener noreferrer" target="_blank">http://nodejs.org</a></div></blockquote></li></ul></li><li>Open a command line terminal and type:<blockquote><div><code>npm install -g tiddlywiki</code></div><div>If it fails with an error you may need to re-run the command as an administrator:</div><div><code>sudo npm install -g tiddlywiki</code> (Mac/Linux)</div></blockquote></li><li>Ensure TiddlyWiki is installed by typing:<blockquote><div><code>tiddlywiki --version</code></div></blockquote><ul><li>In response, you should see <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> report its current version (eg "5.4.0". You may also see other debugging information reported.)</li></ul></li><li>Try it out:<ol><li><code>tiddlywiki mynewwiki --init server</code> to create a folder for a new wiki that includes server-related components</li><li><code>tiddlywiki mynewwiki --listen</code> to start <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a></li><li>Visit <a class="tc-tiddlylink-external" href="http://127.0.0.1:8080/" rel="noopener noreferrer" target="_blank">http://127.0.0.1:8080/</a> in your browser</li><li>Try editing and creating tiddlers</li></ol></li><li>Optionally, make an offline copy:<ul><li>click the <span class="doc-icon"><svg class="tc-image-save-button-dynamic tc-image-button" height="22pt" viewBox="0 0 128 128" width="22pt">
|
||||
<h2 class="">Official Forums</h2><h3 class=""><a class="tc-tiddlylink-external" href="https://talk.tiddlywiki.org/" rel="noopener noreferrer" target="_blank">https://talk.tiddlywiki.org/</a></h3><blockquote class="tc-quote"><p>The new official forum for talking about TiddlyWiki: requests for help, <a class="tc-tiddlylink-external" href="https://talk.tiddlywiki.org/c/announcements/20" rel="noopener noreferrer" target="_blank">announcements</a> of new releases and plugins, debating new features, or just sharing experiences. You can participate via the associated website, or subscribe via email.</p><p><strong>talk.tiddlywiki.org</strong> is a community run service that we host and maintain ourselves. The modest running costs are covered by community contributions.
|
||||
</p></blockquote><h4 class="">Google Groups</h4><blockquote class="tc-quote"><p>For the convenience of existing users, we also continue to operate the original TiddlyWiki group (hosted on Google Groups since 2005): <a class="tc-tiddlylink-external" href="https://groups.google.com/group/TiddlyWiki" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/TiddlyWiki</a>
|
||||
</p></blockquote><h2 class="">Developer Forums</h2><h2 class=""><a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5/graphs/contributors" rel="noopener noreferrer" target="_blank">GitHub Stats</a></h2><p>There are several resources for developers to learn more about <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> and to discuss and contribute to its development.</p><blockquote><div><img class=" tc-image-loading" src="https://repobeats.axiom.co/api/embed/b92b1b363e2b5f26837ae573a60d39b4248b50a0.svg"></div></blockquote><ul><li><a class="tc-tiddlylink-external" href="https://tiddlywiki.com/dev" rel="noopener noreferrer" target="_blank">tiddlywiki.com/dev</a> is the official developer documentation</li><li>Get involved in the <a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5" rel="noopener noreferrer" target="_blank">development on GitHub</a></li><li><a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5/discussions" rel="noopener noreferrer" target="_blank">GitHub Discussions</a> are for Q&A and open-ended discussion</li><li><a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5/issues" rel="noopener noreferrer" target="_blank">GitHub Issues</a> are for raising bug reports and proposing specific, actionable new ideas</li><li>The older TiddlyWikiDev Google Group is now closed in favour of <a class="tc-tiddlylink-external" href="https://talk.tiddlywiki.org/" rel="noopener noreferrer" target="_blank">Talk TiddlyWiki</a> and <a class="tc-tiddlylink-external" href="https://github.com/TiddlyWiki/TiddlyWiki5/discussions" rel="noopener noreferrer" target="_blank">GitHub Discussions</a> <ul><li>It remains a useful archive: <a class="tc-tiddlylink-external" href="https://groups.google.com/group/TiddlyWikiDev" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/TiddlyWikiDev</a><ul><li>An enhanced group search facility is available on <a class="tc-tiddlylink-external" href="https://www.mail-archive.com/tiddlywikidev@googlegroups.com/" rel="noopener noreferrer" target="_blank">mail-archive.com</a></li></ul></li></ul></li></ul><h2 class="">Other Forums</h2><ul><li><a class="tc-tiddlylink-external" href="https://www.reddit.com/r/TiddlyWiki5/" rel="noopener noreferrer" target="_blank">TiddlyWiki Subreddit</a></li><li>Chat on Discord at <a class="tc-tiddlylink-external" href="https://discord.gg/HFFZVQ8" rel="noopener noreferrer" target="_blank">https://discord.gg/HFFZVQ8</a></li></ul><h3 class="">Documentation</h3><p>There is also a discussion group specifically for discussing <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> documentation improvement initiatives: <a class="tc-tiddlylink-external" href="https://groups.google.com/group/tiddlywikidocs" rel="noopener noreferrer" target="_blank">https://groups.google.com/group/tiddlywikidocs</a>
|
||||
</p>
|
||||
</p><hr><h1 class="">Installing TiddlyWiki on Node.js</h1><p>TiddlyWiki is a <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/SingleFileApplication.html">SingleFileApplication</a>, which is easy to use. For advanced users and developers there is a possibility to use a Node.js client / server configuration. This configuration is also used to build the TiddlyWiki <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/SinglePageApplication.html">SinglePageApplication</a></p><ol><li>Install <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Node.js.html">Node.js</a><ul><li>Linux: <blockquote><div><em>Debian/Ubuntu</em>:<br><code>apt install nodejs</code><br>May need to be followed up by:<br><code>apt install npm</code></div><div><em>Arch Linux</em><br><code>yay -S tiddlywiki</code> <br>(installs node and tiddlywiki)</div></blockquote></li><li>Mac<blockquote><div><code>brew install node</code></div></blockquote></li><li>Android<blockquote><div><a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/Serving%2520TW5%2520from%2520Android.html">Termux for Android</a></div></blockquote></li><li>Other <blockquote><div>See <a class="tc-tiddlylink-external" href="http://nodejs.org" rel="noopener noreferrer" target="_blank">http://nodejs.org</a></div></blockquote></li></ul></li><li>Open a command line terminal and type:<blockquote><div><code>npm install -g tiddlywiki</code></div><div>If it fails with an error you may need to re-run the command as an administrator:</div><div><code>sudo npm install -g tiddlywiki</code> (Mac/Linux)</div></blockquote></li><li>Ensure TiddlyWiki is installed by typing:<blockquote><div><code>tiddlywiki --version</code></div></blockquote><ul><li>In response, you should see <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a> report its current version (eg "5.3.8". You may also see other debugging information reported.)</li></ul></li><li>Try it out:<ol><li><code>tiddlywiki mynewwiki --init server</code> to create a folder for a new wiki that includes server-related components</li><li><code>tiddlywiki mynewwiki --listen</code> to start <a class="tc-tiddlylink tc-tiddlylink-resolves" href="https://tiddlywiki.com/static/TiddlyWiki.html">TiddlyWiki</a></li><li>Visit <a class="tc-tiddlylink-external" href="http://127.0.0.1:8080/" rel="noopener noreferrer" target="_blank">http://127.0.0.1:8080/</a> in your browser</li><li>Try editing and creating tiddlers</li></ol></li><li>Optionally, make an offline copy:<ul><li>click the <span class="doc-icon"><svg class="tc-image-save-button-dynamic tc-image-button" height="22pt" viewBox="0 0 128 128" width="22pt">
|
||||
<g class="tc-image-save-button-dynamic-clean">
|
||||
<path d="M120.783 34.33c4.641 8.862 7.266 18.948 7.266 29.646 0 35.347-28.653 64-64 64-35.346 0-64-28.653-64-64 0-35.346 28.654-64 64-64 18.808 0 35.72 8.113 47.43 21.03l2.68-2.68c3.13-3.13 8.197-3.132 11.321-.008 3.118 3.118 3.121 8.193-.007 11.32l-4.69 4.691zm-12.058 12.058a47.876 47.876 0 013.324 17.588c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48c14.39 0 27.3 6.332 36.098 16.362L58.941 73.544 41.976 56.578c-3.127-3.127-8.201-3.123-11.32-.005-3.123 3.124-3.119 8.194.006 11.319l22.617 22.617a7.992 7.992 0 005.659 2.347c2.05 0 4.101-.783 5.667-2.349l44.12-44.12z" fill-rule="evenodd"></path>
|
||||
</g>
|
||||
|
||||
Reference in New Issue
Block a user