1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-06-17 02:49:54 +00:00

Support global macros via the importvariables widget

The new importvariables widget imports macro/variable definitions from
the specified tiddlers and makes them available to its children.

Allows us to split PageMacros up into separate tiddlers.

We still support loading macros from $:/core/ui/PageMacros to help
people upgrading.

Fixes #644 and #559
This commit is contained in:
Jermolene 2014-06-12 18:01:33 +01:00
parent 0e09fbf46a
commit 9ab0c84140
12 changed files with 211 additions and 52 deletions

View File

@ -21,7 +21,7 @@ exports.synchronous = true;
// Default story and history lists
var PAGE_TITLE_TITLE = "$:/core/wiki/title"
var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet";
var PAGE_TEMPLATE_TITLE = "$:/core/ui/PageMacros";
var PAGE_TEMPLATE_TITLE = "$:/core/ui/PageTemplate";
// Time (in ms) that we defer refreshing changes to draft tiddlers
var DRAFT_TIDDLER_TIMEOUT = 400;
@ -49,7 +49,7 @@ exports.startup = function() {
$tw.styleElement.innerHTML = $tw.styleContainer.textContent;
}
}));
// Display the $:/core/ui/PageMacros tiddler to kick off the display
// Display the $:/core/ui/PageTemplate tiddler to kick off the display
$tw.perf.report("mainRender",function() {
$tw.pageWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_TEMPLATE_TITLE,{document: document, parentWidget: $tw.rootWidget});
$tw.pageContainer = document.createElement("div");

View File

@ -0,0 +1,115 @@
/*\
title: $:/core/modules/widgets/importvariables.js
type: application/javascript
module-type: widget
Import variable definitions from other tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var ImportVariablesWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
ImportVariablesWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
ImportVariablesWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
};
/*
Compute the internal state of the widget
*/
ImportVariablesWidget.prototype.execute = function(tiddlerList) {
var self = this;
// Get our parameters
this.filter = this.getAttribute("filter");
// Compute the filter
this.tiddlerList = tiddlerList || this.wiki.filterTiddlers(this.filter,this);
// Accumulate the <$set> widgets from each tiddler
var widgetStackStart,widgetStackEnd;
function addWidgetNode(widgetNode) {
if(widgetNode) {
if(!widgetStackStart && !widgetStackEnd) {
widgetStackStart = widgetNode;
widgetStackEnd = widgetNode;
} else {
widgetStackEnd.children = [widgetNode];
widgetStackEnd = widgetNode;
}
}
}
$tw.utils.each(this.tiddlerList,function(title) {
var parser = self.wiki.parseTiddler(title);
if(parser) {
var parseTreeNode = parser.tree[0];
while(parseTreeNode && parseTreeNode.type === "set") {
addWidgetNode({
type: "set",
attributes: parseTreeNode.attributes,
params: parseTreeNode.params
});
parseTreeNode = parseTreeNode.children[0];
}
}
});
// Add our own children to the end of the pile
var parseTreeNodes;
if(widgetStackStart && widgetStackEnd) {
parseTreeNodes = [widgetStackStart];
widgetStackEnd.children = this.parseTreeNode.children;
} else {
parseTreeNodes = this.parseTreeNode.children;
}
// Construct the child widgets
this.makeChildWidgets(parseTreeNodes);
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ImportVariablesWidget.prototype.refresh = function(changedTiddlers) {
// Recompute our attributes and the filter list
var changedAttributes = this.computeAttributes(),
tiddlerList = this.wiki.filterTiddlers(this.getAttribute("filter"),this);
// Refresh if the filter has changed, or the list of tiddlers has changed, or any of the tiddlers in the list has changed
function haveListedTiddlersChanged() {
var changed = false;
tiddlerList.forEach(function(title) {
if(changedTiddlers[title]) {
changed = true;
}
});
return changed;
}
if(changedAttributes.filter || !$tw.utils.isArrayEqual(this.tiddlerList,tiddlerList) || haveListedTiddlersChanged()) {
// Compute the filter
console.log("Refreshing importvariables with filter=",this.getAttribute("filter"));
this.removeChildDomNodes();
this.execute(tiddlerList);
this.renderChildren(this.parentDomNode,this.findNextSiblingDomNode());
return true;
} else {
return this.refreshChildren(changedTiddlers);
}
};
exports.importvariables = ImportVariablesWidget;
})();

View File

@ -21,6 +21,6 @@ type: text/vnd.tiddlywiki-html
</head>
<body class="tw-body">
{{$:/StaticBanner||$:/core/templates/html-tiddler}}
{{$:/core/ui/PageMacros||$:/core/templates/html-tiddler}}
{{$:/core/ui/PageTemplate||$:/core/templates/html-tiddler}}
</body>
</html>

View File

@ -15,7 +15,9 @@ title: $:/core/templates/static.tiddler.html
<body class="tw-body">
`{{$:/StaticBanner||$:/core/templates/html-tiddler}}`
<section class="story-river">
`<$view tiddler="$:/core/ui/ViewTemplate" format="htmlwikified"/>`
`<$importvariables filter="[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]">
<$view tiddler="$:/core/ui/ViewTemplate" format="htmlwikified"/>
</$importvariables>`
</section>
</body>
</html>

