ZPublishCleanup
// hijack function to handle 412 edit conflict response
config.extensions.ServerSideSavingPlugin.saveTiddlerCallback = function(context, userParams) {
var tiddler = context.tiddler;
if(context.status || context.httpStatus == 1223) {
handle204(context);
} else {
if(context.httpStatus == 412) {
handle412(context);
} else {
displayMessage(config.extensions.ServerSideSavingPlugin.locale.saveError.format([tiddler.title, context.statusText]));
}
}
};
function handle204(context) {
var tiddler = context.tiddler;
if(tiddler.fields.changecount == context.changecount) { //# check for changes since save was triggered
tiddler.clearChangeCount();
} else if(tiddler.fields.changecount > 0) {
tiddler.fields.changecount -= context.changecount;
}
displayMessage(config.extensions.ServerSideSavingPlugin.locale.saved.format([tiddler.title]));
store.setDirty(false);
// from here is a custom bit for the copyPlugin; you'd want to handle via a custom 204 handler passed into the ServerSideSavingPlugin
if (tiddler.fields["sourceworkspace"]) {
newWorkspace = tiddler.fields['server.workspace'];
originalworkspace = tiddler.fields["sourceworkspace"];
tiddler.fields["server.workspace"] = originalworkspace;
tiddler.fields["server.page.revision"] = tiddler.fields["revisionsidinsource"];
if (tiddler.fields["publishlevel"] == 'move') {
store.removeTiddler(tiddler.title);
autoSaveChanges();
}
delete tiddler.fields['sourceworkspace'];
delete tiddler.fields["revisionsidinsource"];
}
}
function handle412(context) {
var tiddler = context.tiddler;
try {
var adaptor = config.extensions.ServerSideSavingPlugin.getTiddlerServerAdaptor(tiddler);
} catch(ex) {
return false;
}
if (!adaptor.host){
adaptor.host = context.host;
}
var context = {workspace: tiddler.fields["server.workspace"]};
var req = adaptor.getTiddler(tiddler.title, context, {}, onGetTiddler);
return req ? tiddler : false;
}
function onGetTiddler(context) {
var destTiddler = context.tiddler;
var sourceTiddler = store.getTiddler(destTiddler.title);
sourceTiddler.fields['server.page.revision'] = destTiddler.fields['server.page.revision'];
sourceTiddler.fields['server.workspace'] = destTiddler.fields['server.workspace'];
store.saveTiddler(sourceTiddler.title);
autoSaveChanges(false);
}
config.extensions.ServerSideSavingPlugin.saveTiddlerCallback = function(context, userParams) {
var tiddler = context.tiddler;
if(context.status || context.httpStatus == 1223) {
handle204(context);
} else {
if(context.httpStatus == 412) {
handle412(context);
} else {
displayMessage(config.extensions.ServerSideSavingPlugin.locale.saveError.format([tiddler.title, context.statusText]));
}
}
};
function handle204(context) {
var tiddler = context.tiddler;
if(tiddler.fields.changecount == context.changecount) { //# check for changes since save was triggered
tiddler.clearChangeCount();
} else if(tiddler.fields.changecount > 0) {
tiddler.fields.changecount -= context.changecount;
}
displayMessage(config.extensions.ServerSideSavingPlugin.locale.saved.format([tiddler.title]));
store.setDirty(false);
// from here is a custom bit for the copyPlugin; you'd want to handle via a custom 204 handler passed into the ServerSideSavingPlugin
if (tiddler.fields["sourceworkspace"]) {
newWorkspace = tiddler.fields['server.workspace'];
originalworkspace = tiddler.fields["sourceworkspace"];
tiddler.fields["server.workspace"] = originalworkspace;
tiddler.fields["server.page.revision"] = tiddler.fields["revisionsidinsource"];
if (tiddler.fields["publishlevel"] == 'move') {
store.removeTiddler(tiddler.title);
autoSaveChanges();
}
delete tiddler.fields['sourceworkspace'];
delete tiddler.fields["revisionsidinsource"];
}
}
function handle412(context) {
var tiddler = context.tiddler;
try {
var adaptor = config.extensions.ServerSideSavingPlugin.getTiddlerServerAdaptor(tiddler);
} catch(ex) {
return false;
}
if (!adaptor.host){
adaptor.host = context.host;
}
var context = {workspace: tiddler.fields["server.workspace"]};
var req = adaptor.getTiddler(tiddler.title, context, {}, onGetTiddler);
return req ? tiddler : false;
}
function onGetTiddler(context) {
var destTiddler = context.tiddler;
var sourceTiddler = store.getTiddler(destTiddler.title);
sourceTiddler.fields['server.page.revision'] = destTiddler.fields['server.page.revision'];
sourceTiddler.fields['server.workspace'] = destTiddler.fields['server.workspace'];
store.saveTiddler(sourceTiddler.title);
autoSaveChanges(false);
}
Comments
PublishCommand
config.commands.saveTiddler.old_handler = config.commands.saveTiddler.handler;
config.commands.saveTiddler.handler = function (event, src, title) {
var stored_tiddler = store.getTiddler(title);
if(stored_tiddler&&stored_tiddler.fields && stored_tiddler.fields['sourceworkspace']){
delete stored_tiddler.fields['sourceworkspace'];
}
config.commands.saveTiddler.old_handler(event,src,title);
};
config.commands.publishtiddler = {
text: "publish",
tooltip: "publish this so everyone can see it",
confirmMsg: "Are you sure you want to publish this? If so, it will become visible to everybody and you will no longer be able to edit it",
saveFirstMsg: "Please save this first!",
handler: function(event,src,title){
var t = store.getTiddler(title);
if(!t){
alert(this.saveFirstMsg);
}
if (!confirm(this.confirmMsg)) {
return false;
}
var fields = store.getTiddler(title).fields;
//********************CHANGE THIS BIT TO YOUR PREFERRED BAG***************
fields['publishtobag'] = "blog";
fields['publishlevel'] = "copy";
//********************************************************************************************
var publishToBag = fields.publishtobag;
var newWorkspace = "bags/"+publishToBag;
var publishLevel = fields.publishlevel;
if(publishLevel) {
fields['sourceworkspace'] = fields['server.workspace'];
fields['revisionsidinsource'] = fields['server.page.revision'];
fields['server.workspace'] = newWorkspace;
store.saveTiddler(title);
autoSaveChanges();
} else {
alert("no publish level set!");
}
}
};
config.commands.saveTiddler.handler = function (event, src, title) {
var stored_tiddler = store.getTiddler(title);
if(stored_tiddler&&stored_tiddler.fields && stored_tiddler.fields['sourceworkspace']){
delete stored_tiddler.fields['sourceworkspace'];
}
config.commands.saveTiddler.old_handler(event,src,title);
};
config.commands.publishtiddler = {
text: "publish",
tooltip: "publish this so everyone can see it",
confirmMsg: "Are you sure you want to publish this? If so, it will become visible to everybody and you will no longer be able to edit it",
saveFirstMsg: "Please save this first!",
handler: function(event,src,title){
var t = store.getTiddler(title);
if(!t){
alert(this.saveFirstMsg);
}
if (!confirm(this.confirmMsg)) {
return false;
}
var fields = store.getTiddler(title).fields;
//********************CHANGE THIS BIT TO YOUR PREFERRED BAG***************
fields['publishtobag'] = "blog";
fields['publishlevel'] = "copy";
//********************************************************************************************
var publishToBag = fields.publishtobag;
var newWorkspace = "bags/"+publishToBag;
var publishLevel = fields.publishlevel;
if(publishLevel) {
fields['sourceworkspace'] = fields['server.workspace'];
fields['revisionsidinsource'] = fields['server.page.revision'];
fields['server.workspace'] = newWorkspace;
store.saveTiddler(title);
autoSaveChanges();
} else {
alert("no publish level set!");
}
}
};
TiddlyWiki
TiddlyWiki is a wiki in a single HTML file, driven by javascript. It is very extensible with plugins, macros, and all sorts of interesting customizations.
Binary Tiddlers and You
I want to take this opportunity to talk about the current state of binary tiddlers within TiddlyWeb, how you can use them, and to introduce some new stuff that I've been working on.
There are currently a few ways of dealing with binary tiddlers in TiddlyWeb/TiddlyWiki. If we first take a look at TiddlyWiki, we can see that binary tiddlers can be loaded in the form of base64 encoded data: URIs (see TiddlyPictoWiki for a good example of this). Indeed, the upcoming TiddlyWiki5 fully supports all of this natively (among other things).
Of course TiddlyWeb also supports binary tiddlers (setting the tiddler.type attribute determines this), with the difficulty being how to get the data into the store in the first place. For this, natively, your only real option is is to PUT it using curl and the RESTful API (more on another native option below). This works for the most part, though I wouldn't call it particularly user friendly. There is also my form plugin (see POSTing to TiddlyWeb), which I'll go into greater detail about later on.
Finally, you can use twanager, and a small plugin for importing binary content that I wrote called tiddlywebplugins.bimport. I should note first that I wrote this a few months ago and some of the functionality has since been integrated with TiddlyWeb core (specifically, the twanager command twimport) so most of this also applies to that command. The main benefit of using bimport however, is that you can guarantee that the file you're importing will always be stored as binary (javascript files or TiddlyWiki files might be a good use case). So, to install:
and then add 'tiddlywebplugins.bimport' to you tiddlywebconfig.py file. You can then import binary files with:
where the URI can be anything (eg - a file: URI). Alternatively, the twimport command can be run as:
with anything not recognised as a valid type for TiddlyWeb to use being stored as binary content. What this means is that an image will import fine, but a Javascript file, will get tagged "systemConfig" and lose its mime type. If you don't want this to happen, you should use bimport. Otherwise, twimport is probably easier (as you don't have to install an extra plugin).
A while ago I wrote a blog entry entitled POSTing to TiddlyWeb which mentioned that you could use it to upload files to a TiddlyWeb bag or recipe. I've recently updated this to support tagging binary tiddlers, and have released it to pypi. You can install it by running:
from a command line. If you were using the old version, you should probably update as the new version supports better handling of tiddler titles, in that you can now override the title of a binary file being uploaded, and the aforementioned tagging of binary content (so that you can tag for example, an image, or a pdf).
I've also created a TiddlyWiki plugin to use with it. You can find it in my SVN repository at http://svn.tiddlywiki.org/Trunk/contributors/BenGillies/TiddlyWeb/Plugins/Binary/tiddlers/BinaryUploadPlugin.js, and can import it into your TiddlyWeb store with:
To use it, simply add:
where bag:bag_name is optional and allows you to specify a different bag to the one you're currently in, edit:tags and edit:title are also optional, and allow you to add a title or tags, and tags:default_tags allows you to set some default tags if you have the edit:tags option on.
I believe that binary tiddlers now have a fairly good story in TiddlyWeb, and am quite looking forward to seeing potential applications that surface.
There are currently a few ways of dealing with binary tiddlers in TiddlyWeb/TiddlyWiki. If we first take a look at TiddlyWiki, we can see that binary tiddlers can be loaded in the form of base64 encoded data: URIs (see TiddlyPictoWiki for a good example of this). Indeed, the upcoming TiddlyWiki5 fully supports all of this natively (among other things).
Of course TiddlyWeb also supports binary tiddlers (setting the tiddler.type attribute determines this), with the difficulty being how to get the data into the store in the first place. For this, natively, your only real option is is to PUT it using curl and the RESTful API (more on another native option below). This works for the most part, though I wouldn't call it particularly user friendly. There is also my form plugin (see POSTing to TiddlyWeb), which I'll go into greater detail about later on.
Finally, you can use twanager, and a small plugin for importing binary content that I wrote called tiddlywebplugins.bimport. I should note first that I wrote this a few months ago and some of the functionality has since been integrated with TiddlyWeb core (specifically, the twanager command twimport) so most of this also applies to that command. The main benefit of using bimport however, is that you can guarantee that the file you're importing will always be stored as binary (javascript files or TiddlyWiki files might be a good use case). So, to install:
sudo pip install -U tiddlywebplugins.bimport
and then add 'tiddlywebplugins.bimport' to you tiddlywebconfig.py file. You can then import binary files with:
twanager bimport <bag_name> <tiddler_name> <URI>
where the URI can be anything (eg - a file: URI). Alternatively, the twimport command can be run as:
twanager twimport <bag_name> <URI>
with anything not recognised as a valid type for TiddlyWeb to use being stored as binary content. What this means is that an image will import fine, but a Javascript file, will get tagged "systemConfig" and lose its mime type. If you don't want this to happen, you should use bimport. Otherwise, twimport is probably easier (as you don't have to install an extra plugin).
Uploading via the Web
A while ago I wrote a blog entry entitled POSTing to TiddlyWeb which mentioned that you could use it to upload files to a TiddlyWeb bag or recipe. I've recently updated this to support tagging binary tiddlers, and have released it to pypi. You can install it by running:
sudo pip install -U tiddlywebplugins.form
from a command line. If you were using the old version, you should probably update as the new version supports better handling of tiddler titles, in that you can now override the title of a binary file being uploaded, and the aforementioned tagging of binary content (so that you can tag for example, an image, or a pdf).
I've also created a TiddlyWiki plugin to use with it. You can find it in my SVN repository at http://svn.tiddlywiki.org/Trunk/contributors/BenGillies/TiddlyWeb/Plugins/Binary/tiddlers/BinaryUploadPlugin.js, and can import it into your TiddlyWeb store with:
twanager twimport <bag_name> http://svn.tiddlywiki.org/Trunk/contributors/BenGillies/TiddlyWeb/Plugins/Binary/tiddlers/split.recipe
To use it, simply add:
<<binaryUpload bag:bag_name edit:tags edit:title tags:default_tags>>
where bag:bag_name is optional and allows you to specify a different bag to the one you're currently in, edit:tags and edit:title are also optional, and allow you to add a title or tags, and tags:default_tags allows you to set some default tags if you have the edit:tags option on.
I believe that binary tiddlers now have a fairly good story in TiddlyWeb, and am quite looking forward to seeing potential applications that surface.
BlogLayout
| Name: | BlogLayout |
| Description: | adds a blog like view and tiddler summary view to TiddlyWiki |
| Author | BenGillies |
| CodeRepository: | http://svn.tiddlywiki.org/Trunk/contributors/BenGillies/plugins/BlogLayout.js |
| Version: | 1.0 |
| Comments: | Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
| License | BSD License |
| CoreVersion: | 2.5 |
Usage
Set POST_TAG_NAME to the tag that you want to load by default. This will then automatically order all tags most recent first.
All posts longer than MAX_HEIGHT will be shortened and a "Read More..." link appended to the bottom.
You can additionally call
<<collapseThisTiddler default_height>>
At the end of any tiddler to provide a similarly shortened view with a "Read More..." link at the bottom. default_height is optional and provides a default to set the height to if setCollapseHeightHere has not been called within the tiddler (see below). Set default_height to -1 to set a default of not shortening tiddlers. This can be placed in the ViewTemplate tiddler (AUTO_SUMMARISE_FRONT_PAGE should be turned off if you are doing this) right after the .viewer div, as follows:
<div macro="collapseThisTiddler default_height"></div>;
You can also set a custom height from within the tiddler. If you do this, it will take precedent over all other default height settings and is the recommended method of setting height as it allows you to fine tune how short each tiddler can be. To use, call:
<<setCollapseHeightHere turn_off>>
This will set the height of the shortened tiddler to wherever you place the macro. turn_off should be -1 if you wish the tiddler to always appear in full. Otherwise, leave blank.
You can link to a blog-like page/layout (as per the page ouy get on first load) by putting:
<<recentByTagLink link_name tag_name max_posts collapse_posts default_height>>
in place of any link, where:
link_name = the text you want the link to read
tag_name = the name of the tag you want to filter by (aka POST_TAG_NAME)
max_posts = the maximum number of posts to display
collapse_posts = this can be 1 or 0. If 1 it will shorten posts, adding the Read More link. Default is AUTO_SUMMARISE_FRONT_PAGE.
default_height = the default height of shortened posts. Set to -1 to turn off by default.
Note - It is assumed that when a user clicks on a link specifically, they want to read the whole tiddler. If you want tiddlers to appear shortened when they are clicked on, you will need to edit the ViewTemplate tiddler.
Code
if(!version.extensions.BlogLayout)
{ //# ensure that the plugin is only installed once
version.extensions.BlogLayout = { installed: true }
};
(function($) { //set up alias for jQuery
config.macros.BlogLayout =
{
//*******collapseTiddlers variables********//
AUTO_SUMMARISE_FRONT_PAGE: true, //collapse all default tiddlers on first load (other tiddlers are unaffected)
MAX_HEIGHT: 200, //max height of tiddler content in pixels (default value)
//*******recentPosts variables*************//
POST_DISPLAY_COUNT: 5, //maximum number of posts to display
POST_TAG_NAME: "blog" //all posts that you want displayed in date order need to be tagged with this.
}
config.macros.BlogLayout.collapseMe = function(tiddlerRoot,defaultHeight)
//collapse tiddlerRoot
{
if (!store.getTiddler($(tiddlerRoot).attr("tiddler")))
{
return;
}
custHeight = store.getTiddler($(tiddlerRoot).attr("tiddler")).fields["collapseHeight"] || defaultHeight || this.MAX_HEIGHT;
customHeight = parseInt(custHeight);
//if the post is too big
if (($(tiddlerRoot).children('.viewer').height() > customHeight)&&(customHeight != -1))
{
//limit height of tiddler
$(tiddlerRoot).children('.viewer').css('overflow','hidden').css('height',customHeight);
//create a link
myLink = document.createElement("a");
myLink.href = "javascript:;";
myLink.onclick = function() {return config.macros.BlogLayout.expandClick(tiddlerRoot);};
myLink.innerHTML = "Read More...";
myLink.className = "button";
$("<div />").addClass('readMore').append(myLink).css("margin-top","3px").appendTo($(tiddlerRoot));
}
}
config.macros.BlogLayout.collapseTiddlers = function(defaultHeight)
//collapse all currently open tiddlers
{
$(".tiddler").each(
function() {
if(this.style.display == "none")
{
$(this).attr("collapseMeLater",(defaultHeight)?(defaultHeight+""):"null");
}
else
{
return config.macros.BlogLayout.collapseMe($(this),defaultHeight)
}
}
)
}
config.macros.BlogLayout.expandClick = function(tiddlerToExpand)
{
$(tiddlerToExpand).children(".readMore").css('display','none');
$(tiddlerToExpand).children(".viewer").css('overflow','visible').css('height','');
}
config.macros.BlogLayout.showNextTiddlers = function(clickedLink)
{
var divs = clickedLink.nextSibling;
$(clickedLink).hide();
$(clickedLink).remove();
var stopping = false;
while((!stopping)&&(divs))
{
$(divs).show();
if (divs.className == "showMorePosts")
{
stopping = true;
break;
}
else if ($(divs).attr("collapseMeLater"))
{
if ($(divs).attr("collapseMeLater") == "null")
{
this.collapseMe($(divs));
}
else
{
this.collapseMe($(divs),$(divs).attr("collapseMeLater"));
}
$(divs).removeAttr("collapseMeLater");
}
divs = divs.nextSibling;
}
}
config.macros.BlogLayout.recentTiddlersByTag = function(tagName,maxPosts)
//view all tiddlers with tagName by date order
{
story.closeAllTiddlers(); //clear screen ready for display
$(".showMorePosts").remove();
tiddlers = store.filterTiddlers("[tag["+tagName+"]][sort[-created]]");
var count = 0;
var currMax = maxPosts;
var justChanged = false;
while (count < tiddlers.length)
{
if (count == currMax)
{
$("<div />").addClass("showMorePosts").text("More Posts...").css("display","none").click(function(){return config.macros.BlogLayout.showNextTiddlers(this);}).appendTo("#tiddlerDisplay");
currMax += maxPosts;
}
story.displayTiddler("bottom",tiddlers[count].title,DEFAULT_VIEW_TEMPLATE,false,false);
if (count >= maxPosts)
{
//hide the tiddler
$(story.getTiddler(tiddlers[count].title)).css("display","none");
}
count += 1;
}
//hide all but the first More Posts...
if ($(".showMorePosts").length > 0)
{
$(".showMorePosts")[0].style.display = "block";
}
}
config.macros.BlogLayout.autoRecentTiddlers = function()
{
if(!window.location.hash)
{
this.recentTiddlersByTag(this.POST_TAG_NAME,this.POST_DISPLAY_COUNT);
}
}
config.shadowTiddlers['DefaultTiddlers'] = "[tag["+config.macros.BlogLayout+"]][sort[-created]]";
window.original_restart = window.restart;
window.restart = function()
{
window.original_restart();
if (config.macros.BlogLayout.POST_DISPLAY_COUNT != -1)
{
config.macros.BlogLayout.autoRecentTiddlers(); //call this to ensure number of posts is limited
}
if ((config.macros.BlogLayout.AUTO_SUMMARISE_FRONT_PAGE)&&(!window.location.hash))
{
$(document).ready(function() {config.macros.BlogLayout.collapseTiddlers()});
}
}
//$(document).ready(config.macros.BlogLayout.collapseTiddlers());
config.macros.setCollapseHeightHere ={
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
dontCollapse = params[0];
if (dontCollapse)
{
tiddler.fields['collapseHeight'] = -1;
}
else
{
tiddler.fields['collapseHeight'] = (place.clientHeight > 0)?(place.clientHeight - 4):(place.offsetHeight - 4);
tiddler.fields['collapseHeight'] += "";
}
}
}
config.macros.collapseThisTiddler ={
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
if ((params[0])&&(!tiddler.fields['collapseHeight']))
{
tiddler.fields['collapseHeight'] = params[0];
}
config.macros.BlogLayout.collapseMe($(story.getTiddler(tiddler.title)));
}
}
config.macros.BlogLayout.collapseRecentByTag = function(tagName,maxPosts,collapsePosts,defaultHeight)
{
this.recentTiddlersByTag(tagName,maxPosts);
if (collapsePosts)
{
this.collapseTiddlers(defaultHeight);
}
}
//params[0] = name of link
//params[1] = tagName
//params[2] = maxPosts
//params[3] = collapse posts. Values are true/false. default is true.
//params[4] = default value for collapsing posts by
config.macros.recentByTagLink ={
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
//check parameters supplied
var tagName, maxPosts, collapsePosts, linkName,defaultHeight;
tagName = params[1] || config.macros.BlogLayout.POST_TAG_NAME;
maxPosts = params[2] || config.macros.BlogLayout.POST_DISPLAY_COUNT;
collapsePosts = params[3] || (config.macros.BlogLayout.AUTO_SUMMARISE_FRONT_PAGE?1:0);
defaultHeight = params[4] || config.macros.BlogLayout.MAX_HEIGHT;
linkName = params[0] || tagName;
collapse = (collapsePosts == 1)?true:false;
var tagLink = document.createElement("a");
tagLink.href = "javascript:;";
tagLink.onclick = function() {return config.macros.BlogLayout.collapseRecentByTag(tagName,maxPosts,collapse,defaultHeight);};
tagLink.innerHTML = linkName;
$(place).append(tagLink);
}
}
})(jQuery)
config.shadowTiddlers.StylesheetBlogLayout = ".showMorePosts {margin: 5px 5px 20px 5px; cursor: pointer; width: 100%; text-align: center; border: 1px solid #c0c0c0; }\n" +
".readMore {}\n" +
".readMore .button {}";
store.addNotification("StylesheetBlogLayout",refreshStyles);
{ //# ensure that the plugin is only installed once
version.extensions.BlogLayout = { installed: true }
};
(function($) { //set up alias for jQuery
config.macros.BlogLayout =
{
//*******collapseTiddlers variables********//
AUTO_SUMMARISE_FRONT_PAGE: true, //collapse all default tiddlers on first load (other tiddlers are unaffected)
MAX_HEIGHT: 200, //max height of tiddler content in pixels (default value)
//*******recentPosts variables*************//
POST_DISPLAY_COUNT: 5, //maximum number of posts to display
POST_TAG_NAME: "blog" //all posts that you want displayed in date order need to be tagged with this.
}
config.macros.BlogLayout.collapseMe = function(tiddlerRoot,defaultHeight)
//collapse tiddlerRoot
{
if (!store.getTiddler($(tiddlerRoot).attr("tiddler")))
{
return;
}
custHeight = store.getTiddler($(tiddlerRoot).attr("tiddler")).fields["collapseHeight"] || defaultHeight || this.MAX_HEIGHT;
customHeight = parseInt(custHeight);
//if the post is too big
if (($(tiddlerRoot).children('.viewer').height() > customHeight)&&(customHeight != -1))
{
//limit height of tiddler
$(tiddlerRoot).children('.viewer').css('overflow','hidden').css('height',customHeight);
//create a link
myLink = document.createElement("a");
myLink.href = "javascript:;";
myLink.onclick = function() {return config.macros.BlogLayout.expandClick(tiddlerRoot);};
myLink.innerHTML = "Read More...";
myLink.className = "button";
$("<div />").addClass('readMore').append(myLink).css("margin-top","3px").appendTo($(tiddlerRoot));
}
}
config.macros.BlogLayout.collapseTiddlers = function(defaultHeight)
//collapse all currently open tiddlers
{
$(".tiddler").each(
function() {
if(this.style.display == "none")
{
$(this).attr("collapseMeLater",(defaultHeight)?(defaultHeight+""):"null");
}
else
{
return config.macros.BlogLayout.collapseMe($(this),defaultHeight)
}
}
)
}
config.macros.BlogLayout.expandClick = function(tiddlerToExpand)
{
$(tiddlerToExpand).children(".readMore").css('display','none');
$(tiddlerToExpand).children(".viewer").css('overflow','visible').css('height','');
}
config.macros.BlogLayout.showNextTiddlers = function(clickedLink)
{
var divs = clickedLink.nextSibling;
$(clickedLink).hide();
$(clickedLink).remove();
var stopping = false;
while((!stopping)&&(divs))
{
$(divs).show();
if (divs.className == "showMorePosts")
{
stopping = true;
break;
}
else if ($(divs).attr("collapseMeLater"))
{
if ($(divs).attr("collapseMeLater") == "null")
{
this.collapseMe($(divs));
}
else
{
this.collapseMe($(divs),$(divs).attr("collapseMeLater"));
}
$(divs).removeAttr("collapseMeLater");
}
divs = divs.nextSibling;
}
}
config.macros.BlogLayout.recentTiddlersByTag = function(tagName,maxPosts)
//view all tiddlers with tagName by date order
{
story.closeAllTiddlers(); //clear screen ready for display
$(".showMorePosts").remove();
tiddlers = store.filterTiddlers("[tag["+tagName+"]][sort[-created]]");
var count = 0;
var currMax = maxPosts;
var justChanged = false;
while (count < tiddlers.length)
{
if (count == currMax)
{
$("<div />").addClass("showMorePosts").text("More Posts...").css("display","none").click(function(){return config.macros.BlogLayout.showNextTiddlers(this);}).appendTo("#tiddlerDisplay");
currMax += maxPosts;
}
story.displayTiddler("bottom",tiddlers[count].title,DEFAULT_VIEW_TEMPLATE,false,false);
if (count >= maxPosts)
{
//hide the tiddler
$(story.getTiddler(tiddlers[count].title)).css("display","none");
}
count += 1;
}
//hide all but the first More Posts...
if ($(".showMorePosts").length > 0)
{
$(".showMorePosts")[0].style.display = "block";
}
}
config.macros.BlogLayout.autoRecentTiddlers = function()
{
if(!window.location.hash)
{
this.recentTiddlersByTag(this.POST_TAG_NAME,this.POST_DISPLAY_COUNT);
}
}
config.shadowTiddlers['DefaultTiddlers'] = "[tag["+config.macros.BlogLayout+"]][sort[-created]]";
window.original_restart = window.restart;
window.restart = function()
{
window.original_restart();
if (config.macros.BlogLayout.POST_DISPLAY_COUNT != -1)
{
config.macros.BlogLayout.autoRecentTiddlers(); //call this to ensure number of posts is limited
}
if ((config.macros.BlogLayout.AUTO_SUMMARISE_FRONT_PAGE)&&(!window.location.hash))
{
$(document).ready(function() {config.macros.BlogLayout.collapseTiddlers()});
}
}
//$(document).ready(config.macros.BlogLayout.collapseTiddlers());
config.macros.setCollapseHeightHere ={
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
dontCollapse = params[0];
if (dontCollapse)
{
tiddler.fields['collapseHeight'] = -1;
}
else
{
tiddler.fields['collapseHeight'] = (place.clientHeight > 0)?(place.clientHeight - 4):(place.offsetHeight - 4);
tiddler.fields['collapseHeight'] += "";
}
}
}
config.macros.collapseThisTiddler ={
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
if ((params[0])&&(!tiddler.fields['collapseHeight']))
{
tiddler.fields['collapseHeight'] = params[0];
}
config.macros.BlogLayout.collapseMe($(story.getTiddler(tiddler.title)));
}
}
config.macros.BlogLayout.collapseRecentByTag = function(tagName,maxPosts,collapsePosts,defaultHeight)
{
this.recentTiddlersByTag(tagName,maxPosts);
if (collapsePosts)
{
this.collapseTiddlers(defaultHeight);
}
}
//params[0] = name of link
//params[1] = tagName
//params[2] = maxPosts
//params[3] = collapse posts. Values are true/false. default is true.
//params[4] = default value for collapsing posts by
config.macros.recentByTagLink ={
handler: function(place,macroName,params,wikifier,paramString,tiddler)
{
//check parameters supplied
var tagName, maxPosts, collapsePosts, linkName,defaultHeight;
tagName = params[1] || config.macros.BlogLayout.POST_TAG_NAME;
maxPosts = params[2] || config.macros.BlogLayout.POST_DISPLAY_COUNT;
collapsePosts = params[3] || (config.macros.BlogLayout.AUTO_SUMMARISE_FRONT_PAGE?1:0);
defaultHeight = params[4] || config.macros.BlogLayout.MAX_HEIGHT;
linkName = params[0] || tagName;
collapse = (collapsePosts == 1)?true:false;
var tagLink = document.createElement("a");
tagLink.href = "javascript:;";
tagLink.onclick = function() {return config.macros.BlogLayout.collapseRecentByTag(tagName,maxPosts,collapse,defaultHeight);};
tagLink.innerHTML = linkName;
$(place).append(tagLink);
}
}
})(jQuery)
config.shadowTiddlers.StylesheetBlogLayout = ".showMorePosts {margin: 5px 5px 20px 5px; cursor: pointer; width: 100%; text-align: center; border: 1px solid #c0c0c0; }\n" +
".readMore {}\n" +
".readMore .button {}";
store.addNotification("StylesheetBlogLayout",refreshStyles);