1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-17 23:34:50 +00:00

Refactored slider macro to lazily render it's content

This commit is contained in:
Jeremy Ruston 2012-03-04 21:58:33 +00:00
parent 60670509e0
commit 4649a0bd88
2 changed files with 75 additions and 30 deletions

View File

@ -5,6 +5,8 @@ title: js/macros/slider.js
The slider macro is used to selectively reveal a chunk of text. By default, it renders as a button that may be clicked or touched to reveal the enclosed text. The slider macro is used to selectively reveal a chunk of text. By default, it renders as a button that may be clicked or touched to reveal the enclosed text.
The enclosed text can be a string of WikiText or be taken from a target tiddler. The enclosed text can be a string of WikiText or be taken from a target tiddler.
The current state of the slider can be stored as the string "open" or "closed" in a specified tiddler. If the value of that tiddler changes then the slider is automatically updated.
!!Parameters !!Parameters
|`state` //(defaults to 1st parameter)// |The title of the tiddler to contain the current state of the slider | |`state` //(defaults to 1st parameter)// |The title of the tiddler to contain the current state of the slider |
|`default` |The initial state of the slider, either `open` or `closed` | |`default` |The initial state of the slider, either `open` or `closed` |
@ -30,6 +32,44 @@ var Renderer = require("../Renderer.js").Renderer,
Tiddler = require("../Tiddler.js").Tiddler, Tiddler = require("../Tiddler.js").Tiddler,
utils = require("../Utils.js"); utils = require("../Utils.js");
function getOpenState() {
if(this.params.hasOwnProperty("state")) {
var stateTiddler = this.store.getTiddler(this.params.state);
if(stateTiddler) {
return stateTiddler.text.trim() === "open";
}
}
if(this.params.hasOwnProperty("default")) {
return this.params["default"] === "open";
}
return false;
};
function saveOpenState() {
if(this.params.hasOwnProperty("state")) {
var stateTiddler = this.store.getTiddler(this.params.state) ||
new Tiddler({title: this.params.state, text: ""});
this.store.addTiddler(new Tiddler(stateTiddler,{text: this.isOpen ? "open" : "closed"}));
return true;
}
return false;
}
function getSliderContent() {
if(this.params.hasOwnProperty("content")) {
return this.store.parseText("text/x-tiddlywiki",this.params.content).nodes;
} else if(this.params.hasOwnProperty("target")) {
return [Renderer.MacroNode(
"tiddler",
{target: this.params.target},
null,
this.store)];
} else {
return [Renderer.ErrorNode("No content specified for slider")];
}
};
exports.macro = { exports.macro = {
name: "slider", name: "slider",
types: ["text/html","text/plain"], types: ["text/html","text/plain"],
@ -43,12 +83,11 @@ exports.macro = {
}, },
events: { events: {
click: function(event) { click: function(event) {
if(event.target === event.currentTarget.firstChild.firstChild) { if(event.target === this.domNode.firstChild.firstChild) {
var el = event.currentTarget.firstChild.firstChild.nextSibling, this.isOpen = !this.isOpen;
stateTiddler = this.params.state ? this.store.getTiddler(this.params.state) : null; if(!saveOpenState.call(this)) {
stateTiddler = stateTiddler || new Tiddler({title: this.params.state, text: ""}); exports.macro.refreshInDom.call(this,{});
var isOpen = stateTiddler.text.trim() === "open"; }
this.store.addTiddler(new Tiddler(stateTiddler,{text: isOpen ? "closed" : "open"}));
event.preventDefault(); event.preventDefault();
return false; return false;
} else { } else {
@ -57,37 +96,40 @@ exports.macro = {
} }
}, },
execute: function() { execute: function() {
var isOpen = this.params.state ? this.store.getTiddlerText(this.params.state,"").trim() === "open" : true, this.isOpen = getOpenState.call(this);
target = this.params.target, var sliderContent = [];
sliderContent; if(this.isOpen) {
if(this.params.hasOwnProperty("content")) { sliderContent = getSliderContent.call(this);
sliderContent = this.store.parseText("text/x-tiddlywiki",this.params.content).nodes;
} else {
sliderContent = [Renderer.MacroNode(
"tiddler",
{target: target},
null,
this.store)];
} }
var content = Renderer.SliderNode(this.params.state, var content = Renderer.SliderNode(this.params.state,
this.params.label ? this.params.label : target, this.params.label ? this.params.label : this.params.target,
this.params.tooltip, this.params.tooltip,
isOpen, this.isOpen,
sliderContent); sliderContent);
content.execute(this.parents,this.store.getTiddler(this.tiddlerText)); content.execute(this.parents,this.store.getTiddler(this.tiddlerTitle));
return [content]; return [content];
}, },
refreshInDom: function(changes) { refreshInDom: function(changes) {
if(this.params.target && changes.hasOwnProperty(this.params.target)) { var needContentRefresh = true; // Avoid refreshing the content nodes if we don't need to
// If the target has changed, re-render the macro // If the state tiddler has changed then reset the open state
} else { if(this.params.hasOwnProperty("state") && changes.hasOwnProperty(this.params.state)) {
if (this.params.state && changes.hasOwnProperty(this.params.state)) { this.isOpen = getOpenState.call(this);
// If it was just the state tiddler that's changed, set the display appropriately }
var el = this.domNode.firstChild.firstChild.nextSibling, // Render the content if the slider is open and we don't have any content yet
isOpen = this.store.getTiddlerText(this.params.state,"").trim() === "open"; if(this.isOpen && this.content[0].children[1].children.length === 0) {
el.style.display = isOpen ? "block" : "none"; // Get the slider content and execute it
} this.content[0].children[1].children = getSliderContent.call(this);
// Refresh any children this.content[0].children[1].execute(this.parents,this.store.getTiddler(this.tiddlerTitle));
// Replace the existing slider body DOM node
this.domNode.firstChild.removeChild(this.domNode.firstChild.firstChild.nextSibling);
this.content[0].children[1].renderInDom(this.domNode.firstChild,this.domNode.firstChild.firstChild.nextSibling);
needContentRefresh = false; // Don't refresh the children if we've just created them
}
// Set the visibility of the slider content
var el = this.domNode.firstChild.firstChild.nextSibling;
el.style.display = this.isOpen ? "block" : "none";
// Refresh any children
if(needContentRefresh) {
for(var t=0; t<this.content.length; t++) { for(var t=0; t<this.content.length; t++) {
this.content[t].refreshInDom(changes); this.content[t].refreshInDom(changes);
} }

View File

@ -10,3 +10,6 @@ And here's another slider that contains a video, with the state stored in VideoS
And here's a MiniSlider that works with text, rather than a separate tiddler. And here's a MiniSlider that works with text, rather than a separate tiddler.
<<slider state:MiniSlider label:"Click me!" content:"This is the //content// of the slider. The state is stored in MiniSlider">> <<slider state:MiniSlider label:"Click me!" content:"This is the //content// of the slider. The state is stored in MiniSlider">>
And here's a slider that doesn't use a state tiddler:
<<slider label:"Click me!" content:"This is the //content// of the slider. The state is not retained.">>