diff --git a/core/modules/utils/fakedom.js b/core/modules/utils/fakedom.js
index 4a756f43d..3100e731d 100755
--- a/core/modules/utils/fakedom.js
+++ b/core/modules/utils/fakedom.js
@@ -45,10 +45,28 @@ var TW_Element = function(tag,namespace) {
this.attributes = {};
this.isRaw = false;
this.children = [];
- this.style = {};
+ this._style = {};
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
};
+Object.defineProperty(TW_Element.prototype, "style", {
+ get: function() {
+ return this._style;
+ },
+ set: function(str) {
+ var self = this;
+ str = str || "";
+ $tw.utils.each(str.split(";"),function(declaration) {
+ var parts = declaration.split(":"),
+ name = $tw.utils.trim(parts[0]),
+ value = $tw.utils.trim(parts[1]);
+ if(name && value) {
+ self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value;
+ }
+ });
+ }
+});
+
Object.defineProperty(TW_Element.prototype, "nodeType", {
get: function() {
return 1;
@@ -169,13 +187,13 @@ Object.defineProperty(TW_Element.prototype, "outerHTML", {
}
}
}
- if(this.style) {
+ if(this._style) {
var style = [];
- for(var s in this.style) {
- style.push(s + ":" + this.style[s] + ";");
+ for(var s in this._style) {
+ style.push($tw.utils.convertPropertyNameToStyleName(s) + ":" + this._style[s] + ";");
}
if(style.length > 0) {
- output.push(" style=\"",style.join(""),"\"")
+ output.push(" style=\"",style.join(""),"\"");
}
}
output.push(">");
diff --git a/editions/innerwikidemo/tiddlers/HelloThere.tid b/editions/innerwikidemo/tiddlers/HelloThere.tid
index 84a0ad99f..9b85ae530 100644
--- a/editions/innerwikidemo/tiddlers/HelloThere.tid
+++ b/editions/innerwikidemo/tiddlers/HelloThere.tid
@@ -8,5 +8,7 @@ To try these examples under Node.js:
# Execute the following command in the root of the TiddlyWiki 5 repo:
```
-./tiddlywiki.js editions/innerwikidemo --screenshot '[[$:/plugins/tiddlywiki/innerwiki/examples]]' 4
+./tiddlywiki.js editions/innerwikidemo --screenshot '[[$:/plugins/tiddlywiki/innerwiki/examples]]' 4 --render '[[$:/plugins/tiddlywiki/innerwiki/examples]]' "examples.html"
```
+
+Open `examples.html` to see the generated static HTML rendering.
diff --git a/plugins/tiddlywiki/innerwiki/doc/examples.tid b/plugins/tiddlywiki/innerwiki/doc/examples.tid
index 64fbc8888..f1dab0213 100644
--- a/plugins/tiddlywiki/innerwiki/doc/examples.tid
+++ b/plugins/tiddlywiki/innerwiki/doc/examples.tid
@@ -1,5 +1,11 @@
title: $:/plugins/tiddlywiki/innerwiki/examples
+\define big-arrow(x,y,colour:"#ff0000",border:"#000000")
+
+
+
+\end
+
\define example(text)
<$codeblock code=<<__text__>>/>
@@ -12,10 +18,10 @@ $text$
The innerwiki widget specifies the dimensions of the virtual screen used to render the wiki (in pixels) and CSS styles to apply to it. Nested `<$data>` widgets are used to specify individual payload tiddlers to be loaded into the wiki. In this example, we initialise the innerwiki with two tiddlers "HelloThere" and "$:/DefaultTiddlers":
-<
+<$macrocall $name="example" text="""<$innerwiki width="1200" height="400" style="width:100%;" filename="screenshot-1.png">
<$data title="HelloThere" text="This tiddler is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
-$innerwiki>""">>
+$innerwiki>"""/>
Note that the "screenshot" is a shrunken but fully interactive TiddlyWiki.
@@ -24,50 +30,70 @@ Note that the "screenshot" is a shrunken but fully interactive TiddlyWiki.
To render these examples as a PNG bitmap under Node.js, execute the following at the command prompt:
```
-tiddlywiki mywiki --screenshot $:/plugins/tiddlywiki/innerwiki/examples
+tiddlywiki editions/innerwikidemo --screenshot $:/plugins/tiddlywiki/innerwiki/examples
```
The screenshots will be saved as `screenshot-1.png` etc in the `./output` folder of the wiki.
+To render this example tiddler as a static HTML file that embeds the screenshot images and includes the SVG overlays:
+
+```
+tiddlywiki editions/innerwikidemo --render '[[$:/plugins/tiddlywiki/innerwiki/examples]]' "examples.html" --build index
+```
+
+!! SVG overlays
+
+Any displayable content within innerwiki widget is displayed within an automatically created SVG element. This allows overlays to be added:
+
+<$macrocall $name="example" text="""<$innerwiki width="1200" height="400" style="width:100%;" filename="screenshot-2.png">
+ <$data title="HelloThere" text="This tiddler is inside a wiki"/>
+ <$data title="$:/DefaultTiddlers" text="HelloThere"/>
+
+ <>
+$innerwiki>"""/>
+
+Notice how macros can be used to encapsulate SVG fragments ([[see the source of this tiddler|$:/plugins/tiddlywiki/innerwiki/examples]]).
+
!! Clipping
A clipping rectangle can be applied to limit the area of the wiki that is displayed. For example:
-<
+<$macrocall $name="example" text="""<$innerwiki width="1200" height="400" style="width:100%;" clipLeft="500" clipTop="100" clipWidth="600" clipHeight="300" filename="screenshot-3.png">
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
-$innerwiki>""">>
+$innerwiki>"""/>
!! Transcluding payload tiddlers
This example shows how the `<$data>` widget can be transcluded from other tiddlers (see $:/plugins/tiddlywiki/innerwiki/example-data):
-<
+<$macrocall $name="example" text="""<$innerwiki width="600" height="400" style="width:100%;" filename="screenshot-4.png">
{{$:/plugins/tiddlywiki/innerwiki/example-data}}
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
-$innerwiki>""">>
+$innerwiki>"""/>
!! Customising the wiki state
By injecting the right payload tiddlers, the innerwiki can be initialised to any desired state. In this example we inject a configuration tiddler to make the "more" page control button visible, and a state tiddler to cause the dropdown to appear:
-<
+<$macrocall $name="example" text="""<$innerwiki template="$:/plugins/tiddlywiki/innerwiki/template" filename="screenshot-5.png" width="1200" height="400" clipLeft="500" clipTop="100" clipWidth="600" clipHeight="300" style="width:100%;">
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere"/>
<$data title="$:/config/PageControlButtons/Visibility/$:/core/ui/Buttons/more-page-actions" text="show"/>
<$data title="$:/state/popup/more--1600698846" text="(151,144,21,25)"/>
-$innerwiki>""">>
+$innerwiki>"""/>
!! Inception
An innerwiki can itself contain an inner-innerwiki:
-<
+<$macrocall $name="example" text="""<$innerwiki width="1200" height="600" style="width:100%;" filename="screenshot-6.png">
<$data title="HelloThere" text="! This tiddler is inside a wiki that is inside a wiki"/>
<$data title="$:/DefaultTiddlers" text="HelloThere $:/plugins/tiddlywiki/innerwiki/inner-example"/>
<$data $tiddler="$:/plugins/tiddlywiki/innerwiki"/>
-$innerwiki>""">>
+ <>
+$innerwiki>"""/>
(You can see the innerwiki here: $:/plugins/tiddlywiki/innerwiki/inner-example)
diff --git a/plugins/tiddlywiki/innerwiki/innerwiki.js b/plugins/tiddlywiki/innerwiki/innerwiki.js
index 7c1cdc629..05c4a148a 100644
--- a/plugins/tiddlywiki/innerwiki/innerwiki.js
+++ b/plugins/tiddlywiki/innerwiki/innerwiki.js
@@ -40,11 +40,19 @@ InnerWikiWidget.prototype.render = function(parent,nextSibling) {
classes.push("tc-innerwiki-wrapper");
domWrapper.className = classes.join(" ");
domWrapper.style = this.innerWikiStyle;
+ domWrapper.style.overflow = "hidden";
+ domWrapper.style.position = "relative";
+ domWrapper.style.boxSizing = "content-box";
+ // Set up the SVG container
+ var domSVG = this.document.createElementNS("http://www.w3.org/2000/svg","svg");
+ domSVG.style = this.innerWikiStyle;
+ domSVG.style.position = "absolute";
+ domSVG.style.zIndex = "1";
+ domSVG.setAttribute("viewBox","0 0 " + this.innerWikiClipWidth + " " + this.innerWikiClipHeight);
+ domWrapper.appendChild(domSVG);
+ this.setVariable("namespace","http://www.w3.org/2000/svg");
// If we're on the real DOM, adjust the wrapper and iframe
if(!this.document.isTiddlyWikiFakeDom) {
- domWrapper.style.overflow = "hidden";
- domWrapper.style.position = "relative";
- domWrapper.style.boxSizing = "content-box";
// Create iframe
var domIFrame = this.document.createElement("iframe");
domIFrame.className = "tc-innerwiki-iframe";
@@ -54,10 +62,16 @@ InnerWikiWidget.prototype.render = function(parent,nextSibling) {
domIFrame.width = this.innerWikiWidth;
domIFrame.height = this.innerWikiHeight;
domWrapper.appendChild(domIFrame);
+ } else {
+ // Create image placeholder
+ var domImage = this.document.createElement("img");
+ domImage.style = this.innerWikiStyle;
+ domImage.setAttribute("src",this.innerWikiFilename);
+ domWrapper.appendChild(domImage);
}
// Insert wrapper into the DOM
parent.insertBefore(domWrapper,nextSibling);
- this.renderChildren(domWrapper,null);
+ this.renderChildren(domSVG,null);
this.domNodes.push(domWrapper);
// If we're on the real DOM, finish the initialisation that needs us to be in the DOM
if(!this.document.isTiddlyWikiFakeDom) {
@@ -65,14 +79,16 @@ InnerWikiWidget.prototype.render = function(parent,nextSibling) {
domIFrame.contentWindow.document.open();
domIFrame.contentWindow.document.write(this.createInnerHTML());
domIFrame.contentWindow.document.close();
- // Scale the iframe and adjust the height of the wrapper
- var clipLeft = self.innerWikiClipLeft,
- clipTop = self.innerWikiClipTop,
- clipWidth = self.innerWikiClipWidth,
- clipHeight = self.innerWikiClipHeight,
- translateX = -clipLeft,
- translateY = -clipTop,
- scale = domWrapper.clientWidth / clipWidth;
+ }
+ // Scale the iframe and adjust the height of the wrapper
+ var clipLeft = this.innerWikiClipLeft,
+ clipTop = this.innerWikiClipTop,
+ clipWidth = this.innerWikiClipWidth,
+ clipHeight = this.innerWikiClipHeight,
+ translateX = -clipLeft,
+ translateY = -clipTop,
+ scale = domWrapper.clientWidth / clipWidth;
+ if(!this.document.isTiddlyWikiFakeDom) {
domIFrame.style.transformOrigin = (-translateX) + "px " + (-translateY) + "px";
domIFrame.style.transform = "translate(" + translateX + "px," + translateY + "px) scale(" + scale + ")";
domWrapper.style.height = (clipHeight * scale) + "px";
@@ -205,7 +221,7 @@ InnerWikiWidget.prototype.saveScreenshot = function(options,callback) {
return callback(null);
}
var path = require("path"),
- filepath = path.resolve(basepath,this.innerWikiFilename) + ".png";
+ filepath = path.resolve(basepath,this.innerWikiFilename);
$tw.utils.createFileDirectories(filepath);
console.log("Taking screenshot",filepath);
// Fire up Puppeteer