View File

@ -4,6 +4,8 @@ title: $:/core/ui/PageTemplate
tw-page-container tw-page-view-$(themeTitle)$ tw-language-$(languageTitle)$
\end
<$importvariables filter="[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]">
<$set name="themeTitle" value={{$:/view}}>
<$set name="currentTiddler" value={{$:/language}}>
@ -37,3 +39,5 @@ tw-page-container tw-page-view-$(themeTitle)$ tw-language-$(languageTitle)$
</$set>
</$set>
</$importvariables>

10
core/wiki/macros/CSS.tid Normal file
View File

@ -0,0 +1,10 @@
title: $:/core/macros/CSS
tags: $:/tags/Macro
\define colour(name)
<$transclude tiddler={{$:/palette}} index="$name$"/>
\end
\define color(name)
<<colour $name$>>
\end

View File

@ -0,0 +1,10 @@
title: $:/core/macros/lingo
tags: $:/tags/Macro
\define lingo-base()
$:/lingo/
\end
\define lingo(title)
{{$(lingo-base)$$title$}}
\end

View File

@ -1,12 +1,5 @@
title: $:/core/ui/PageMacros
\define colour(name)
<$transclude tiddler={{$:/palette}} index="$name$"/>
\end
\define color(name)
<<colour $name$>>
\end
title: $:/core/macros/tabs
tags: $:/tags/Macro
\define tabs(tabsList,default,state:"$:/state/tab",class)
<div class="tw-tab-set $class$">
@ -27,40 +20,3 @@ title: $:/core/ui/PageMacros
</div>
</div>
\end
\define wikitext-example(src)
```
$src$
```
Renders as:
$src$
In HTML:
$$$text/vnd.tiddlywiki>text/html
$src$
$$$
\end
\define wikitext-example-without-html(src)
```
$src$
```
Renders as:
$src$
\end
\define lingo-base()
$:/lingo/
\end
\define lingo(title)
{{$(lingo-base)$$title$}}
\end
{{$:/core/ui/PageTemplate}}

View File

@ -23,4 +23,4 @@ It also determines the standard UI flow:
# The core then issues a store change event which triggers the refresh cycle
# Each widget in the tree then gets a chance to refresh itself to reflect the changes in the store if they need to
From a technical perspective, TiddlyWiki is a fairly classic MVC architecture, with strict separation of concerns. The model is the tiddler store, the view is a rendering tree (such as the one created from [[$:/core/ui/PageMacros]] in startup.js), and the controller is the core code itself.
From a technical perspective, TiddlyWiki is a fairly classic MVC architecture, with strict separation of concerns. The model is the tiddler store, the view is a rendering tree (such as the one created from [[$:/core/ui/PageTemplate]] in startup.js), and the controller is the core code itself.

View File

@ -6,7 +6,7 @@ type: text/vnd.tiddlywiki
The StateMechanism in TiddlyWiki is at the heart of how complex user interfaces can be built from WikiText.
In the browser, the TiddlyWiki display is produced by dynamically rendering the tiddler [[$:/core/ui/PageMacros]]. Through various transclusions and other widgets it renders the entire user interface. The dynamic rendering is accomplished by a mechanism called "binding": any changes to the tiddlers in the store are dynamically reflected in the browser display.
In the browser, the TiddlyWiki display is produced by dynamically rendering the tiddler [[$:/core/ui/PageTemplate]]. Through various transclusions and other widgets it renders the entire user interface. The dynamic rendering is accomplished by a mechanism called "binding": any changes to the tiddlers in the store are dynamically reflected in the browser display.
The stack of templates that make up the TiddlyWiki display are complex but we'll focus on the line that displays the main story column:

View File

@ -0,0 +1,30 @@
title: $:/editions/tw5.com/wikitext-macros
tags: $:/tags/Macro
\define wikitext-example(src)
```
$src$
```
Renders as:
$src$
In HTML:
$$$text/vnd.tiddlywiki>text/html
$src$
$$$
\end
\define wikitext-example-without-html(src)
```
$src$
```
Renders as:
$src$
\end

View File

@ -0,0 +1,32 @@
created: 20140612142500000
modified: 20140612175900970
tags: widget
title: ImportVariablesWidget
type: text/vnd.tiddlywiki
! Introduction
The ImportVariablesWidget imports macro and variable definitions from a list of other tiddlers and makes them available to its children. For example:
```
<$importvariables filter="[tag[mySpecialMacros]]">
All the macros defined in tiddlers with the tag "mySpecialMacros" are available here
</$importvariables>
```
! Attributes and Content
The content of the importvariables widget is the scope within which the imported variable definitions are available.
|!Attribute |!Description |
|filter |[[Tiddler filter|TiddlerFilters]] defining the tiddlers from which macro definitions will be imported |
! Global Macros
So-called global macros are implemented within the main page template ([[$:/core/ui/PageTemplate]]) by wrapping the page content in the following importvariables widget:
```
<$importvariables filter="[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]">
...
</$importvariables>
```