Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="72 648 70 70"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 77.59005 669.34003 C 71.532745 681.90424 73.714462 697.4441 84.135193 707.86475
C 97.315445 721.0451 118.684715 721.0451 131.8649 707.86475
C 145.04515 694.68457 145.04515 673.31537 131.8649 660.13513
C 121.4441 649.7141 105.90419 647.53253 93.339905 653.5899 L 102.047455 662.2976
C 109.58637 660.2373 117.987976 662.16803 123.90997 668.08997
C 132.69673 676.8767 132.69673 691.12317 123.90997 699.90985
C 115.12313 708.6966 100.87699 708.6966 92.09012 699.90985
C 86.168266 693.98804 84.23744 685.58643 86.297653 678.04755 Z M 72 648 L 72 668.25 L 78.75 661.49957
L 99.00019 681.7502 L 105.750175 675.00006 L 85.50013 654.75012 L 92.249985 648 Z" fill="black"
class="glyph"/>
</g>
</g>
</svg>
/***
TiddlySpace extensions for [[chrjs]]
***/
//{{{
(function($) {
tiddlyweb.routes.spaces = "{host}/spaces";
tiddlyweb.routes.space = "{host}/spaces/{name}";
tiddlyweb.routes.members = "{host}/spaces/{name}/members";
tiddlyweb.routes.member = "{host}/spaces/{name}/members/{username}";
tiddlyweb.Space = function(name, host) {
tiddlyweb.Resource.apply(this, ["space", host]);
this.name = name;
};
tiddlyweb.Space.prototype = new tiddlyweb.Resource();
$.extend(tiddlyweb.Space.prototype, {
create: function(callback, errback) { // API wrapper
this.put.apply(this, arguments);
},
members: function() {
return new MemberCollection(this);
}
});
var Member = function(username, space) {
tiddlyweb.Resource.apply(this, ["member", space.host]);
this.name = space.name;
this.username = username;
};
Member.prototype = new tiddlyweb.Resource();
var MemberCollection = function(space) {
tiddlyweb.Collection.apply(this, ["members", space.host, {
name: space.name
}]);
};
MemberCollection.prototype = new tiddlyweb.Collection();
$.extend(MemberCollection.prototype, {
add: function(username, callback, errback) {
var member = new Member(username, this);
member.put(callback, errback);
},
remove: function(username, callback, errback) {
var member = new Member(username, this);
member["delete"](callback, errback);
}
});
})(jQuery);
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="491 13 34 35" width="34pt" height="35pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2010-06-05 14:34Z</dc:date><!-- Produced by OmniGraffle Professional 5.2.2 --></metadata><defs></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><path d="M 493.45312 28.112467 C 494.7151 20.143282 502.20773 14.699663 510.177 15.961652 C 518.1471 17.223583 523.5907 24.716248 522.32867 32.686314 C 521.06586 40.655617 513.57324 46.099178 505.60397 44.83719 C 497.63474 43.57523 492.19028 36.081776 493.45312 28.112467 Z" fill="white"/><path d="M 493.45312 28.112467 C 494.7151 20.143282 502.20773 14.699663 510.177 15.961652 C 518.1471 17.223583 523.5907 24.716248 522.32867 32.686314 C 521.06586 40.655617 513.57324 46.099178 505.60397 44.83719 C 497.63474 43.57523 492.19028 36.081776 493.45312 28.112467 Z" stroke="#bebebe" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/><path d="M 507.84293 35.927711 C 504.56314 35.927711 501.90082 33.265377 501.90082 29.98558 C 501.90082 26.704926 504.56314 24.043444 507.84293 24.043444 C 511.1227 24.043444 513.78503 26.704926 513.78503 29.98558 C 513.78503 33.265377 511.1227 35.927711 507.84293 35.927711 Z" fill="#f4c4e2"/><path d="M 507.84293 35.927711 C 504.56314 35.927711 501.90082 33.265377 501.90082 29.98558 C 501.90082 26.704926 504.56314 24.043444 507.84293 24.043444 C 511.1227 24.043444 513.78503 26.704926 513.78503 29.98558 C 513.78503 33.265377 511.1227 35.927711 507.84293 35.927711 Z" stroke="#ce81b0" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/></g></g></svg>
/***
|TiddlyFileImporter|
|Version|0.2|
|Author|Ben Gillies|
|Type|plugin|
|Description|Upload a TiddlyWiki file to TiddlyWeb, and import the tiddlers.|
!Usage
Upload a TiddlyWiki file to TiddlyWeb, and import the tiddlers.
!Requires
tiddlyweb
tiddlywebplugins.reflector
!Code
***/
//{{{
(function($){
if(!version.extensions.TiddlyFileImporter)
{ //# ensure that the plugin is only installed once
version.extensions.TiddlyFileImporter = { installed: true }
};
config.macros.fileImport = {
reflectorURI: '/reflector',
incorrectTypeError: 'Incorrect File Type. You must upload a TiddlyWiki',
uploadLabel: 'Upload',
uploadLabelPrompt: 'Import tiddlers from this TiddlyWiki',
step1Text: 'Pick a TiddlyWiki file to Upload',
step1Title: 'Step 1: Upload a TiddlyWiki file',
step3Html: '<input type="hidden" name="markList" />'
+ '<input type="hidden" checked="true" name="chkSync" />'
+ '<input type="hidden" name="chkSave" />'
+ '<input type="hidden" name="txtSaveTiddler" />',
handler: function(place, macroName, params, wikifier, paramString) {
var wizard = new Wizard();
wizard.createWizard(place, 'Import a TiddlyWiki');
this.restart(wizard);
},
restart: function(wizard) {
var me = config.macros.fileImport;
wizard.addStep(me.step1Title, '<input type="hidden" '
+ 'name="markList" />');
var markList = wizard.getElement('markList');
var uploadWrapper = document.createElement('div');
markList.parentNode.insertBefore(uploadWrapper, markList);
uploadWrapper.setAttribute('refresh', 'macro');
uploadWrapper.getAttribute('macroName', 'fileImport');
$(uploadWrapper).append('<p>' + me.step1Text + '</p>');
var iframeName = 'reflectorImporter' + Math.random().toString();
me.createForm(uploadWrapper, wizard, iframeName);
wizard.setValue('serverType', 'tiddlyweb');
wizard.setValue('adaptor', new config.adaptors.file());
wizard.setValue('host', config.defaultCustomFields['server.host']);
wizard.setValue('context', {});
wizard.setButtons([{
caption: me.uploadLabel,
tooltip: me.uploadLabelPrompt,
onClick: function() {
var iframe = $('<iframe name="' + iframeName + '" '
+ 'style="display: none" />').appendTo(uploadWrapper);
// set an onload ready to hijack the form
me.setOnLoad(uploadWrapper, wizard, iframe[0]);
wizard.formElem.submit();
}
}]);
},
createForm: function(place, wizard, iframeName) {
var form = wizard.formElem;
var me = config.macros.fileImport;
form.action = me.reflectorURI;
form.enctype = 'multipart/form-data';
form.method = 'POST';
form.target = iframeName;
$(place).append('<input type="file" name="file" />');
},
setOnLoad: function(place, wizard, iframe) {
var me = config.macros.fileImport
var loadHandler = function() {
me.importTiddlers.apply(this, [place, wizard, iframe]);
};
iframe.onload = loadHandler;
completeReadyStateChanges = 0;
iframe.onreadystatechange = function() {
if (++(completeReadyStaeChanges) == 3) {
loadHandler();
}
}
},
importTiddlers: function(place, wizard, iframe) {
var tmpStore = new TiddlyWiki();
try {
var POSTedWiki= iframe.contentWindow
.document.documentElement.innerHTML;
} catch(e) {
displayMessage(config.macros.fileImport.incorrectTypeError);
config.macros.fileImport.restart(wizard);
return;
}
// now we are done, so remove the iframe
$(iframe).remove();
tmpStore.importTiddlyWiki(POSTedWiki);
var newTiddlers = tmpStore.getTiddlers();
var workspace = config.defaultCustomFields['server.workspace']
.split(/^[^\/]*\//)[1];
var context = {
status: true,
statusText: 'OK',
httpStatus: 200,
adaptor: wizard.getValue('adaptor'),
tiddlers: newTiddlers
};
context.adaptor.store = tmpStore;
wizard.setValue('context', context);
wizard.setValue('workspace', workspace);
wizard.setValue('inFileImport', true);
config.macros.importTiddlers.onGetTiddlerList(context, wizard);
}
};
_onGetTiddler = config.macros.importTiddlers.onGetTiddler;
config.macros.importTiddlers.onGetTiddler = function(context, wizard) {
if (wizard.getValue('inFileImport')) {
var me = config.macros.importTiddlers;
if(!context.status)
displayMessage("Error in importTiddlers.onGetTiddler: " + context.statusText);
var tiddler = context.tiddler;
var fields = tiddler.fields;
merge(fields, config.defaultCustomFields);
delete fields['server.permissions'];
delete fields['server.bag'];
delete fields['server.page.revision'];
delete fields['server.recipe'];
fields.changecount = 1;
store.saveTiddler(tiddler.title, tiddler.title, tiddler.text,
tiddler.modifier, tiddler.modified, tiddler.tags, tiddler.fields,
false, tiddler.created);
var remainingImports = wizard.getValue("remainingImports")-1;
wizard.setValue("remainingImports",remainingImports);
if(remainingImports == 0) {
if(context.isSynchronous) {
store.notifyAll();
refreshDisplay();
}
wizard.setButtons([
{caption: me.doneLabel, tooltip: me.donePrompt, onClick: me.onClose}
],me.statusDoneImport);
autoSaveChanges();
}
} else {
_onGetTiddler.apply(this, arguments);
}
};
_onCancel = config.macros.importTiddlers.onCancel;
config.macros.importTiddlers.onCancel = function(e)
{
var wizard = new Wizard(this);
if (!wizard.getValue('inFileImport')) {
return _onCancel.apply(this, arguments);
}
var place = wizard.clear();
config.macros.fileImport.restart(wizard);
return false;
};
_step3Html = config.macros.importTiddlers.step3Html;
_onGetTiddlerList = config.macros.importTiddlers.onGetTiddlerList;
config.macros.importTiddlers.onGetTiddlerList = function(context, wizard) {
var fileImport = config.macros.fileImport;
var importTiddlers = config.macros.importTiddlers;
if (wizard.getValue('inFileImport')) {
importTiddlers.step3Html = fileImport.step3Html;
} else {
importTiddlers.step3Html = _step3Html;
}
_onGetTiddlerList.apply(this, arguments);
}
})(jQuery);
//}}}
/*{{{*/
.headerForeground {
position: relative;
padding: 2em 0em 1em 0em;
float: right;
top: 0;
margin-right: 5.3em;
background-color: [[ColorPalette::PrimaryMid]];
text-align: right;
}
.header {
width: 100%; /* for ie */
}
.clearFloat {
clear: both;
}
#contentWrapper {
position: relative;
padding-top: 1px;
top: -1px;
}
.header {
position: relative;
background-color: [[ColorPalette::PrimaryMid]];
}
.siteTitle {
clear: both;
display: block;
}
#sidebarSearch {
padding: 0.8em 1em 1em;
width: 10.5em;
margin: 0.6em 0.6em;
float: right;
position: relative;
}
#sidebarSearch .txtOptionInput {
width: 100%;
margin-top: 5px;
}
#sidebarSearch .searchButton {
padding: 0.2em;
color: [[ColorPalette::Background]];
}
/*}}}*/
/***
|''Name''|TiddlySpaceUserControls|
|''Version''|0.5.0|
|''Description''|registration and login UIs|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceUserControls.js|
|''Requires''|TiddlySpaceConfig|
!HTMLForm
<form action="#">
<fieldset>
<legend />
<dl>
<dt class="_basic">Username:</dt>
<dd class="_basic"><input type="text" name="username" autocapitalize="off" autocorrect="off" /></dd>
<dt class="_basic">Password:</dt>
<dd class="_basic">
<input type="password" name="password" />
<input type="password" name="password_confirm" class="_register" />
</dd>
<dt class="_openid">OpenID:</dt>
<dd class="_openid"><input type="text" name="openid" autocapitalize="off" autocorrect="off" /></dd>
<dt class="_login">Method:</dt>
<dd class="_login">
<select>
<option value="basic">username & password</option>
<option value="openid">OpenID</option>
</select>
</dd>
</dl>
<input type="hidden" name="tiddlyweb_redirect" class="_openid" />
<p class="annotation" />
<input type="submit" />
</fieldset>
</form>
!Code
***/
//{{{
(function($) {
var tweb = config.extensions.tiddlyweb;
var tsl = config.macros.TiddlySpaceLogin = {
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
locale: {
label: "Login",
success: "logged in as %0",
loginError: "error logging in %0: %1",
forbiddenError: "login failed for <em>%0</em>: username and password do not match"
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var type = params[0];
this.name = macroName;
var container = $("<div />", { className: this.name }).appendTo(place);
this.refresh(container, type);
},
refresh: function(container, type) {
var msg = this.locale;
type = type || "basic";
var selector = type == "openid" ? "._basic" : "._openid";
var handler = function(ev) {
var form = $(this).closest("form");
return tsl[type + "Login"](form);
};
container.empty();
tweb.getUserInfo(function(user) {
if(user.anon) {
$(tsl.formTemplate).submit(handler).
find("legend").text(msg.label).end().
find("select").change(tsl.onSelect).end().
find("option[value=" + type + "]").
attr("selected", "selected").end().
find("._register, " + selector).remove().end().
find(".annotation").hide().end().
find("[type=submit]").val(msg.label).end().
appendTo(container);
}
});
},
onSelect: function(ev) {
var el = $(this);
var type = el.val();
var container = el.closest("." + tsl.name);
tsl.refresh(container, type);
},
basicLogin: function(form) {
var username = form.find("[name=username]").val();
var password = form.find("[name=password]").val();
this.login(username, password, tsl.redirect, function(xhr, error, exc) { // TODO: DRY (cf. displayMembers)
var ctx = {
msg: {
401: tsl.locale.forbiddenError.format([username])
},
form: form,
selector: "[name=username], [name=password]"
};
tsl.displayError(xhr, error, exc, ctx);
});
return false;
},
displayError: function(xhr, error, exc, ctx) {
error = ctx.msg[xhr.status] || // XXX: lacks parameters
"%0: %1".format([xhr.statusText, xhr.responseText]).htmlEncode();
var el = $(ctx.selector, ctx.form).addClass("error").focus(function(ev) {
el.removeClass("error").unbind(ev.originalEvent.type).
closest("form").find(".annotation").slideUp();
});
$(".annotation", ctx.form).html(error).slideDown();
},
login: function(username, password, callback, errback) {
var challenger = "cookie_form";
var uri = "%0/challenge/%1".format([tweb.host, challenger]);
$.ajax({
url: uri,
type: "POST",
data: {
user: username,
password: password,
tiddlyweb_redirect: tweb.serverPrefix + "/status" // workaround to marginalize automatic subsequent GET
},
success: callback,
error: function(xhr, error, exc) {
if(errback) {
errback.apply(this, arguments);
} else {
displayMessage(tsl.locale.loginError.format([username, error]));
}
}
});
},
openidLogin: function(form) {
var openid = form.find("[name=openid]").val();
var challenger = "tiddlywebplugins.tiddlyspace.openid";
var uri = "%0/challenge/%1".format([tweb.host, challenger]);
var redirect = tweb.serverPrefix || "/"; // must not be empty string
form.attr("action", uri).attr("method", "POST").
find("[name=tiddlyweb_redirect]").val(redirect);
return true;
},
redirect: function() {
window.location = tweb.host;
}
};
config.macros.TiddlySpaceLogout = {
locale: {
label: "Log out"
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var form = $('<form method="POST" />').addClass(macroName).
attr("action", tweb.host + "/logout");
$("<button />", { text: this.locale.label }).
click(function(ev) { form.submit(); }).
appendTo(form);
form.appendTo(place);
}
};
var tsr = config.macros.TiddlySpaceRegister = {
locale: {
label: "Sign Up",
userSuccess: "created user %0",
userError: "user <em>%0</em> already exists",
spaceSuccess: "created space %0",
spaceError: "space <em>%0</em> already exists",
charError: "error: invalid username - must only contain lowercase " +
"letters, digits or hyphens",
passwordError: "error: passwords do not match"
},
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
$(this.formTemplate).submit(this.onSubmit).
find("._login, ._openid").remove().end().
find("legend").text(this.locale.label).end().
find(".annotation").hide().end().
find("[type=submit]").val(this.locale.label).end().
appendTo(place);
},
onSubmit: function(ev) {
var form = $(this).closest("form");
var username = form.find("[name=username]").val();
var password = form.find("[name=password]").val();
var passwordConfirm = form.find("[name=password_confirm]").val();
var validName = config.extensions.tiddlyspace.isValidSpaceName(username);
if(validName && password && password == passwordConfirm) { // TODO: check password length?
tsr.register(username, password, form);
} else {
var xhr = { status: 409 }; // XXX: hacky
var msg = validName ? "passwordError" : "charError";
var ctx = {
msg: { 409: tsr.locale[msg] },
form: form,
selector: validName ? "[type=password]" : "[name=username]"
};
tsl.displayError(xhr, null, null, ctx);
}
return false;
},
register: function(username, password, form) {
var msg = tsr.locale;
var ctx = {
form: form,
selector: "[name=username]"
};
var userCallback = function(resource, status, xhr) {
displayMessage(msg.userSuccess.format([username])); // XXX: redundant?
tsl.login(username, password, function(data, status, xhr) {
var space = new tiddlyweb.Space(username, tweb.host);
space.create(spaceCallback, spaceErrback);
});
};
var userErrback = function(xhr, error, exc) {
ctx.msg = { 409: msg.userError.format([username]) };
tsl.displayError(xhr, error, exc, ctx);
};
var spaceCallback = function(resource, status, xhr) {
displayMessage(msg.spaceSuccess.format([username]));
tsl.redirect();
};
var spaceErrback = function(xhr, error, exc) {
ctx.msg = { 409: msg.spaceError.format([username]) }; // XXX: 409 unlikely to occur at this point
tsl.displayError(xhr, error, exc, ctx);
};
var user = new tiddlyweb.User(username, password, tweb.host);
user.create(userCallback, userErrback);
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceConfig|
|''Version''|0.5.4|
|''Description''|TiddlySpace configuration|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceConfig.js|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlyWebConfig ServerSideSavingPlugin|
!Code
***/
//{{{
(function($) {
var tweb = config.extensions.tiddlyweb;
var recipe = config.defaultCustomFields["server.workspace"].split("recipes/")[1];
// hijack search macro to add custom attributes for mobile devices
var _search = config.macros.search.handler;
config.macros.search.handler = function(place, macroName, params) {
_search.apply(this, arguments);
$(".searchField:input", place).
attr({ autocapitalize: "off", autocorrect: "off" });
};
// arg is either a container name or a tiddler object
// if fuzzy is truthy, space may be inferred from workspace (for new tiddlers)
// returns space object or false
var determineSpace = function(arg, fuzzy) {
if(typeof arg == "string") { // container name
var space = split(arg, "_", "r");
return ["public", "private"].contains(space.type) ? space : false;
} else if(arg) { // tiddler
var container = determineContainer(arg, fuzzy);
return container ? determineSpace(container.name, fuzzy) : false;
} else {
return false;
}
};
// if fuzzy is truthy, container may be inferred from workspace for new tiddlers
// returns container object or false
var determineContainer = function(tiddler, fuzzy) { // TODO: expose?
var bag = tiddler.fields["server.bag"];
var recipe = tiddler.fields["server.recipe"]; // XXX: unused/irrelevant/redundant!?
if(bag) {
return { type: "bag", name: bag };
} else if(recipe) {
return { type: "recipe", name: recipe };
} else if(fuzzy) { // new tiddler
var workspace = tiddler.fields["server.workspace"];
if(workspace) {
var container = split(workspace, "/", "l");
return ["bags", "recipes"].contains(container.type) ? container : false;
} else {
return false;
}
} else {
return false;
}
};
// hijack removeTiddlerCallback to restore tiddler from recipe cascade -- TODO: move into TiddlyWebWiki?
var sssp = config.extensions.ServerSideSavingPlugin;
var _removeTiddlerCallback = sssp.removeTiddlerCallback;
sssp.removeTiddlerCallback = function(context, userParams) {
var title = context.tiddler.title;
var recipe = context.tiddler.fields["server.recipe"];
_removeTiddlerCallback.apply(this, arguments);
if(recipe) {
context.workspace = "recipes/" + recipe;
var callback = function(context, userParams) {
if(context.status) {
store.saveTiddler(context.tiddler);
} else {
store.notify(title, true);
}
};
context.adaptor.getTiddler(title, context, null, callback);
}
};
// hijack getUserInfo to treat unknown users as anonymous
var _getUserInfo = tweb.getUserInfo;
tweb.getUserInfo = function(callback) {
_getUserInfo.call(this, function(user) {
if(!user.anon) { // double-check whether the user is real
$.ajax({
url: "%0/users/%1".format([tweb.host, user.name]),
type: "GET",
success: function(data, status, xhr) {
user.anon = false;
},
error: function(xhr, error, exc) {
user.anon = true;
},
complete: function(xhr, status) {
callback(user);
}
});
} else {
callback(user);
}
});
};
// splits a string once using delimiter
// mode "l" splits at the first, "r" at the last occurrence
// returns an object with members type and name
var split = function(str, sep, mode) {
mode = mode == "r" ? "pop" : "shift"; // TODO: use +/-1 instead of "l"/"r"?
var arr = str.split(sep);
var type = arr.length > 1 ? arr[mode]() : null;
return { type: type, name: arr.join(sep) };
};
// hijack saveTiddler to accept Tiddler instance
var _saveTiddler = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title, newTitle, newBody, modifier,
modified, tags, fields, clearChangeCount, created, creator) {
if(title instanceof Tiddler) { // overloading first argument
var t = $.extend(new Tiddler(title.title), title);
t = _saveTiddler.apply(this, [t.title, t.title, t.text, t.modifier,
t.modified, t.tags, t.fields, false, t.created, t.creator]);
return t;
} else {
return _saveTiddler.apply(this, arguments);
}
};
var coreBags = ["system", "tiddlyspace"];
var systemSpaces = ["plugins", "info", "images", "theme"];
systemSpaces = $.map(systemSpaces, function(item, i) {
return "system-%0_public".format(item);
});
var plugin = config.extensions.tiddlyspace = {
currentSpace: determineSpace(recipe),
coreBags: coreBags.concat(systemSpaces),
determineSpace: determineSpace,
isValidSpaceName: function(name) {
return name.match(/^[a-z][0-9a-z\-]*[0-9a-z]$/) ? true : false;
},
// returns the URL for a space's avatar (SiteIcon) based on a server_host
// object and an optional space name
// optional nocors argument prevents cross-domain URLs from being generated
getAvatar: function(host, space, nocors) {
if(space && typeof space != "string") { // backwards compatibility -- XXX: deprecated
space = space.name;
}
var subdomain = nocors ? plugin.currentSpace.name : space;
host = host ? this.getHost(host, subdomain) : "";
var bag = space ? "%0_public".format([space]) : "tiddlyspace";
return "%0/bags/%1/tiddlers/SiteIcon".format([host, bag]);
},
// returns the URL based on a server_host object (scheme, host, port) and an
// optional subdomain
getHost: function(host, subdomain) {
subdomain = subdomain ? subdomain + "." : "";
var url = "%0://%1%2".format([host.scheme, subdomain, host.host]);
var port = host.port;
if(port && !["80", "443"].contains(port)) {
url += ":" + port;
}
return url;
}
};
tweb.serverPrefix = tweb.host.split("/")[3] || ""; // XXX: assumes root handler
tweb.getStatus(function(status) {
var url = plugin.getHost(status.server_host);
tweb.status.server_host.url = url;
});
// set global read-only mode based on membership heuristics
var indicator = store.getTiddler("SiteTitle") || tiddler;
readOnly = !(recipe.split("_").pop() == "private" ||
tweb.hasPermission("write", indicator));
// ensure backstage is always initialized
// required to circumvent TiddlyWiki's read-only based handling
config.macros.backstageInit = {
init: function() {
showBackstage = true;
}
};
// register style sheet for backstage separately (important)
store.addNotification("StyleSheetBackstage", refreshStyles);
})(jQuery);
//}}}
/***
|''Name''|TiddlyWebAdaptor|
|''Description''|adaptor for interacting with TiddlyWeb|
|''Author:''|FND|
|''Contributors''|Chris Dent, Martin Budden|
|''Version''|1.3.8|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/adaptors/TiddlyWebAdaptor.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
|''Keywords''|serverSide TiddlyWeb|
!Notes
This plugin includes [[jQuery JSON|http://code.google.com/p/jquery-json/]].
!To Do
* createWorkspace
* document custom/optional context attributes (e.g. filters, query, revision) and tiddler fields (e.g. server.title, origin)
!Code
***/
//{{{
(function($) {
var adaptor = config.adaptors.tiddlyweb = function() {};
adaptor.prototype = new AdaptorBase();
adaptor.serverType = "tiddlyweb";
adaptor.serverLabel = "TiddlyWeb";
adaptor.mimeType = "application/json";
adaptor.parsingErrorMessage = "Error parsing result from server";
adaptor.noBagErrorMessage = "no bag specified for tiddler";
adaptor.locationIDErrorMessage = "no bag or recipe specified for tiddler"; // TODO: rename
// retrieve current status (requires TiddlyWeb status plugin)
adaptor.prototype.getStatus = function(context, userParams, callback) {
context = this.setContext(context, userParams, callback);
var uriTemplate = "%0/status";
var uri = uriTemplate.format([context.host]);
var req = httpReq("GET", uri, adaptor.getStatusCallback, context,
null, null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getStatusCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(status) {
context.serverStatus = $.evalJSON(responseText); // XXX: error handling!?
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// retrieve a list of workspaces
adaptor.prototype.getWorkspaceList = function(context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.workspaces = [];
var uriTemplate = "%0/recipes"; // XXX: bags?
var uri = uriTemplate.format([context.host]);
var req = httpReq("GET", uri, adaptor.getWorkspaceListCallback,
context, { accept: adaptor.mimeType }, null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getWorkspaceListCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(status) {
try {
var workspaces = $.evalJSON(responseText);
} catch(ex) {
context.status = false; // XXX: correct?
context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
if(context.callback) {
context.callback(context, context.userParams);
}
return;
}
context.workspaces = workspaces.map(function(itm) { return { title: itm }; });
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// retrieve a list of tiddlers
adaptor.prototype.getTiddlerList = function(context, userParams, callback) {
context = this.setContext(context, userParams, callback);
var uriTemplate = "%0/%1/%2/tiddlers%3";
var params = context.filters ? "?" + context.filters : "";
if(context.format) {
params = context.format + params;
}
var workspace = adaptor.resolveWorkspace(context.workspace);
var uri = uriTemplate.format([context.host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name), params]);
var req = httpReq("GET", uri, adaptor.getTiddlerListCallback,
context, merge({ accept: adaptor.mimeType }, context.headers), null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getTiddlerListCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(status) {
context.tiddlers = [];
try {
var tiddlers = $.evalJSON(responseText); //# NB: not actual tiddler instances
} catch(ex) {
context.status = false; // XXX: correct?
context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
if(context.callback) {
context.callback(context, context.userParams);
}
return;
}
for(var i = 0; i < tiddlers.length; i++) {
var t = tiddlers[i];
var tiddler = new Tiddler(t.title);
t.created = Date.convertFromYYYYMMDDHHMM(t.created);
t.modified = Date.convertFromYYYYMMDDHHMM(t.modified);
tiddler.assign(t.title, t.text, t.modifier, t.modified, t.tags, t.created, t.fields);
tiddler.fields["server.type"] = adaptor.serverType;
tiddler.fields["server.host"] = AdaptorBase.minHostName(context.host);
tiddler.fields["server.workspace"] = context.workspace;
tiddler.fields["server.page.revision"] = t.revision;
context.tiddlers.push(tiddler);
}
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// perform global search
adaptor.prototype.getSearchResults = function(context, userParams, callback) {
context = this.setContext(context, userParams, callback);
var uriTemplate = "%0/search?q=%1%2";
var filterString = context.filters ? ";" + context.filters : "";
var uri = uriTemplate.format([context.host, context.query, filterString]); // XXX: parameters need escaping?
var req = httpReq("GET", uri, adaptor.getSearchResultsCallback,
context, { accept: adaptor.mimeType }, null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getSearchResultsCallback = function(status, context, responseText, uri, xhr) {
adaptor.getTiddlerListCallback(status, context, responseText, uri, xhr); // XXX: use apply?
};
// retrieve a particular tiddler's revisions
adaptor.prototype.getTiddlerRevisionList = function(title, limit, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions";
var workspace = adaptor.resolveWorkspace(context.workspace);
var uri = uriTemplate.format([context.host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name), adaptor.normalizeTitle(title)]);
var req = httpReq("GET", uri, adaptor.getTiddlerRevisionListCallback,
context, merge({ accept: adaptor.mimeType }, context.headers), null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getTiddlerRevisionListCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(status) {
context.revisions = [];
try {
var tiddlers = $.evalJSON(responseText); //# NB: not actual tiddler instances
} catch(ex) {
context.status = false; // XXX: correct?
context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
if(context.callback) {
context.callback(context, context.userParams);
}
return;
}
for(var i = 0; i < tiddlers.length; i++) {
var t = tiddlers[i];
var tiddler = new Tiddler(t.title);
tiddler.assign(t.title, null, t.modifier, Date.convertFromYYYYMMDDHHMM(t.modified),
t.tags, Date.convertFromYYYYMMDDHHMM(t.created), t.fields);
tiddler.fields["server.type"] = adaptor.serverType;
tiddler.fields["server.host"] = AdaptorBase.minHostName(context.host);
tiddler.fields["server.page.revision"] = t.revision;
tiddler.fields["server.workspace"] = "bags/" + t.bag;
context.revisions.push(tiddler);
}
var sortField = "server.page.revision";
context.revisions.sort(function(a, b) {
return a.fields[sortField] < b.fields[sortField] ? 1 :
(a.fields[sortField] == b.fields[sortField] ? 0 : -1);
});
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// retrieve an individual tiddler revision -- XXX: breaks with standard arguments list -- XXX: convenience function; simply use getTiddler?
adaptor.prototype.getTiddlerRevision = function(title, revision, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.revision = revision;
return this.getTiddler(title, context, userParams, callback);
};
// retrieve an individual tiddler
//# context is an object with members host and workspace
//# callback is passed the new context and userParams
adaptor.prototype.getTiddler = function(title, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.title = title;
if(context.revision) {
var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions/%4";
} else {
uriTemplate = "%0/%1/%2/tiddlers/%3";
}
if(!context.tiddler) {
context.tiddler = new Tiddler(title);
}
context.tiddler.fields["server.type"] = adaptor.serverType;
context.tiddler.fields["server.host"] = AdaptorBase.minHostName(context.host);
context.tiddler.fields["server.title"] = title; //# required for detecting renames
context.tiddler.fields["server.workspace"] = context.workspace;
var workspace = adaptor.resolveWorkspace(context.workspace);
var uri = uriTemplate.format([context.host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name), adaptor.normalizeTitle(title),
context.revision]);
var req = httpReq("GET", uri, adaptor.getTiddlerCallback, context,
merge({ accept: adaptor.mimeType }, context.headers), null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getTiddlerCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(status) {
try {
var t = $.evalJSON(responseText); //# NB: not an actual tiddler instance
} catch(ex) {
context.status = false;
context.statusText = exceptionText(ex, adaptor.parsingErrorMessage);
if(context.callback) {
context.callback(context, context.userParams);
}
return;
}
context.tiddler.assign(context.tiddler.title, t.text, t.modifier,
Date.convertFromYYYYMMDDHHMM(t.modified), t.tags || [],
Date.convertFromYYYYMMDDHHMM(t.created), context.tiddler.fields,
t.creator); // XXX: merge extended fields!?
context.tiddler.fields["server.bag"] = t.bag;
context.tiddler.fields["server.etag"] = xhr.getResponseHeader("Etag");
if(t.recipe) {
context.tiddler.fields["server.recipe"] = t.recipe;
}
context.tiddler.fields["server.workspace"] = "bags/" + t.bag;
context.tiddler.fields["server.page.revision"] = t.revision;
context.tiddler.fields["server.permissions"] = t.permissions.join(", ");
if(t.type && t.type != "None") {
context.tiddler.fields["server.content-type"] = t.type;
}
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// retrieve tiddler chronicle (all revisions)
adaptor.prototype.getTiddlerChronicle = function(title, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.title = title;
var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions?fat=1";
var workspace = adaptor.resolveWorkspace(context.workspace);
var uri = uriTemplate.format([context.host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name), adaptor.normalizeTitle(title)]);
var req = httpReq("GET", uri, adaptor.getTiddlerChronicleCallback,
context, { accept: adaptor.mimeType }, null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.getTiddlerChronicleCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(status) {
context.responseText = responseText;
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// store an individual tiddler
adaptor.prototype.putTiddler = function(tiddler, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.title = tiddler.title;
context.tiddler = tiddler;
context.host = context.host || this.fullHostName(tiddler.fields["server.host"]);
var uriTemplate = "%0/%1/%2/tiddlers/%3";
try {
context.workspace = context.workspace || tiddler.fields["server.workspace"];
var workspace = adaptor.resolveWorkspace(context.workspace);
} catch(ex) {
return adaptor.locationIDErrorMessage;
}
var uri = uriTemplate.format([context.host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name),
adaptor.normalizeTitle(tiddler.title)]);
var etag = adaptor.generateETag(workspace, tiddler);
var headers = etag ? { "If-Match": etag } : null;
var payload = {
type: tiddler.fields["server.content-type"] || null,
text: tiddler.text,
tags: tiddler.tags,
fields: $.extend({}, tiddler.fields)
};
delete payload.fields.changecount;
$.each(payload.fields, function(key, value) {
if(key.indexOf("server.") == 0) {
delete payload.fields[key];
}
});
payload = $.toJSON(payload);
var req = httpReq("PUT", uri, adaptor.putTiddlerCallback,
context, headers, payload, adaptor.mimeType, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.putTiddlerCallback = function(status, context, responseText, uri, xhr) {
context.status = [204, 1223].contains(xhr.status);
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(context.status) {
var bag = xhr.getResponseHeader("Location").
split("/bags/").pop().split("/")[0];
context.tiddler.fields["server.bag"] = bag;
var etag = xhr.getResponseHeader("Etag");
if(etag) {
context.tiddler.fields["server.etag"] = etag;
if(context.callback) {
context.callback(context, context.userParams);
}
} else { // IE
context.adaptor.getTiddler(context.tiddler.title, context,
context.userParams, context.callback);
}
} else if(context.callback) {
context.callback(context, context.userParams);
}
};
// store a tiddler chronicle
adaptor.prototype.putTiddlerChronicle = function(revisions, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.title = revisions[0].title;
var headers = null;
var uriTemplate = "%0/%1/%2/tiddlers/%3/revisions";
var host = context.host || this.fullHostName(tiddler.fields["server.host"]);
var workspace = adaptor.resolveWorkspace(context.workspace);
var uri = uriTemplate.format([host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name),
adaptor.normalizeTitle(context.title)]);
if(workspace.type == "bag") { // generate ETag
var etag = [adaptor.normalizeTitle(workspace.name),
adaptor.normalizeTitle(context.title), 0].join("/"); //# zero-revision prevents overwriting existing contents
headers = { "If-Match": '"' + etag + '"' };
}
var payload = $.toJSON(revisions);
var req = httpReq("POST", uri, adaptor.putTiddlerChronicleCallback,
context, headers, payload, adaptor.mimeType, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.putTiddlerChronicleCallback = function(status, context, responseText, uri, xhr) {
context.status = [204, 1223].contains(xhr.status);
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(context.callback) {
context.callback(context, context.userParams);
}
};
// store a collection of tiddlers (import TiddlyWiki HTML store)
adaptor.prototype.putTiddlerStore = function(store, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
var uriTemplate = "%0/%1/%2/tiddlers";
var host = context.host;
var workspace = adaptor.resolveWorkspace(context.workspace);
var uri = uriTemplate.format([host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name)]);
var req = httpReq("POST", uri, adaptor.putTiddlerStoreCallback,
context, null, store, "text/x-tiddlywiki", null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.putTiddlerStoreCallback = function(status, context, responseText, uri, xhr) {
context.status = [204, 1223].contains(xhr.status);
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(context.callback) {
context.callback(context, context.userParams);
}
};
// rename an individual tiddler or move it to a different workspace -- TODO: make {from|to}.title optional
//# from and to are objects with members title and workspace (bag; optional),
//# representing source and target tiddler, respectively
adaptor.prototype.moveTiddler = function(from, to, context, userParams, callback) { // XXX: rename parameters (old/new)?
var self = this;
var newTiddler = store.getTiddler(from.title) || store.getTiddler(to.title); //# local rename might already have occurred
var oldTiddler = $.extend(true, {}, newTiddler); //# required for eventual deletion
oldTiddler.title = from.title; //# required for original tiddler's ETag
var _getTiddlerChronicle = function(title, context, userParams, callback) {
return self.getTiddlerChronicle(title, context, userParams, callback);
};
var _putTiddlerChronicle = function(context, userParams) {
if(!context.status) {
return callback(context, userParams);
}
var revisions = $.evalJSON(context.responseText); // XXX: error handling?
// change current title while retaining previous location
for(var i = 0; i < revisions.length; i++) {
delete revisions[i].revision;
if(!revisions[i].fields.origin) { // NB: origin = "<workspace>/<title>"
revisions[i].fields.origin = ["bags", revisions[i].bag, revisions[i].title].join("/");
}
revisions[i].title = to.title;
}
// add new revision
var rev = $.extend({}, revisions[0]);
rev.title = to.title;
$.each(newTiddler, function(i, item) {
if(!$.isFunction(item)) {
rev[i] = item;
}
});
rev.created = rev.created.convertToYYYYMMDDHHMM();
rev.modified = new Date().convertToYYYYMMDDHHMM();
delete rev.fields.changecount;
revisions.unshift(rev);
if(to.workspace) {
context.workspace = to.workspace;
} else if(context.workspace.substring(0, 4) != "bags") { // NB: target workspace must be a bag
context.workspace = "bags/" + rev.bag;
}
var subCallback = function(context, userparams) {
context.adaptor.getTiddler(newTiddler.title, context, userParams, _deleteTiddler);
};
return self.putTiddlerChronicle(revisions, context, context.userParams, subCallback);
};
var _deleteTiddler = function(context, userParams) {
if(!context.status) {
return callback(context, userParams);
}
context.callback = null;
return self.deleteTiddler(oldTiddler, context, context.userParams, callback);
};
callback = callback || function() {};
context = this.setContext(context, userParams);
context.host = context.host || oldTiddler.fields["server.host"];
context.workspace = from.workspace || oldTiddler.fields["server.workspace"];
return _getTiddlerChronicle(from.title, context, userParams, _putTiddlerChronicle);
};
// delete an individual tiddler
adaptor.prototype.deleteTiddler = function(tiddler, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.title = tiddler.title; // XXX: not required!?
var uriTemplate = "%0/bags/%1/tiddlers/%2";
var host = context.host || this.fullHostName(tiddler.fields["server.host"]);
var bag = tiddler.fields["server.bag"];
if(!bag) {
return adaptor.noBagErrorMessage;
}
var uri = uriTemplate.format([host, adaptor.normalizeTitle(bag),
adaptor.normalizeTitle(tiddler.title)]);
var etag = adaptor.generateETag({ type: "bag", name: bag }, tiddler);
var headers = etag ? { "If-Match": etag } : null;
var req = httpReq("DELETE", uri, adaptor.deleteTiddlerCallback, context, headers,
null, null, null, null, true);
return typeof req == "string" ? req : true;
};
adaptor.deleteTiddlerCallback = function(status, context, responseText, uri, xhr) {
context.status = [204, 1223].contains(xhr.status);
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
if(context.callback) {
context.callback(context, context.userParams);
}
};
// compare two revisions of a tiddler (requires TiddlyWeb differ plugin)
//# if context.rev1 is not specified, the latest revision will be used for comparison
//# if context.rev2 is not specified, the local revision will be sent for comparison
//# context.format is a string as determined by the TiddlyWeb differ plugin
adaptor.prototype.getTiddlerDiff = function(title, context, userParams, callback) {
context = this.setContext(context, userParams, callback);
context.title = title;
var tiddler = store.getTiddler(title);
try {
var workspace = adaptor.resolveWorkspace(tiddler.fields["server.workspace"]);
} catch(ex) {
return adaptor.locationIDErrorMessage;
}
var tiddlerRef = [workspace.type + "s", workspace.name, tiddler.title].join("/");
var rev1 = context.rev1 ? [tiddlerRef, context.rev1].join("/") : tiddlerRef;
var rev2 = context.rev2 ? [tiddlerRef, context.rev2].join("/") : null;
var uriTemplate = "%0/diff?rev1=%1";
if(rev2) {
uriTemplate += "&rev2=%2";
}
if(context.format) {
uriTemplate += "&format=%3";
}
var host = context.host || this.fullHostName(tiddler.fields["server.host"]);
var uri = uriTemplate.format([host, adaptor.normalizeTitle(rev1),
adaptor.normalizeTitle(rev2), context.format]);
if(rev2) {
var req = httpReq("GET", uri, adaptor.getTiddlerDiffCallback, context, null,
null, null, null, null, true);
} else {
var payload = {
title: tiddler.title,
text: tiddler.text,
modifier: tiddler.modifier,
tags: tiddler.tags,
fields: $.extend({}, tiddler.fields)
}; // XXX: missing attributes!?
payload = $.toJSON(payload);
req = httpReq("POST", uri, adaptor.getTiddlerDiffCallback, context,
null, payload, adaptor.mimeType, null, null, true);
}
return typeof req == "string" ? req : true;
};
adaptor.getTiddlerDiffCallback = function(status, context, responseText, uri, xhr) {
context.status = status;
context.statusText = xhr.statusText;
context.httpStatus = xhr.status;
context.uri = uri;
if(status) {
context.diff = responseText;
}
if(context.callback) {
context.callback(context, context.userParams);
}
};
// generate tiddler information
adaptor.prototype.generateTiddlerInfo = function(tiddler) {
var info = {};
var uriTemplate = "%0/%1/%2/tiddlers/%3";
var host = this.host || tiddler.fields["server.host"]; // XXX: this.host obsolete?
host = this.fullHostName(host);
var workspace = adaptor.resolveWorkspace(tiddler.fields["server.workspace"]);
info.uri = uriTemplate.format([host, workspace.type + "s",
adaptor.normalizeTitle(workspace.name),
adaptor.normalizeTitle(tiddler.title)]);
return info;
};
adaptor.resolveWorkspace = function(workspace) {
var components = workspace.split("/");
return {
type: components[0] == "bags" ? "bag" : "recipe",
name: components[1] || components[0]
};
};
adaptor.generateETag = function(workspace, tiddler) {
var revision = tiddler.fields["server.page.revision"];
var etag = revision == "false" ? null : tiddler.fields["server.etag"];
if(!etag && workspace.type == "bag") {
if(typeof revision == "undefined") {
revision = "0";
} else if(revision == "false") {
return null;
}
etag = [adaptor.normalizeTitle(workspace.name),
adaptor.normalizeTitle(tiddler.title), revision].join("/");
etag = '"' + etag + '"';
}
return etag;
};
adaptor.normalizeTitle = function(title) {
return encodeURIComponent(title);
};
})(jQuery);
/*
* jQuery JSON Plugin
* version: 1.3
* source: http://code.google.com/p/jquery-json/
* license: MIT (http://www.opensource.org/licenses/mit-license.php)
*/
(function($){function toIntegersAtLease(n)
{return n<10?'0'+n:n;}
Date.prototype.toJSON=function(date)
{return this.getUTCFullYear()+'-'+
toIntegersAtLease(this.getUTCMonth())+'-'+
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.quoteString=function(string)
{if(escapeable.test(string))
{return'"'+string.replace(escapeable,function(a)
{var c=meta[a];if(typeof c==='string'){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};$.toJSON=function(o,compact)
{var type=typeof(o);if(type=="undefined")
return"undefined";else if(type=="number"||type=="boolean")
return o+"";else if(o===null)
return"null";if(type=="string")
{return $.quoteString(o);}
if(type=="object"&&typeof o.toJSON=="function")
return o.toJSON(compact);if(type!="function"&&typeof(o.length)=="number")
{var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i],compact));}
if(compact)
return"["+ret.join(",")+"]";else
return"["+ret.join(", ")+"]";}
if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.");}
var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number")
name='"'+k+'"';else if(type=="string")
name=$.quoteString(k);else
continue;var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;}
if(compact)
ret.push(name+":"+val);else
ret.push(name+": "+val);}
return"{"+ret.join(", ")+"}";};$.compactJSON=function(o)
{return $.toJSON(o,true);};$.evalJSON=function(src)
{return eval("("+src+")");};$.secureEvalJSON=function(src)
{var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
return eval("("+src+")");else
throw new SyntaxError("Error parsing JSON, source is not valid.");};})(jQuery);
//}}}
iVBORw0KGgoAAAANSUhEUgAAABgAAAAZCAYAAAArK+5dAAAACXBIWXMAAChpAAAoaQG7rfh7AAAC7ElEQVRIDa1WSa7aQBAtwAwBFOYNCxbAJmfIGSL9ZS7BKbgI54AlGwSLLBASSCDEAvjMswAb7PTruDu2MfzoKyW16KHq1VzG41OUezqV8ui6Ti/I8+LN9UlRFJpOpz8UBn4rlUqB0+nkyvjsEgDP6Ha7Ed7L5fJ3hVmu7ff7wGKxoN1uRz6f75kcvxfv9/vdlQ/3qVSKwuEw3jOKYRgaNAK8WCxSMpl0FYRFl8uF1us1BYNBDgI5J7Gw0Gw2Ewp0+KkJawAej8edMvxcr9ep0WjQ8XjkXubzeXp7e6NoNGrjR6gnkwldr1d+7/V4PKqbJVaparVKWCyU/FrTNOp2u1SpVLhCKy/2MFgYDQXcA3HhZB6NRtRsNsnv9/OFHGAfCAQIeavVajYRkSPTA4Mn+Rk4JFutFgcAoJNQ2v1+n5bLJaXTafkMPFVV+dnLiIcIl87SQ1Ln8zmzOMDjDuusC55AbjAYSHBg4A4LZEuy5DI3SCjy42a94GUG0vv7TBzlr1SAMoU79/tjJyOOsMjrtb8BVBDCdLmcxZH/AksqQKPhoOuPjROJRHjNC2YbinmAAicBy0wBKShTAeDMAXoCvYHmslptBYSCUOiLvBI5MC8M3slQIJRITnOTzWbpcDi8VBCLfbWJWbHgwcs+SCQSsgdsKOYBYDDCSvBKhE5hDEzBYxxRolibzYaFIMQ8cB+CoZD3QYHNA1bXqqapXCPiB9BOp0Pb7VY2CxS4EYAKhcLDPAKv9IDtNVyAGTWPGbNarXhDvap/NBxkMFlhlDACRmJWSQVsw3MAJQBGQp0TEm/PaDwe85mUyWQol8tJNjNMhoJRAW1YaCzzQyEZ/3WDwQdvYrEYx5IeoIrgEghuP1OAt49IfANgvVTADjxE5/OZ2u32Rxi2d2f1+XxeGg6HvDikAiZxw1TcbnfU6/VsAJ89oKT9/j9/ChRWAXv2Db2ysvw7wT6LbJEzR4uO/zvf2PrJFj6uBlv/i4D16zfZO8ztrLtRkQAAAABJRU5ErkJggg==
<html>
<div id="space1" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space2" class="public_bubble bubble large"><div class="private_bubble"></div></div>
<div id="space3" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space4" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space5" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space6" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space7" class="public_bubble bubble large"><div class="private_bubble"></div></div>
<div id="space8" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space9" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space10" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space11" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space12" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space13" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space14" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space15" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space16" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space17" class="public_bubble bubble large"><div class="private_bubble"></div></div>
<div id="space18" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space19" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space20" class="public_bubble bubble large"><div class="private_bubble"></div></div>
<div id="space21" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space22" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space23" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space24" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space25" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space26" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space27" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space28" class="public_bubble bubble small"><div class="private_bubble"></div></div>
<div id="space29" class="public_bubble bubble medium"><div class="private_bubble"></div></div>
<div id="space30" class="public_bubble bubble small"><div class="private_bubble"></div></div>
</html>
/*{{{*/
.concertina {
overflow: hidden;
display: none;
padding: 0.7em;
background-color: white;
}
.concertinaOn .concertina {
display: auto;
padding: 10px;
height: auto;
border-bottom: 1px solid [[ColorPalette: :PrimaryDark]];
overflow: auto;
}
.privateNotPublic .concertina,
.private .concertina {
background: -webkit-gradient(linear, left bottom, left top, color-stop(0.29, rgb(222,133,179)), color-stop(1, rgb(245,208,229)), color-stop(0.71, rgb(255,224,241)));
background: -moz-linear-gradient(center bottom, rgb(222,133,179) 29%, rgb(245,208,229) 100%, rgb(255,224,241) 71%);
/* For Internet Explorer 5.5 - 7 */
filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#ffffffff, endColorstr=#ffDE85B3)";
/* For Internet Explorer 8 */
-ms-filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#ffffffff, endColorstr=#ffDE85B3)";
}
.public .concertina,
.privateAndPublic .concertina {
background: -webkit-gradient(linear, left bottom, left top, color-stop(0.55, rgb(187,231,253)), color-stop(1, rgb(197,233,252)), color-stop(0.74, rgb(220,238,250)));
background: -moz-linear-gradient(center bottom, rgb(187,231,253) 55%, rgb(197,233,252) 100%, rgb(220,238,250) 74%);
/* For Internet Explorer 5.5 - 7 */
filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#ffffffff, endColorstr=#ffBBE7FD)";
/* For Internet Explorer 8 */
-ms-filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#ffffffff, endColorstr=#ffBBE7FD)";
}
.external .concertina {
background-color: white;
background: -webkit-gradient(linear, left bottom, left top, color-stop(0.25, rgb(139,214,158)), color-stop(1, rgb(175,230,187)), color-stop(0.74, rgb(204,240,213)));
background: -moz-linear-gradient(center bottom, rgb(139,214,158) 25%, rgb(175,230,187) 100%, rgb(204,240,213) 74%);
/* For Internet Explorer 5.5 - 7 */
filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#ffffffff, endColorstr=#ff8BD69E)";
/* For Internet Explorer 8 */
-ms-filter: "progid: DXImageTransform.Microsoft.gradient(startColorstr=#ffffffff, endColorstr=#ff8BD69E)";
}
.concertina .publishButton {
border-radius: 1em;
-webkit-border-radius: 1em;
-moz-border-radius: 1em;
background-color: white;
border: 1px solid black;
display: block;
padding: 0.7em;
text-align: center;
width: 12em;
}
.content .calendar {
margin-left: 2em;
position: relative;
width: 46px;
float: right;
margin-top: 2em;
cursor: pointer;
}
.content .calendar:hover {
opacity: 0.2;
}
.selected .tagging,
.selected .tagged,
.selected .tagging:hover,
.selected .tagged:hover {
background: none;
border: none;
}
.tagged {
float: right;
position: relative;
right: -2.4em;
}
.tagging, .tagged {
background: none;
border: none;
}
.tagging {
float: none;
}
.tagging li {
display: inline;
float: left;
}
.tagging .tiddlyLink {
-webkit-border-radius: 5px 5px 5px 5px;
-moz-border-radius: 5px 5px 5px 5px;
background-color: white;
margin: 0 0.2em 0.2em;
display: block;
padding: 0.8em;
}
.tagged .button {
-webkit-border-radius: 15px 0px 0px 15px;
-moz-border-radius: 15px 0px 0px 15px;
background-color: white;
border-bottom: 2px solid #ccc;
border-left: 2px solid #ccc;
border-top: 2px solid #ccc;
display: block;
margin: 0 0 0.3em -1.1em;
padding: 0.4em;
font-size: 0.9em;
width: 8em;
word-wrap: break-word;
color: [[ColorPalette: :Background]];
background: [[ColorPalette: :TertiaryMid]];
}
/* for following */
#popup .siteIcon {
float: left;
height: 25px;
}
.content {
position: relative;
top: 0;
left: 0;
width: 100%; /* IE */
}
.content .info {
float: right;
position: relative;
right: 1em;
top: 0;
width: 9em;
z-index: 2;
}
.heading {
left: 0;
margin-bottom: 3em;
position: relative;
top: 3em;
position: relative;
}
.followButton a:hover {
background: none;
color: black;
}
.followPlaceHolder {
position: absolute;
left: 5.8em;
top: 0.5em;
}
.followButton {
cursor: pointer;
-webkit-border-radius: 0.3em;
-moz-border-radius: 0.3em;
background: none repeat scroll 0 0 #CCCCCC;
color: red;
min-width: 2em;
height: 1em;
padding: 0.4em;
text-align: center;
}
.followButton:before {
content: "\00a0";
display: block; /* reduce the damage in FF3.0 */
position: absolute;
bottom: -0.2em;
left: 0.1em;
width: 0;
height: 0;
border-width: 0.5em 0.2em 0 0.6em;
border-style: solid;
border-color: #ccc transparent;
}
.calendar .month {
padding: 2px;
color: white;
text-align: center;
border-left: solid 1px black;
border-right: solid 1px black;
border-top: solid 1px black;
background-color: #F09CA7;
}
.toolbar svg {
height: 20px;
width: 20px;
}
.toolbar svg .glyph{
fill: #ccc;
}
.toolbar a:hover .glyph{
fill: #111;
}
.calendar .date {
background-color: white;
color: #515151;
font-weight: bold;
text-align: center;
font-size: 1.8em;
border: solid 1px black;
}
.calendar .time {
font-size: 0.7em;
background-color: white;
border-left: solid 1px black;
border-right: solid 1px black;
border-bottom: solid 1px black;
text-align: center;
}
.originButton,
.modifierIcon .label {
color: [[ColorPalette: :TertiaryDark]];
font-size: 0.8em;
text-align: center;
display: block;
}
.modifierIcon {
margin-right: 2em;
position: relative;
float: right;
}
.tiddler .viewer {
margin: 0 12em 0 2em;
padding-bottom: 4em;
line-height: normal;
}
.viewer pre {
margin-left: 0;
}
.tiddler .title {
font-size: 1.7em;
display: block;
padding-bottom: 0.5em;
margin-bottom: 0.4em;
border-bottom: 0.05em solid [[ColorPalette: :PrimaryDark]];
word-wrap: break-word;
}
.spaceIcon img {
height: 40px;
}
.siteIcon .label {
color: [[ColorPalette: :TertiaryDark]];
}
.siteIcon {
text-align: center;
}
.tiddler .spaceSiteIcon {
width: 7em;
margin-top: -15px;
position: relative;
float: left;
margin-top: 0em;
}
.followButton a {
color: red;
}
.tiddler {
position: relative;
-moz-box-shadow: 2px 2px 8px black;
-webkit-box-shadow: 2px 2px 8px black;
filter: progid: DXImageTransform.Microsoft.Shadow(color='#000000', Direction=135, Strength=3);
box-shadow: 2px 2px 8px black;
background-color: white;
margin-bottom: 2em;
padding: 0;
}
.tiddler .editor {
padding-left: 1em;
padding-right: 1em;
}
.tiddler .heading .title {
margin-left: 5em;
margin-right: 7em;
position: relative;
}
.tiddler .headingClear {
clear: both;
}
.tiddler .subtitle {
font-size: 0.8em;
margin-top: 0.2em;
}
.external .spaceSiteIcon a:hover {
background-color: #8BD69E;
}
.privateNotPublic .spaceSiteIcon a:hover,
.private .spaceSiteIcon a:hover {
background-color: #DE85B3;
}
.privateAndPublic .spaceSiteIcon a:hover,
.public .spaceSiteIcon a:hover {
background-color: #BBE7FD;
}
.toolbar {
position: absolute;
padding: 1em 1em 0 0;
top: 0px;
right: 0px;
}
.tiddler .toolbar .button {
float: left;
border: none;
display: block;
}
.tiddler .toolbar a:hover {
background-color: #ccc;
border: solid 1px #000;
}
.tiddler .button.command_closeTiddler {
float: right;
}
.tiddler .tagged .listTitle {
display: none;
}
.revButton {
float: right;
}
/*! EditTemplate specific*/
.tiddler .privacySettings {
text-align: center;
}
.tiddler .privacySettings .originButton{
display: inline;
}
.annotationsBox {
margin-top: 4em;
}
.editorFooter {
padding: 0.3em 1em;
}
.heading .editor input {
width: 90%;
font-size: 1.5em;
}
/*}}}*/
/***
|''Name''|BinaryUploadPlugin|
|''Version''|0.3.4|
|''Author''|Ben Gillies and Jon Robson|
|''Type''|plugin|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/BinaryUploadPlugin.js|
|''Description''|Upload a binary file to TiddlyWeb|
|''Requires''|TiddlySpaceConfig|
!Usage
{{{
<<binaryUpload bag:<name> edit:tags edit:title tags:<default tags> title:<title> >>
}}}
* {{{bag:<name>}}}: optional; if left out, the file will be saved to the current workspace
* {{{edit:tags}}}: specifies that you want to tag the file being uploaded
* {{{edit:title}}}: specifies that you want to set the title to something other than the filename
* {{{tags:<default tags>}}}: specifies a default set of tags to apply to the file (requires {{{edit:tags}}} to be set)
* {{{title:<title>}}}: predefines the title of the binary tiddler
!Requires
TiddlyWeb
tiddlywebplugins.form
!Code
***/
//{{{
(function($) {
var macro = config.macros.binaryUpload ={
locale: {
titleDefaultValue: "Please enter a title...",
tagsDefaultValue: "Please enter some tags...",
titlePrefix: "title: ",
tagsPrefix: "tags: ",
loadSuccess: 'Tiddler %0 successfully uploaded',
loadError: "An error occurred when uploading the tiddler %0",
uploadInProgress: "Please wait while the file is uploaded..."
},
createUploadForm: function(place, tiddler, options) {
var bag = options.bag;
var editableFields = options.edit;
var defaults = config.defaultCustomFields;
var locale = macro.locale;
place = $('<div class="container" />').appendTo(place)[0];
var uploadTo = bag ? "bags/%0".format([bag]) : defaults["server.workspace"];
var includeFields = {
tags: editableFields && editableFields.contains("tags") ? true : false,
title: editableFields && editableFields.contains("title") ? true : false
};
var baseURL = defaults["server.host"];
baseURL += (baseURL[baseURL.length - 1] !== "/") ? "/" : "";
baseURL = "%0%1/tiddlers".format([baseURL, uploadTo]);
//create the upload form, complete with invisible iframe
var iframeName = "binaryUploadiframe%0".format([Math.random()]);
var editables = [];
var fields = ["title", "tags"];
for(var i = 0; i < fields.length; i++) {
var fieldName = fields[i];
var userDefault = options[fieldName];
var defaultValue = userDefault ? userDefault : false;
if(includeFields[fieldName] || defaultValue) {
var localeDefault = locale["%0DefaultValue".format([fieldName])];
var className = defaultValue ? "userInput" : "userInput notEdited";
var inputEl;
var val = defaultValue || localeDefault;
if(defaultValue && !includeFields[fieldName]) {
inputEl = $('<input type="hidden" /><input type="text" disabled />');
} else {
inputEl = $('<input type="text" />');
}
inputEl.attr("name", fieldName).
addClass("%0Edit".format([fieldName])).
val(val).addClass(className);
var editEl = $("<span />").text(locale["%0Prefix".format([fieldName])]).
appendTo('<div class="binaryUpload%0"></div>'.format([fieldName])).
append(inputEl)[0];
editables.push(editEl);
}
}
var pleaseWait = $('<div />').text(locale.uploadInProgress).hide().appendTo(place);
var frameHtml = '<form class="binaryUploadForm" action="%0" method="POST" enctype="multipart/form-data" />'.
format([baseURL]);
$(frameHtml).
append(editables).
append('<div class="binaryUploadFile"><input type="file" name="file" /></div>').
append('<div class="binaryUploadSubmit"><input type="submit" value="Upload" /></div>').
submit(function(ev) {
this.target = iframeName;
var existingVal = $("input[name=title]", place).val();
var fileName = existingVal || $('input:file', place).val();
if (!fileName) {
return false; // the user hasn't selected a file yet
}
var fStart = fileName.lastIndexOf("\\");
var fStart2 = fileName.lastIndexOf("/");
fStart = fStart < fStart2 ? fStart2 : fStart;
fileName = fileName.substr(fStart+1);
$("input[name=title]", place).val(fileName);
var form = $(this);
// we need to go somewhere afterwards to ensure the onload event triggers
this.action = "%0?redirect=/tiddlers".format([baseURL, fileName]); // dont use jquery to work with ie
/*$('<iframe name="%0" id="%0" />'.format([iframeName])).
css('display','none').appendTo(place);*/
$(place).append($('<iframe name="' + iframeName + '" id="' + iframeName + '"/>').css('display','none'));
macro.iFrameLoader(iframeName, fileName, place, uploadTo, tiddler, baseURL, function() {
form.show(1000);
pleaseWait.hide(1000);
});
form.hide(1000);
pleaseWait.show(1000);
return true;
}).appendTo(place);
$(".notEdited", place).mousedown(function(ev) { // clear default text on click
var target = $(ev.target);
if(target.hasClass("notEdited")) {
target.removeClass("notEdited");
target.val("");
}
});
$("input[name=file]", place).change(function(ev) {
var target = $(ev.target);
var fileName = target.val();
var titleInput = $("input[name=title]", place);
if(titleInput.hasClass("notEdited") || !titleInput.val()) {
titleInput.val(fileName);
}
titleInput.removeClass("notEdited"); // allow editing on this element.
});
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
params = paramString.parseParams(null, null, true);
macro.createUploadForm(place, tiddler, params[0]);
},
iFrameLoader: function(iframeName, fileName, place, workspace, tiddler, baseurl, callback) {
var iframe = document.getElementById(iframeName); //jQuery doesn't seem to want to do this!?
var locale = macro.locale;
$(".userInput").addClass("notEdited"); // reset editing
var finishedLoading = function() {
displayMessage(locale.loadSuccess.format([fileName]));
var url = "%0/%1".format([baseurl, fileName]);
$.getJSON(url, function(file) {
macro.displayFile(place, fileName, workspace, tiddler);
$(iframe).remove();
refreshDisplay();
callback(url);
});
};
var iFrameLoadHandler = function() {
finishedLoading.apply();
return;
};
iframe.onload = iFrameLoadHandler;
//IE
completeReadyStateChanges = 0;
iframe.onreadystatechange = function() {
if (++(completeReadyStateChanges) == 3) {
iFrameLoadHandler();
}
};
},
displayFile: function(place, title, workspace, tiddler) {
var adaptor = tiddler.getAdaptor();
var context = {
workspace: workspace
};
adaptor.getTiddler(title, context, null, function(context) {
if(context.status) {
store.addTiddler(context.tiddler);
story.displayTiddler(place, title);
} else {
displayMessage(locale.loadError.format([title]));
}
});
}
};
config.macros.binaryUploadPublic = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
params = paramString.parseParams(null, null, true);
var options = params[0];
options.bag = "%0_public".
format([config.extensions.tiddlyspace.currentSpace.name]);
macro.createUploadForm(place, tiddler, options);
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceChangePassword|
|''Version''|0.2.0|
|''Author''|Osmosoft|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceChangePassword.js|
|''Requires''|TiddlyWebConfig TiddlySpaceUserControls|
!HTMLForm
<form action="#">
<fieldset>
<legend />
<dl>
<dt>Current password:</dt>
<dd>
<input type="password" name="password" />
</dd>
<dd>
<dt>New password:</dt>
<input type="password" name="new_password" />
<dt>Confirm new password:</dt>
<input type="password" name="new_password_confirm" />
</dd>
</dl>
<p class="annotation" />
<input type="submit" />
</fieldset>
</form>
!Code
***/
//{{{
(function($) {
var tweb = config.extensions.tiddlyweb;
var displayError = config.macros.TiddlySpaceLogin.displayError;
var macro = config.macros.TiddlySpaceChangePassword = {
locale: {
label: "Change password",
cpwSuccess: "Password changed",
noPasswordError: "Please enter password",
passwordMatchError: "Error: passwords do not match",
passwordShortError: "Error: password must be at least %0 characters",
passwordAuthError: "Error: old password is incorrect",
passwordMinLength: 6
},
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
$(macro.formTemplate).submit(macro.onSubmit).
find("legend").text(macro.locale.label).end().
find(".annotation").hide().end().
find("[type=submit]").val(macro.locale.label).end().
appendTo(place);
},
onSubmit: function(ev) {
var msg = macro.locale;
var form = $(this).closest("form");
form.find(".annotation").hide();
var password = form.find("[name=password]").val();
var npassword = form.find("[name=new_password]").val();
var npasswordConfirm = form.find("[name=new_password_confirm]").val();
var xhr, ctx;
if(npassword != npasswordConfirm) {
xhr = { status: 409 }; // XXX: hacky
ctx = {
msg: {
409: msg.passwordMatchError
},
form: form,
selector: "[name=new_password], [name=new_password_confirm]"
};
displayError(xhr, null, null, ctx);
} else if(npassword.length < msg.passwordMinLength) {
xhr = { status: 409 }; // XXX: hacky
ctx = {
msg: {
409: msg.passwordShortError.format([msg.passwordMinLength])
},
form: form,
selector: "[name=new_password]"
};
displayError(xhr, null, null, ctx);
} else {
macro.changePassword(tweb.username, password, npassword);
}
return false;
},
changePassword: function(username, password, npassword, form) {
var pwCallback = function(resource, status, xhr) {
displayMessage(macro.locale.cpwSuccess);
};
var pwErrback = function(xhr, error, exc) {
var ctx = {
msg: {
400: macro.locale.passwordAuthError
},
form: form,
selector: "[name=password]"
};
displayError(xhr, null, null, ctx);
};
var user = new tiddlyweb.User(username, password, tweb.host);
user.setPassword(npassword, pwCallback, pwErrback);
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceSpaces|
|''Version''|0.5.1|
|''Description''|TiddlySpace spaces management|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceSpaces.js|
|''Requires''|TiddlyWebConfig TiddlySpaceInclusion TiddlySpaceUserControls|
!HTMLForm
<form action="#">
<fieldset>
<legend />
<dl>
<dt>Name:</dt>
<dd><input type="text" name="space" /></dd>
</dl>
<p>
<input type="checkbox" name="subscribe" />
Include the current space in the new space.
</p>
<p class="annotation" />
<input type="submit" />
</fieldset>
</form>
!Code
***/
//{{{
(function($) {
var host = config.extensions.tiddlyweb.host;
var macro = config.macros.TiddlySpaceSpaces = { // TODO: rename
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
locale: {
listError: "error listing spaces: %0",
addLabel: "Create space",
addSuccess: "created space %0",
conflictError: "space <em>%0</em> already exists",
charError: "error: invalid space name - must only contain lowercase " +
"letters, digits or hyphens",
noSpaces: "you have no spaces"
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var container = $("<div />").appendTo(place);
var mode = params[0] || "list";
if(mode == "add") {
container.append(this.generateForm());
} else {
this.refresh(container);
}
},
refresh: function(container) {
container.empty().append("<ul />");
$.ajax({ // XXX: DRY; cf. TiddlySpaceInclusion
url: host + "/spaces?mine=1",
type: "GET",
success: function(data, status, xhr) {
var spaces = $.map(data, function(item, i) {
var link = $("<a />", {
href: item.uri,
text: item.name
});
return $("<li />").append(link)[0];
});
var el = $("ul", container);
if(data.length > 0) {
el.append(spaces);
} else { // XXX: should never occur!?
$('<p class="annotation" />').text(macro.locale.noSpaces).
replaceAll(el);
}
},
error: function(xhr, error, exc) {
displayMessage(macro.locale.listError.format([error]));
}
});
},
generateForm: function() {
return $(this.formTemplate).submit(this.onSubmit).
find("legend").text(this.locale.addLabel).end().
find(".annotation").hide().end().
find("[type=submit]").val(this.locale.addLabel).end();
},
onSubmit: function(ev) {
var form = $(this).closest("form");
var container = form.closest("div");
var space = form.find("[name=space]").val();
var subscribe = form.find("[name=subscribe]").attr("checked");
space = new tiddlyweb.Space(space, host);
var displayError = config.macros.TiddlySpaceLogin.displayError;
var ns = config.extensions.tiddlyspace;
var callback = function(resource, status, xhr) {
if(subscribe) {
config.macros.TiddlySpaceInclusion.inclusion(
ns.currentSpace.name, space.name);
}
var link = $('<a href="javascript:;" />').text(space.name); // TODO: calculate URL
var el = $("ul", container);
$("<li />").append(link).hide().appendTo(el).
slideDown(function() {
$(this).css("display", ""); // required to neutralize animation remnants
macro.refresh(container); // XXX: hack to add URL (see above)
});
};
var errback = function(xhr, error, exc) { // TODO: DRY (cf. TiddlySpaceLogin)
var ctx = {
msg: { 409: macro.locale.conflictError.format([space.name]) },
form: form,
selector: "[name=space]"
};
displayError(xhr, error, exc, ctx);
};
if(ns.isValidSpaceName(space.name)) {
space.create(callback, errback);
} else {
xhr = { status: 409 }; // XXX: hacky
var ctx = {
msg: { 409: macro.locale.charError },
form: form,
selector: "[name=space]"
};
displayError(xhr, null, null, ctx);
}
return false;
}
};
})(jQuery);
//}}}
<!--{{{-->
<div macro='slideRevision'></div>
<div class='toolbar' macro='toolbar [[ToolbarCommands::RevisionToolbar]] icons:yes more:popup'></div>
<div class="followPlaceHolder" macro="followTiddlers"></div>
<div class='heading'>
<div class='spaceSiteIcon' macro='tiddlerOrigin label:yes height:48 width:48'></div>
<div class='modifierIcon'
macro="view modifier SiteIcon label:yes height:48 width:48 labelPrefix:'modified by '">
</div>
<div class='title' macro='view title'></div>
<div class='tagClear'></div>
</div>
<div class='tagClear'></div>
<div class='concertina' ></div>
<div class='content'>
<div class='info'>
<div class='calendar'>
<div class='month' macro='view modified date mmm'></div>
<div class='date' macro='view modified date 0DD'></div>
<div class='time' macro='view modified date 0hh:0mm'></div>
</div>
<div class='tagClear'></div>
<div class='tagged' macro='tags'></div>
</div>
<div class='viewer' macro='view text wikified'></div>
</div>
<div class='tagClear'></div>
<div class='tagging' macro='tagging'></div>
<div class='tagClear'></div>
<!--}}}-->
<<TiddlySpaceSpaces add>>
You are currently a member of the following spaces.
{{inlineList{
<<TiddlySpaceSpaces list>>
}}}
{{backstageClear{}}}
<<tabs txtSpaceTab
members Members BackstageSpaceMembers
includes "include spaces" BackstageSpaceInclusions
tiddlers "tiddlers control panel" BackstageTiddlers
plugins "Manage installed plugins" PluginManager
options "TiddlyWiki options" BackstageOptions
tweaks "Tweak the appearance and behaviour of TiddlyWiki" AdvancedOptions
"import" "Import tiddlers from a TiddlyWiki" BackstageFileImport
>>
Welcome to TiddlySpace.
!Log In
<<TiddlySpaceLogin>>
!Sign Up
<<TiddlySpaceRegister>>
/***
|''Name''|TiddlySpacePublishingCommands|
|''Version''|0.7.1|
|''Status''|@@beta@@|
|''Description''|toolbar commands for drafting and publishing|
|''Author''|Jon Robson|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpacePublishingCommands.js|
|''Requires''|TiddlySpaceConfig|
!Code
***/
//{{{
(function($) {
var tiddlyspace = config.extensions.tiddlyspace;
var cmd = config.commands.publishTiddler = {
text: "publish",
tooltip: "Change the public/private state of this tiddler",
errorMsg: "Error publishing %0: %1",
isEnabled: function(tiddler) {
if(readOnly || !store.tiddlerExists(tiddler.title)) {
return false;
}
var space = tiddlyspace.determineSpace(tiddler, true);
return space && space.name == tiddlyspace.currentSpace.name &&
space.type == "private";
},
handler: function(ev, src, title) {
var tiddler = store.getTiddler(title);
if(tiddler) {
var newBag = cmd.toggleBag(tiddler.fields["server.bag"]);
this.moveTiddler(tiddler, {
title: tiddler.title,
fields: { "server.bag": newBag }
});
}
},
toggleBag: function(bag, to) {
var newBag;
if(typeof bag != typeof "") {
var tiddler = bag;
bag = tiddler.fields["server.bag"];
}
if(bag.indexOf("_private") > -1) { // should make use of endsWith
to = to ? to : "public";
newBag = bag.replace("_private", "_" + to);
} else {
to = to ? to : "private";
newBag = bag.replace("_public", "_" + to);
}
return newBag;
},
toggleWorkspace: function(workspace, to) {
if(typeof workspace != typeof "") {
var tiddler = workspace;
var bag = tiddler.fields["server.bag"];
workspace = bag ? "bags/%0".format([bag]) : tiddler.fields["server.workspace"];
}
var newWorkspace;
if(workspace.indexOf("_private") > -1) { // should make use of endsWith
to = to ? to : "public";
newWorkspace = workspace.replace("_private", "_" + to);
} else {
to = to ? to : "private";
newWorkspace = workspace.replace("_public", "_" + to);
}
return newWorkspace;
},
copyTiddler: function(title, newBag, callback) {
var original = store.getTiddler(title);
var adaptor = original.getAdaptor();
var publish = function(original, callback) {
var tiddler = $.extend(new Tiddler(original.title), original);
tiddler.fields = $.extend({}, original.fields, {
"server.bag": newBag,
"server.workspace": "bags/%0".format([newBag]),
"server.page.revision": "false"
});
adaptor.putTiddler(tiddler, null, null, callback);
};
publish(original, callback);
},
moveTiddler: function(tiddler, newTiddler, withRevisions, callback) {
if(withRevisions) {
this.moveTiddlerWithRevisions(tiddler, newTiddler, callback);
} else {
var info = {
copyContext: {},
deleteContext: {}
};
var _dirty = store.isDirty();
var adaptor = tiddler.getAdaptor();
var newTitle = newTiddler.title;
var oldTitle = tiddler.title;
delete tiddler.fields["server.workspace"];
var oldBag = tiddler.fields["server.bag"];
var newBag = newTiddler.fields["server.bag"];
var newWorkspace = "bags/%0".format([newBag]);
cmd.copyTiddler(oldTitle, newBag, function(ctx) {
info.copyContext = ctx;
var context = {
tiddler: tiddler,
workspace: newWorkspace
};
tiddler.title = oldTitle; // for cases where a rename occurs
if(ctx.status) { // only do if a success
if(oldBag != newBag) {
adaptor.deleteTiddler(tiddler, context, {}, function(ctx) {
info.deleteContext = ctx;
var el;
if(tiddler) {
tiddler.fields["server.workspace"] = newWorkspace;
tiddler.fields["server.bag"] = newBag;
store.addTiddler(tiddler);
}
if(oldTitle != newTitle) {
store.removeTiddler(oldTitle);
el = story.closeTiddler(oldTitle);
}
el = el ? el : story.refreshTiddler(newTitle, true);
if(el) {
story.displayTiddler(el, newTitle);
}
if(callback) {
callback(info);
}
store.setDirty(_dirty);
});
} else {
if(callback) {
callback(info);
}
story.refreshTiddler(newTitle, true);
}
}
});
}
},
moveTiddlerWithRevisions: function(tiddler, newTiddler, callback) {
var adaptor = tiddler.getAdaptor();
var oldBag = tiddler.fields["server.bag"];
var oldTitle = tiddler.title;
var newTitle = newTiddler.title;
var newBag = newTiddler.fields["server.bag"];
delete tiddler.fields["server.workspace"];
delete newTiddler.fields["server.workspace"];
var oldWorkspace = "bags/%0".format([oldBag]);
var newWorkspace = "bags/%0".format([newBag]);
var info = {};
if(oldBag == newBag) { // we are in a dangerous error state
return callback ? callback(info) : false;
}
// we first must delete any existing public revisions
tiddler.title = newTitle;
tiddler.fields["server.bag"] = newBag;
tiddler.fields["server.workspace"] = newWorkspace;
tiddler.fields["server.page.revision"] = "false"; // force this action
adaptor.deleteTiddler(tiddler, {}, {},
function(ctx) {
info.deleteContext = ctx;
tiddler.fields["server.workspace"] = oldWorkspace;
tiddler.fields["server.bag"] = oldBag; // rectify above change to workspace
adaptor.moveTiddler(
{ title: oldTitle, workspace: oldWorkspace },
{ title: newTitle, workspace: newWorkspace },
{}, {},
function(context) {
info.moveContext = context;
if(context.status) {
var newTiddler = context.tiddler;
newTiddler.fields["server.workspace"] = newWorkspace;
// some some reason the old tiddler is not being removed from the store (hence next 3 lines)
var oldDirty = store.isDirty();
store.removeTiddler(oldTitle);
store.setDirty(oldDirty);
store.addTiddler(newTiddler); // note the tiddler may have changed name
var old = story.refreshTiddler(oldTitle, true);
if(old) {
story.displayTiddler(old, newTitle);
}
}
if(callback) {
callback(info);
}
}
);
});
}
};
config.commands.changeToPrivate = {
text: "make private",
tooltip: "turn this public tiddler into a private tiddler",
handler: function(event, src, title) {
var tiddler = store.getTiddler(title);
var newBag = cmd.toggleBag(tiddler, "private");
var newTiddler = { title: title, fields: { "server.bag": newBag }};
cmd.moveTiddler(tiddler, newTiddler, true);
}
};
config.commands.changeToPublic = {
text: "make public",
tooltip: "turn this private tiddler into a public tiddler",
handler: function(event, src, title) {
var tiddler = store.getTiddler(title);
var newBag = cmd.toggleBag(tiddler, "public");
var newTiddler = { title: title, fields: { "server.workspace": newBag }};
cmd.moveTiddler(tiddler, newTiddler, true);
}
};
config.commands.deleteTiddler.deleteResource = function(tiddler, bag, userCallback) {
var workspace = "bags/%0".format([bag]);
var oldDirty = store.isDirty();
var originalBag = tiddler.fields["server.bag"];
var originalWorkspace = "bags/%0".format([originalBag]);
var deleteLocal = originalWorkspace == workspace;
var context = {
tiddler: tiddler,
workspace: workspace
};
tiddler.fields["server.bag"] = bag;
tiddler.fields["server.workspace"] = context.workspace;
tiddler.fields["server.page.revision"] = "false";
var defaultWorkspace = config.defaultCustomFields["server.workspace"];
delete tiddler.fields["server.etag"];
var callback;
if(deleteLocal) {
var _dirty = store.isDirty();
callback = function(context, userParams) {
var title = tiddler.title;
store.removeTiddler(title);
context.adaptor.getTiddler(title, { workspace: defaultWorkspace }, null, function(context) {
if(context.status) {
store.addTiddler(context.tiddler);
story.refreshTiddler(title, null, true);
userCallback(context);
}
store.setDirty(_dirty);
});
};
} else {
callback = function(context, userParams) {
if(context.status) {
tiddler.fields["server.workspace"] = originalWorkspace;
tiddler.fields["server.bag"] = originalBag;
story.refreshTiddler(tiddler.title, null, true);
store.setDirty(oldDirty); // will fail to delete locally and throw an error
}
if(userCallback) {
userCallback(context);
}
};
}
tiddler.getAdaptor().deleteTiddler(tiddler, context, {}, callback);
};
config.commands.deletePublicTiddler = {
text: "delete public",
tooltip: "Delete any public versions of this tiddler",
isEnabled: function(tiddler) {
return tiddler.fields["server.workspace"];
},
handler: function(event, src, title) {
var tiddler = store.getTiddler(title);
var bag = cmd.toggleBag(tiddler, "public");
config.commands.deleteTiddler.deleteResource(tiddler, bag);
}
};
config.commands.deletePrivateTiddler = {
text: "delete private",
tooltip: "delete any private versions of this tiddler",
handler: function(event, src, title) {
var tiddler = store.getTiddler(title);
var bag = cmd.toggleBag(tiddler, "private");
config.commands.deleteTiddler.deleteResource(tiddler, bag);
}
};
/* Save as draft command */
config.commands.saveDraft = {
text: "save draft",
tooltip: "Save as a private draft",
isEnabled: function(tiddler) {
if(tiddler) {
var workspace = tiddler.fields["server.workspace"];
if(workspace && workspace.indexOf("_public") > -1) {
return true;
} else {
return false;
}
} else {
return false;
}
},
handler: function(ev, src, title) {
// TODO: when creating a draft also copy over revisions from the public version
var tiddler = store.getTiddler(title); // original tiddler
var tidEl = story.getTiddler(title);
var fields = {};
story.gatherSaveFields(tidEl, fields);
var extendedFields = merge({}, config.defaultCustomFields);
var currentSpace = tiddlyspace.currentSpace.name;
var privateWorkspace = "recipes/%0_private".format([currentSpace]);
var draftTitle;
var draftNum = "";
while(!draftTitle) {
var suggestedTitle = "%0 [draft%1]".format([title, draftNum]);
if(store.getTiddler(suggestedTitle)) {
draftNum = !draftNum ? 2 : draftNum + 1;
} else {
draftTitle = suggestedTitle;
}
}
extendedFields["server.publish.name"] = title;
extendedFields["server.workspace"] = privateWorkspace;
var newDate = new Date();
for(var n in fields) {
if(!TiddlyWiki.isStandardField(n)) {
extendedFields[n] = fields[n];
}
}
tiddler = store.saveTiddler(draftTitle, draftTitle, fields.text, config.options.txtUserName,
newDate, fields.tags, extendedFields);
autoSaveChanges(null, [tiddler]);
story.closeTiddler(title);
story.displayTiddler(src, draftTitle);
return draftTitle;
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceBackstage|
|''Version''|0.5.4|
|''Description''|Provides a TiddlySpace version of the backstage|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceBackstage.js|
|''Requires''|TiddlySpaceConfig ImageMacroPlugin|
!Code
***/
//{{{
(function($) {
var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;
var imageMacro = config.macros.image;
if(config.options.chkBackstage === undefined) {
config.options.chkBackstage = true;
}
config.backstageTasks = [];
config.tasks.login = {
text: "login",
tooltip: "TiddlySpace login",
content: "<<tiddler BackstageLogin>>"
};
config.backstageTasks.push("login");
config.tasks.user = {
text: "user: ",
tooltip: "user control panel",
content: "<<tiddler BackstageUser>>"
};
config.backstageTasks.push("user");
config.tasks.space = {
text: "space: ",
tooltip: "space control panel",
content: "<<tiddler BackstageSpace>>",
className: "right"
};
config.backstageTasks.push("space");
config.messages.backstage.prompt = "";
// initialize state
var _show = backstage.show;
backstage.show = function() {
// selectively hide backstage tasks based on user status
var tasks = $("#backstageToolbar .backstageTask").show();
tweb.getUserInfo(function(user) {
if(user.anon) {
tasks.slice(1, 2).hide();
} else {
tasks.eq(0).hide();
}
});
// display backstage
return _show.apply(this, arguments);
};
var _init = backstage.init;
backstage.init = function(){
_init.apply(this, arguments);
var backstageArea = $("#backstageArea");
// override user button (logged in) to show username
var userBtn = $(".backstageTask[task=user]").
html('<span>%0<span class="txtUserName" /></span>'.format([
config.tasks.user.text]));
config.macros.option.handler($(".txtUserName", userBtn)[0], null, ["txtUserName"]);
// override show button with an svg image
var showBtn = $("#backstageShow")[0];
var altText = $(showBtn).text();
$(showBtn).empty();
imageMacro.renderImage(showBtn, "backstage.svg",
{ alt: altText, width: 60, height: 60 });
// override hide button
var hideBtn = $("#backstageHide")[0];
altText = $(hideBtn).text();
$(hideBtn).empty();
imageMacro.renderImage(hideBtn, "close.svg",
{ alt: altText, width: 24, height: 24 });
var backstageToolbar = $("#backstageToolbar")[0];
var backstageLogo = $('<div id="backstageLogo" />').
prependTo(backstageToolbar)[0];
var iconName = readOnly ? "publicIcon" : "privateAndPublicIcon";
imageMacro.renderImage(backstageLogo, iconName, { width: 24, height: 24 });
// construct the tiddlyspace logo
$('<span class="logoText"><span class="privateLightText">tiddly</span>' +
'<span class="publicLightText">space</span></span>').
appendTo(backstageLogo);
// override space button to show SiteIcon
var siteIcon = store.getTiddler("SiteIcon");
if(siteIcon) {
var spaceName = tiddlyspace.currentSpace.name;
var btn = $("[task=space]", backstageArea);
btn.empty();
var uri = "/bags/%0_public/tiddlers/SiteIcon".format([spaceName]);
imageMacro.renderImage(btn[0], uri,
{ imageClass:"spaceSiteIcon", height: 24, width: 24 });
$("<span />").html(config.tasks.space.text).appendTo(btn);
$('<span class="spaceName" />').text(spaceName).appendTo(btn);
}
tweb.getUserInfo(function(user) {
if(!user.anon) {
var src = tiddlyspace.getAvatar(tweb.status.server_host, user.name);
var container = $("<span />").appendTo("[task=user]", backstageArea)[0];
imageMacro.renderImage(container, src,
{ imageClass:"userSiteIcon", height: 24, width: 24 });
}
// override login button to show default avatar
var loginBtn = $("[task=login]", backstageArea);
loginBtn.html("<span>%0</span>".format([config.tasks.login.text]));
imageMacro.renderImage(loginBtn[0], "/bags/common/tiddlers/defaultUserIcon",
{ imageClass:"userSiteIcon", height: 24, width: 24 });
var tasks = $(".backstageTask");
for(var i = 0; i < tasks.length; i++) {
var btn = $(tasks[i]);
var taskName = btn.attr("task");
btn.addClass("task_%0".format([taskName]));
}
});
};
})(jQuery);
//}}}
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='viewer' macro='view text wikified'></div>
<!--}}}-->
/***
|''Name''|RevisionsCommandPlugin|
|''Description''|provides access to tiddler revisions|
|''Author''|FND|
|''Contributors''|Martin Budden|
|''Version''|0.3.2|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/RevisionsCommandPlugin.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/association/plugins/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Keywords''|serverSide|
!Usage
Extend [[ToolbarCommands]] with {{{revisions}}}.
!Revision History
!!v0.1 (2009-07-23)
* initial release (renamed from experimental ServerCommandsPlugin)
!!v0.2 (2010-03-04)
* suppressed wikification in diff view
!!v0.3 (2010-04-07)
* restored wikification in diff view
* added link to side-by-side diff view
!To Do
* strip server.* fields from revision tiddlers
* resolve naming conflicts
* i18n, l10n
* code sanitizing
* documentation
!Code
***/
//{{{
(function($) {
jQuery.twStylesheet(".diff { white-space: pre, font-family: monospace }",
{ id: "diff" });
var cmd = config.commands.revisions = {
type: "popup",
hideShadow: true,
text: "revisions",
tooltip: "display tiddler revisions",
revTooltip: "", // TODO: populate dynamically?
loadLabel: "loading...",
loadTooltip: "loading revision list",
selectLabel: "select",
selectTooltip: "select revision for comparison",
selectedLabel: "selected",
compareLabel: "compare",
linkLabel: "side-by-side view",
revSuffix: " [rev. #%0]",
diffSuffix: " [diff: #%0 #%1]",
dateFormat: "YYYY-0MM-0DD 0hh:0mm",
listError: "revisions could not be retrieved",
handlePopup: function(popup, title) {
stripSuffix = function(type, title) {
var str = cmd[type + "Suffix"];
var i = str.indexOf("%0");
i = title.indexOf(str.substr(0, i));
if(i != -1) {
title = title.substr(0, i);
}
return title;
};
title = stripSuffix("rev", title);
title = stripSuffix("diff", title);
var tiddler = store.getTiddler(title);
var type = this._getField("server.type", tiddler);
var adaptor = new config.adaptors[type]();
var limit = null; // TODO: customizable
var context = {
host: this._getField("server.host", tiddler),
workspace: this._getField("server.workspace", tiddler)
};
var loading = createTiddlyButton(popup, cmd.loadLabel, cmd.loadTooltip);
var params = { popup: popup, loading: loading, origin: title };
adaptor.getTiddlerRevisionList(title, limit, context, params, this.displayRevisions);
},
displayRevisions: function(context, userParams) {
removeNode(userParams.loading);
if(context.status) {
var callback = function(ev) {
var e = ev || window.event;
var revision = resolveTarget(e).getAttribute("revision");
context.adaptor.getTiddlerRevision(tiddler.title, revision, context,
userParams, cmd.displayTiddlerRevision);
};
var table = createTiddlyElement(userParams.popup, "table");
for(var i = 0; i < context.revisions.length; i++) {
var tiddler = context.revisions[i];
var row = createTiddlyElement(table, "tr");
var timestamp = tiddler.modified.formatString(cmd.dateFormat);
var revision = tiddler.fields["server.page.revision"];
var cell = createTiddlyElement(row, "td");
createTiddlyButton(cell, timestamp, cmd.revTooltip, callback, null,
null, null, { revision: revision });
cell = createTiddlyElement(row, "td", null, null, tiddler.modifier);
cell = createTiddlyElement(row, "td");
createTiddlyButton(cell, cmd.selectLabel, cmd.selectTooltip,
cmd.revisionSelected, null, null, null,
{ index:i, revision: revision, col: 2 });
cmd.context = context; // XXX: unsafe (singleton)!?
}
} else {
$("<li />").text(cmd.listError).appendTo(userParams.popup);
}
},
revisionSelected: function(ev) {
var e = ev || window.event;
e.cancelBubble = true;
if(e.stopPropagation) {
e.stopPropagation();
}
var n = resolveTarget(e);
var index = n.getAttribute("index");
var col = n.getAttribute("col");
while(!index || !col) {
n = n.parentNode;
index = n.getAttribute("index");
col = n.getAttribute("col");
}
cmd.revision = n.getAttribute("revision");
var table = n.parentNode.parentNode.parentNode;
var rows = table.childNodes;
for(var i = 0; i < rows.length; i++) {
var c = rows[i].childNodes[col].firstChild;
if(i == index) {
if(c.textContent) {
c.textContent = cmd.selectedLabel;
} else {
c.text = cmd.selectedLabel;
}
} else {
if(c.textContent) {
c.textContent = cmd.compareLabel;
} else {
c.text = cmd.compareLabel;
}
c.onclick = cmd.compareSelected;
}
}
},
compareSelected: function(ev) {
var e = ev || window.event;
var n = resolveTarget(e);
var context = cmd.context;
context.rev1 = n.getAttribute("revision");
context.rev2 = cmd.revision;
context.tiddler = context.revisions[n.getAttribute("index")];
context.format = "unified";
context.adaptor.getTiddlerDiff(context.tiddler.title, context,
context.userParams, cmd.displayTiddlerDiffs);
},
displayTiddlerDiffs: function(context, userParams) {
var tiddler = context.tiddler;
tiddler.title += cmd.diffSuffix.format([context.rev1, context.rev2]);
tiddler.text = "{{diff{\n" + context.diff + "\n}}}";
tiddler.tags = ["diff"];
tiddler.fields.doNotSave = "true"; // XXX: correct?
if(!store.getTiddler(tiddler.title)) {
store.addTiddler(tiddler);
}
var src = story.getTiddler(userParams.origin);
var tiddlerEl = story.displayTiddler(src, tiddler);
var uri = context.uri.replace("format=unified", "format=horizontal");
var link = $('<a target="_blank" />').attr("href", uri).text(cmd.linkLabel);
$(".viewer", tiddlerEl).prepend(link);
},
displayTiddlerRevision: function(context, userParams) {
var tiddler = context.tiddler;
tiddler.title += cmd.revSuffix.format([tiddler.fields["server.page.revision"]]);
tiddler.fields.doNotSave = "true"; // XXX: correct?
if(!store.getTiddler(tiddler.title)) {
store.addTiddler(tiddler);
}
var src = story.getTiddler(userParams.origin);
story.displayTiddler(src, tiddler);
},
_getField: function(name, tiddler) {
return tiddler.fields[name] || config.defaultCustomFields[name];
}
};
})(jQuery);
//}}}
{{annotation{
TiddlySpace is a new [[open source service|Open Source Service]] that lets you publish and share your thoughts. It is being developed by a community of independent developers, supported by [[Osmosoft|http://osmosoft.com]], [[BT|http://www.bt.com]]'s open source innovation unit. It is still in the early stages of development and so should be used in a spirit of experimentation. It works best with the latest versions of Safari, Chrome and Firefox.
}}}
/***
|''Name''|TiddlySpaceInclusion|
|''Version''|0.5.1|
|''Description''|provides user interfaces for managing TiddlySpace inclusions|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceInclusion.js|
|''Requires''|TiddlySpaceConfig TiddlySpaceUserControls chrjs|
!HTMLForm
<form action="#">
<fieldset>
<legend />
<p class="description" />
<dl>
<dt class="_passive">Space Name:</dt>
<dd class="_passive"><input type="text" name="space" /></dd>
<dt class="_active">Space Selection:</dt>
<dd class="_active">
<select>
<option></option>
</select>
</dd>
</dl>
<p class="annotation" />
<input type="submit" />
</fieldset>
</form>
!Code
***/
//{{{
(function($) {
var tweb = config.extensions.tiddlyweb;
var currentSpace = config.extensions.tiddlyspace.currentSpace.name;
var macro = config.macros.TiddlySpaceInclusion = {
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
locale: {
addPassiveLabel: "Include space",
addActiveLabel: "Include into space",
passiveDesc: "Include a space into the current space",
activeDesc: "Include another space in the current space",
addSuccess: "included %0 in %1",
delPrompt: "Are you sure you want to exclude %0 from the current space?",
delTooltip: "click to exclude from the space",
delError: "error excluding %0: %1",
listError: "error retrieving spaces included in space %0: %1",
forbiddenError: "unauthorized to modify space <em>%0</em>",
noSpaceError: "space <em>%0</em> does not exist",
conflictError: "space <em>%0</em> is already included in <em>%1</em>",
noInclusions: "no spaces are included",
recursiveInclusions: "Spaces included by the removed space are highlighted and should be removed manually.",
reloadPrompt: "The page must be reloaded for inclusion to take effect. Reload now?"
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
// passive mode means subscribing given space to current space
// active mode means subscribing current space to given space
this.name = macroName;
var mode = params[0] || "list";
var form = $(this.formTemplate).
find(".annotation").hide().end();
if(mode == "passive") {
if(!readOnly) {
form.submit(function(ev) { return macro.onSubmit(this, mode); }).
find("._active").remove().end().
find("legend").text(this.locale.addPassiveLabel).end().
find(".description").text(this.locale.passiveDesc).end().
find("[type=submit]").val(this.locale.addPassiveLabel).end().
appendTo(place);
}
} else if(mode == "active") {
form.submit(function(ev) { return macro.onSubmit(this, mode); }).
find("._passive").remove().end().
find("legend").text(this.locale.addActiveLabel).end().
find(".description").text(this.locale.activeDesc).end().
find("[type=submit]").val(this.locale.addActiveLabel).end().
appendTo(place);
this.populateSpaces(form);
} else {
var container = $("<div />").addClass(this.name).appendTo(place);
$('<p class="annotation" />').hide().appendTo(container);
this.listInclusions(container);
}
},
listInclusions: function(container) {
var recipe = new tiddlyweb.Recipe(currentSpace + "_public", tweb.host);
recipe.get(function(recipe, status, xhr) {
var inclusions = $.map(recipe.recipe, function(item, i) { // TODO: refactor to canonicalize; move to TiddlySpaceConfig!?
var arr = item[0].split("_public");
return (arr[0] != currentSpace && arr[1] === "") ? arr[0] : null;
});
var items = $.map(inclusions, function(item, i) { // TODO: DRY (cf. displayMembers)
var link = $("<a />").text(item);
tweb.getStatus(function(status) {
var uri = config.extensions.tiddlyspace.getHost(
status.server_host, item);
link.attr("href", uri);
});
var btn = $('<a class="deleteButton" href="javascript:;" />').
text("x"). // TODO: i18n (use icon!?)
attr("title", macro.locale.delTooltip).
data("space", item).click(macro.onDelClick);
if(readOnly) {
btn.hide();
}
return $("<li />").append(link).append(btn)[0];
});
if(items.length) {
$("<ul />").append(items).appendTo(container);
} else {
$('<div class="annotation" />').
text(macro.locale.noInclusions).appendTo(container);
}
}, function(xhr, error, exc) {
displayMessage(macro.locale.listError.format([currentSpace, error]));
});
},
populateSpaces: function(form) { // TODO: rename?
$.ajax({ // TODO: add to model/space.js?
url: tweb.host + "/spaces?mine=1",
type: "GET",
success: function(data, status, xhr) {
var spaces = $.map(data, function(item, i) {
return $("<option />", { value: item.name }).text(item.name)[0];
});
$("select", form).append(spaces);
} // TODO: error handling?
});
},
onSubmit: function(el, mode) {
var form = $(el).closest("form");
var selector = mode == "passive" ? "[name=space]" : "select";
var space = form.find(selector).val();
var provider = mode == "passive" ? space : currentSpace;
var subscriber = mode == "passive" ? currentSpace : space;
var loc = macro.locale;
var callback = function(data, status, xhr) {
displayMessage(loc.addSuccess.format([provider, subscriber]));
if(confirm(loc.reloadPrompt)) {
window.location.reload();
}
};
var errback = function(xhr, error, exc) {
if(xhr.status == 409) {
var included = "already subscribed";
xhr = { // XXX: hacky
status: xhr.responseText.indexOf(included) != -1 ? "409a" : "409b"
};
}
var ctx = {
msg: {
403: loc.forbiddenError.format([subscriber]),
404: loc.noSpaceError.format([subscriber]), // XXX: only relevant for passive mode
"409a": loc.conflictError.format([provider, subscriber]),
"409b": loc.noSpaceError.format([provider])
},
form: form,
selector: selector
};
config.macros.TiddlySpaceLogin.displayError(xhr, error, exc, ctx);
};
this.inclusion(provider, subscriber, callback, errback, false);
return false;
},
onDelClick: function(ev) { // XXX: too long, needs refactoring
var btn = $(this);
var provider = btn.data("space");
var msg = macro.locale.delPrompt.format([provider]);
var callback = function(data, status, xhr) {
btn.closest("li").slideUp(function(ev) { $(this).remove(); });
};
var errback = function(xhr, error, exc) { // XXX: doesn't actually happen
displayMessage(macro.locale.delError.format([username, error]));
};
if(confirm(msg)) {
var recipe = new tiddlyweb.Recipe(provider + "_public", tweb.host);
recipe.get(function(recipe, status, xhr) {
var inclusions = $.map(recipe.recipe, function(item, i) { // XXX: duplicated from above
var arr = item[0].split("_public");
return (arr[0] != provider && arr[1] === "") ? arr[0] : null;
});
var recursiveMatch = false;
btn.closest("ul").find("li").each(function(i, node) {
var space = $(".deleteButton", node).data("space"); // XXX: relying on button is hacky
if($.inArray(space, inclusions) != -1) {
recursiveMatch = true;
$(node).addClass("annotation"); // TODO: proper highlighting
}
});
if(recursiveMatch) {
btn.closest("." + macro.name).find("> .annotation").
text(macro.locale.recursiveInclusions).slideDown();
}
});
macro.inclusion(provider, currentSpace, callback, errback, true);
}
return false;
},
inclusion: function(provider, subscriber, callback, errback, remove) {
var data = {};
var key = remove ? "unsubscriptions" : "subscriptions";
data[key] = [provider];
$.ajax({ // TODO: add to model/space.js?
url: tweb.host + "/spaces/" + subscriber,
type: "POST",
contentType: "application/json",
data: $.toJSON(data),
success: callback,
error: errback
});
}
};
})(jQuery);
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1"
viewBox="416 13 34 34" width="34pt" height="34pt">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 418.78613 28.08259 C 420.0481 20.113405 427.54074 14.6697865 435.51 15.931775
C 443.4801 17.193707 448.9237 24.686371 447.6617 32.656437 C 446.3989 40.62574 438.90625
46.069302 430.93698 44.807312 C 422.96774 43.545353 417.52328 36.0519 418.78613 28.08259 Z"
fill="#c1e6fd"/><path d="M 418.78613 28.08259 C 420.0481 20.113405 427.54074 14.6697865 435.51 15.931775 C
443.4801 17.193707 448.9237 24.686371 447.6617 32.656437 C
446.3989 40.62574 438.90625 46.069302 430.93698 44.807312 C 422.96774 43.545353 417.52328 36.0519 418.78613
28.08259 Z" stroke="#7aa3be" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/>
<path d="M 433.17715 35.897835 C 429.89737 35.897835 427.23505 33.2355 427.23505 29.955704
C 427.23505 26.675049 429.89737 24.013567 433.17715 24.013567 C 436.45694 24.013567 439.11926 26.675049 439.11926
29.955704 C 439.11926 33.2355 436.45694 35.897835 433.17715 35.897835 Z" fill="#f4c4e2"/>
<path d="M 433.17715 35.897835 C 429.89737 35.897835 427.23505 33.2355 427.23505 29.955704
C 427.23505 26.675049 429.89737 24.013567 433.17715 24.013567 C 436.45694 24.013567 439.11926 26.675049 439.11926
29.955704 C 439.11926 33.2355 436.45694 35.897835 433.17715 35.897835 Z" stroke="#ce81b0"
stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/>
</g>
</g>
</svg>
/***
|''Name''|BinaryTiddlersPlugin|
|''Description''|renders base64-encoded binary tiddlers as images or links|
|''Author''|FND|
|''Version''|0.3.0|
|''Status''|@@beta@@|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/BinaryTiddlersPlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5|
!Code
***/
//{{{
(function($) {
var ctfield = "server.content-type";
var plugin = config.extensions.BinaryTiddlersPlugin = {
isWikiText: function(tiddler) {
var ctype = tiddler.fields[ctfield];
if(ctype) {
return !this.isBinary(tiddler) && !this.isTextual(ctype);
} else {
return true;
}
},
// NB: pseudo-binaries are considered non-binary here
isBinary: function(tiddler) {
var ctype = tiddler.fields[ctfield];
return ctype ? !this.isTextual(ctype) : false;
},
isTextual: function(ctype) {
return ctype.indexOf("text/") == 0 || this.endsWith(ctype, "+xml");
},
endsWith: function(str, suffix) {
return str.length >= suffix.length &&
str.substr(str.length - suffix.length) == suffix;
}
};
// hijack text viewer to add special handling for binary tiddlers
var _view = config.macros.view.views.wikified;
config.macros.view.views.wikified = function(value, place, params, wikifier,
paramString, tiddler) {
var ctype = tiddler.fields["server.content-type"];
if(params[0] == "text" && ctype && !tiddler.tags.contains("systemConfig")) {
var el;
if(plugin.isBinary(tiddler)) {
var uri = "data:%0;base64,%1".format([ctype, tiddler.text]); // TODO: fallback for legacy browsers
if(ctype.indexOf("image/") == 0) {
el = $("<img />").attr("alt", tiddler.title).attr("src", uri);
} else {
el = $("<a />").attr("href", uri).text(tiddler.title);
}
} else {
el = $("<pre />").text(tiddler.text);
}
el.appendTo(place);
} else {
_view.apply(this, arguments);
}
};
// hijack edit macro to disable editing of binary tiddlers' body
var _editHandler = config.macros.edit.handler;
config.macros.edit.handler = function(place, macroName, params, wikifier,
paramString, tiddler) {
if(params[0] == "text" && plugin.isBinary(tiddler)) {
return false;
} else {
_editHandler.apply(this, arguments);
}
};
// hijack autoLinkWikiWords to ignore binary tiddlers
var _autoLink = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function() {
return plugin.isWikiText(this) ? _autoLink.apply(this, arguments) : false;
};
})(jQuery);
//}}}
/***
|''Name''|ImageMacroPlugin|
|''Version''|0.7.0|
|''Description''|Allows the rendering of svg images in a TiddlyWiki|
|''Author''|Osmosoft|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Notes''|Currently only works in modern browsers (not IE)|
|''Usage''|{{{<<image SVG>>}}} will render the text of the tiddler with title SVG as an SVG image (but not in ie where it will fail silently)|
!Notes
Binary tiddlers in TiddlyWeb when passed through the wikifier will be shown as images.
eg. {{{<<view text wikified>>}}} on a binary tiddler will show the image.
{{{<<view fieldname image>>}}}
will render the value of the tiddler field 'fieldname' as an image. This field can contain a tid
{{{<<image SiteIcon>>}}}
will create an image tag where the tiddler has content type beginning image and not ending +xml
will attempt to create svg object in other scenarios
{{{<<image /photos/x.jpg>>}}}
will create an image tag with src /photos/x.jpg as long as there is not a tiddler called /photos/x.jpg in
which case it will render that tiddler as an image.
!Code
***/
//{{{
(function($) {
var macro = config.macros.image = {
svgns: "http://www.w3.org/2000/svg",
xlinkns: "http://www.w3.org/1999/xlink",
svgAvailable: document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"),
_fixPrefix: 1,
_external_cache: {},
isBinaryImageType: function(contentType) {
if(contentType && contentType.indexOf("image") === 0 &&
contentType.indexOf("+xml") != contentType.length - 4) {
return true;
} else {
return false;
}
},
isImageTiddler: function(tiddler) {
return macro.isSVGTiddler(tiddler) || macro.isBinaryImageTiddler(tiddler);
},
isSVGTiddler: function(tiddler) {
var type;
type = tiddler ? tiddler.fields['server.content-type'] : false;
return type == "image/svg+xml";
},
isBinaryImageTiddler: function(tiddler) {
return macro.isBinaryImageType(tiddler.fields['server.content-type']);
},
generateIdPrefix: function(){
return "tw_svgfix_" + (this._fixPrefix++).toString() + "_";
},
fixSVG: function(childNodes,idPrefix) {
if(!idPrefix) {
idPrefix = this.generateIdPrefix();
}
var urlPattern = /^\s*url\(\#([^\)]*)\)\s*$/ig;
var fixes = [
{ attr: "id", namespace: "", pattern: /^(.*)$/ig },
{ attr: "filter", namespace: "", pattern: urlPattern },
{ attr: "fill", namespace: "", pattern: urlPattern },
{ attr: "stroke", namespace: "", pattern: urlPattern },
{ attr: "href", namespace: macro.xlinkns, pattern: /^#(.*)$/ig }
];
for(var t = 0; t < childNodes.length; t++) {
var node = childNodes[t];
for(var a = 0; a < fixes.length; a++) {
var fix = fixes[a];
if(node.hasAttributeNS && node.hasAttributeNS(fix.namespace, fix.attr)) {
var v = node.getAttributeNS(fix.namespace, fix.attr);
fix.pattern.lastIndex = 0;
var match = fix.pattern.exec(v);
if(match) {
// Make sure replacement string doesn't contain any single dollar signs
var replacement = (idPrefix + match[1]).replace("$", "$$$$");
v = v.replace(match[1], replacement);
node.setAttributeNS(fix.namespace, fix.attr,v);
}
}
}
var children = node.childNodes;
if(children.length > 0) {
this.fixSVG(children, idPrefix);
}
}
},
importSVGfallback: function(place,options){
// no fallback yet for browsers such as IE
},
importSVG: function(place,options){
if(!options) {
options = {};
}
var tiddlerText = options.tiddler.text;
var svgDoc;
if (window.DOMParser) {
svgDoc = new DOMParser().parseFromString(tiddlerText, "application/xml").documentElement;
var idPrefix = options.idPrefix || this.generateIdPrefix();
this.fixSVG([svgDoc], idPrefix);
var el = document.importNode(svgDoc, true);
var existingDefs = el.getElementsByTagNameNS(macro.svgns, "defs");
var elDef;
if(existingDefs.length === 0) {
elDef = document.createElementNS(macro.svgns, "defs");
} else {
elDef = existingDefs[0];
}
if(options.def) {
for(var i = 0; i < options.def.length; i++) {
var text = store.getTiddlerText(options.def[i]);
var def = new DOMParser().parseFromString(text, "application/xml").documentElement;
this.fixSVG([def], idPrefix);
elDef.appendChild(document.importNode(def, true));
}
}
el.insertBefore(elDef, el.firstChild);
var svgHolder = document.createElementNS(macro.svgns,"svg");
var width = options.width;
var height = options.height;
// what if width and height exist in css?
if(width || height) {
if(width && height) {
// set view box of containing svg element based on the svg viewbox and width and height.
var viewBox = el.getAttribute("viewBox");
var topLeft = "0 0";
if(viewBox) {
topLeft = viewBox.replace(/([0-9]*) +([0-9]*) +([0-9]*) +([0-9]*) */gi,"$1 $2");
}
svgHolder.setAttributeNS(macro.svgns, "viewBox", "0 0 %0 %1".format([width, height]));
} else {
if(!width) {
width = el.getAttribute("width");
}
if(!height) {
height = el.getAttribute("height");
}
}
svgHolder.setAttribute("width", width);
svgHolder.setAttribute("height", height);
el.setAttribute("width", "100%");
el.setAttribute("height", "100%");
svgHolder.setAttribute("class", "svgImage svgIcon %0".format([options.imageClass || ""]));
svgHolder.appendChild(el);
place.appendChild(svgHolder);
}
else {
el.setAttribute("class","svgImage svgIcon");
place.appendChild(el);
}
// if a tiddler attribute is set this is read as a link
jQuery("[tiddler]", place).click(function(ev) {
var tiddler = $(ev.target).attr("tiddler");
if(tiddler) {
story.displayTiddler(ev.target, tiddler);
}
});
}
else{
this.importSVGfallback(place,options);
}
},
supportsDataUris: false,
renderBinaryImageTiddler: function(place, tiddler, options) {
var ctype = tiddler.fields["server.content-type"] || tiddler.type;
if(macro.supportsDataUris && ctype) {
var uri = "data:%0;base64,%1".format([ctype, tiddler.text]); // TODO: fallback for legacy browsers
return macro.renderBinaryImageUrl(place, uri, options);
} else if(options.src) {
return macro.renderBinaryImageUrl(place, options.src, options);
} else {
var src;
var fields = tiddler.fields;
if(fields["server.type"] == 'tiddlyweb') { // construct an accurate url for the resource
src = "%0%1/tiddlers/%2".format([fields['server.host'],
fields['server.workspace'],fields['server.title']]);
} else { // guess the url for the resource
src = tiddler.title;
}
return macro.renderBinaryImageUrl(place, src, options);
}
},
renderImage: function(place, imageSource, options) {
var imageTiddler = store.getTiddler(imageSource);
if(imageTiddler && macro.isBinaryImageTiddler(imageTiddler)) { // handle the case where we have an image url
return macro.renderBinaryImageTiddler(place, imageTiddler, options);
} else if(imageTiddler){ // handle the case where we have a tiddler
return macro.renderSVGTiddler(place, imageTiddler, options);
} else { // we have a string representing a url
// check if we can access the json format of this url
var newplace = $('<div class="externalImage"/>').appendTo(place)[0];
try{
var img = new Image();
img.onload = function(ev) {
return macro.renderBinaryImageUrl(newplace, imageSource, options);
};
img.onerror = function(ev) {
var renderTiddler = function(tiddler, contentType) {
macro._external_cache[imageSource] = {tiddler: tiddler, contentType: contentType};
if(contentType == 'application/json') { // assume tiddlyweb server
contentType = tiddler.type;
} else { // try and use the response as tiddler text
tiddler = {text: tiddler};
}
if(macro.isBinaryImageType(contentType)) {
options.src = imageSource;
return macro.renderBinaryImageTiddler(newplace, tiddler, options);
} else {
return macro.renderSVGTiddler(newplace, tiddler, options);
}
};
var cached = macro._external_cache[imageSource];
if(cached) { // use cache where possible
renderTiddler(cached.tiddler, cached.contentType)
} else {
ajaxReq({ // deal with tiddlyweb binary images
url: imageSource,
beforeSend: function(xhr) {
xhr.setRequestHeader("Accept", "application/json,*/*");
xhr.setRequestHeader("X-ControlView", "false"); // for tiddlyspace usage
},
success: function(tiddler, status, xhr) {
if(!tiddler) {
return macro.renderBinaryImageUrl(newplace, imageSource, options);
}
var header = xhr.getResponseHeader("content-type");
var contentType;
if(header) {
header = header ? header.split(";") : [];
contentType = header[0] || false;
}
renderTiddler(tiddler, contentType);
},
error: function() {
return macro.renderBinaryImageUrl(newplace, imageSource, options);
}
});
}
};
img.src = imageSource;
} catch(e) { // the url is external thus our ajax request failed. we could try proxying..
return macro.renderBinaryImageUrl(newplace, imageSource, options); // attempt to render as image
}
}
},
handler: function(place, macroName, params, wikifier, paramString, tiddler){
var imageSource = params[0];
// collect named arguments
var args = macro.getArguments(paramString, params);
this.renderImage(place, imageSource, args);
},
renderAlternateText: function(place, options) {
if(options.alt) {
$("<div class='svgImageTest svgIconText' />").text(options.alt).appendTo(place);
}
},
renderSVGTiddler: function(place, tiddler, options) {
if(!options) {
options = {};
}
options.tiddler = tiddler;
options.fix = true;
if(macro.svgAvailable) {
this.importSVG(place, options); // display the svg
} else {
// instead of showing the image show the alternate text.
this.renderAlternateText(place, options);
}
},
renderBinaryImageUrl: function(place, src, options) {
var container = $('<div class="image" />').appendTo(place)[0];
var image = new Image(); // due to weird scaling issues where you use just a width or just a height
var createImageTag = function(userW, userH) {
var img = $("<img />");
img.attr("src", src);
img.appendTo(container);
if(userH) {
img.attr("height", userH);
}
if(userW) {
img.attr("width", userW);
}
img.addClass(options.imageClass);
};
image.onload = function() {
var w = image.width;
var h = image.height;
var userH = options.height;
var userW = options.width;
var ratio;
if(userH && !userW) {
ratio = userH / h;
userW = ratio * w;
} else if (userW && !userH) {
ratio = userW / w;
userH = ratio * h;
}
createImageTag(userW, userH);
};
image.onerror = function() {
createImageTag(options.width, options.height);
};
image.src = src;
},
getArguments: function(paramString, params) {
var args = paramString.parseParams("name", null, true, false, true)[0];
var options = {};
for(var id in args) {
if(true) {
var p = args[id];
if(id == "def") {
options[id] = p;
} else {
options[id] = p[0];
}
}
}
var width = params[1] || false;
var height = params[2] || false;
if(width && width.indexOf(":") > -1) {
width = false;
}
if(height && height.indexOf(":") > -1) {
height = false;
}
options.width = macro.lookupArgument(options, "width", width);
options.height = macro.lookupArgument(options, "height", height);
return options;
},
lookupArgument: function(args, id, ifEmpty) {
if(args[id]) {
return args[id];
} else {
return ifEmpty;
}
}
};
var datauriTest = function() {
var data = new Image();
data.onload = function() {
if(this.width != 1 || this.height != 1) {
macro.supportsDataUris = false;
} else {
macro.supportsDataUris = true;
}
};
data.onerror = data.onload;
data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
};
datauriTest();
// update views
var _oldwikifiedview = config.macros.view.views.wikified;
// update wikifier to check tiddler type before rendering
config.macros.view.views.wikified = function(value, place, params, wikifier, paramString, tiddler) {
if(macro.isImageTiddler(tiddler) && params[0] == "text") {
var newplace = $('<div class="wikifiedImage" />').appendTo(place)[0];
macro.renderImage(newplace, tiddler.title, {});
} else {
_oldwikifiedview(value, place, params, wikifier, paramString, tiddler);
}
};
config.macros.view.views.image = function(value, place, params, wikifier, paramString, tiddler) {
invokeMacro(place, "image", "%0 %1".format([value, params.splice(2).join(" ")]), null, tiddler);
};
config.shadowTiddlers.StyleSheetImageMacro = ".wikifiedImage svg, .wikifiedImage .image { width: 80%; }";
store.addNotification("StyleSheetImageMacro", refreshStyles);
})(jQuery);
//}}}
//{{{
(function() {
var macro = config.macros.TiddlySpaceUserPrompt = {
tiddler: "Unknown user",
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
config.extensions.tiddlyweb.getUserInfo(function(user) {
if(!user.anon) {
story.displayTiddler(document.body, macro.tiddler);
}
});
}
};
})();
//}}}
/*{{{*/
Background: #e0e4f4
Foreground: #0a0e1e
PrimaryPale: #c2caea
PrimaryLight: #7384ce
PrimaryMid: #374a9f
PrimaryDark: #000000
SecondaryPale: #d9eac2
SecondaryLight: #a6ce73
SecondaryMid: #729f37
SecondaryDark: #000000
TertiaryPale: #eacac2
TertiaryLight: #ce8573
TertiaryMid: #9f4c37
TertiaryDark: #000000
/*}}}*/
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="918 510 14 14" width="14pt" height="14pt">
<defs>
<radialGradient cx="0" cy="0" r="1" id="Gradient" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="white"/>
<stop offset="1" stop-color="#2b2b2b"/>
</radialGradient>
<radialGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(922.3752 513.7837) scale(11.4739436)"/>
</defs>
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 929.6952 512.9018 C 927.1568 510.36337 923.0412 510.36337 920.5028 512.9018 C 917.9644 515.4402 917.9644 519.5558 920.5028 522.09418 C 923.0412 524.63257 927.1568 524.63257 929.6952 522.09418 C 932.2336 519.5558 932.2336 515.4402 929.6952 512.9018 M 925.099 515.7425 L 927.17633 513.66516 L 928.9318 515.42065 L 926.8545 517.498 L 928.9318 519.57532 L 927.17633 521.3308 L 925.099 519.25348 L 923.02167 521.3308 L 921.2662 519.57532 L 923.3435 517.498 L 921.2662 515.42065 L 923.02167 513.66516 Z" fill="url(#Obj_Gradient)"/>
<path
d="M 927.61447,515.38354 A 4.5120482,4.2590361 0 1 1 918.59037,515.38354 A 4.5120482,4.2590361 0 1 1 927.61447,515.38354 z"
transform="matrix(1.0218069,0,0,1.0462046,-18.063694,-21.648443)"
id="path2394"
style="opacity:1;fill:#000000;fill-opacity:0;fill-rule:evenodd;stroke:none;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="416 13 34 34" width="34pt" height="34pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2010-06-05 14:34Z</dc:date><!-- Produced by OmniGraffle Professional 5.2.2 --></metadata><defs></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><path d="M 418.78613 28.08259 C 420.0481 20.113405 427.54074 14.6697865 435.51 15.931775 C 443.4801 17.193707 448.9237 24.686371 447.6617 32.656437 C 446.3989 40.62574 438.90625 46.069302 430.93698 44.807312 C 422.96774 43.545353 417.52328 36.0519 418.78613 28.08259 Z" fill="#c1e6fd"/><path d="M 418.78613 28.08259 C 420.0481 20.113405 427.54074 14.6697865 435.51 15.931775 C 443.4801 17.193707 448.9237 24.686371 447.6617 32.656437 C 446.3989 40.62574 438.90625 46.069302 430.93698 44.807312 C 422.96774 43.545353 417.52328 36.0519 418.78613 28.08259 Z" stroke="#7aa3be" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/><path d="M 433.17715 35.897835 C 429.89737 35.897835 427.23505 33.2355 427.23505 29.955704 C 427.23505 26.675049 429.89737 24.013567 433.17715 24.013567 C 436.45694 24.013567 439.11926 26.675049 439.11926 29.955704 C 439.11926 33.2355 436.45694 35.897835 433.17715 35.897835 Z" fill="white"/><path d="M 433.17715 35.897835 C 429.89737 35.897835 427.23505 33.2355 427.23505 29.955704 C 427.23505 26.675049 429.89737 24.013567 433.17715 24.013567 C 436.45694 24.013567 439.11926 26.675049 439.11926 29.955704 C 439.11926 33.2355 436.45694 35.897835 433.17715 35.897835 Z" stroke="#6a96bd" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="1081 357 41 41"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2010-06-05 15:00Z</dc:date><!-- Produced by OmniGraffle Professional 5.2.2 --></metadata><defs><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#b8b8b8"/><stop offset=".5" stop-color="black"/><stop offset="1" stop-color="black"/></linearGradient><linearGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(1101.07983 359.21158) rotate(90) scale(27)"/><linearGradient x1="0" x2="1" id="Gradient_2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#280000"/></linearGradient><linearGradient id="Obj_Gradient_2" xl:href="#Gradient_2" gradientTransform="translate(1122.6825 365.0514) rotate(149.999995) scale(48.74121)"/></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><g><path d="M 1083.50964 359.21158 C 1083.6959 359.26721 1083.7958 359.29745 1083.7958 359.29745 C 1083.7958 359.29745 1099.2529 358.84064 1109.0364 367.7494 C 1114.3331 372.57196 1116.91943 380.21628 1118.17786 386.21158 L 1118.65015 386.21158 L 1118.65015 359.21158 Z" fill="url(#Obj_Gradient)"/><path d="M 1113.9187 376.45688 C 1115.64136 375.06143 1116.8745 373.04938 1117.24854 370.68896 C 1118.0514 365.61874 1114.5885 360.85217 1109.5182 360.04938 C 1106.0405 359.49866 1102.7052 360.95535 1100.69434 363.56107" fill="#c1e6fd"/><path d="M 1113.9187 376.45688 C 1115.64136 375.06143 1116.8745 373.04938 1117.24854 370.68896 C 1118.0514 365.61874 1114.5885 360.85217 1109.5182 360.04938 C 1106.0405 359.49866 1102.7052 360.95535 1100.69434 363.56107" stroke="#7aa3be" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="1.5"/><path d="M 1111.5276 370.43875 C 1111.71826 369.98734 1111.8236 369.49133 1111.8236 368.97086 C 1111.8236 366.88382 1110.1299 365.19073 1108.04346 365.19073 C 1107.4209 365.19073 1106.8334 365.34143 1106.3154 365.60834" fill="#f4c4e2"/><path d="M 1111.5276 370.43875 C 1111.71826 369.98734 1111.8236 369.49133 1111.8236 368.97086 C 1111.8236 366.88382 1110.1299 365.19073 1108.04346 365.19073 C 1107.4209 365.19073 1106.8334 365.34143 1106.3154 365.60834" stroke="#ce81b0" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="1.5"/><path d="M 1083.79565 359.29755 C 1083.79565 359.29755 1099.2533 358.84064 1109.036 367.74924 C 1118.817 376.6543 1119.3557 395.18008 1119.35815 395.1798 C 1119.3573 395.18008 1118.0963 378.3106 1111.4159 374.57047 C 1104.73865 370.83041 1102.46655 373.58853 1102.46655 373.58853 C 1102.46655 373.58853 1105.8236 370.51877 1102.7499 365.99915 C 1099.68506 361.479 1083.79565 359.29755 1083.79565 359.29755 Z" fill="url(#Obj_Gradient_2)"/><path d="M 1083.79565 359.29755 C 1083.79565 359.29755 1099.2533 358.84064 1109.036 367.74924 C 1118.817 376.6543 1119.3557 395.18008 1119.35815 395.1798 C 1119.3573 395.18008 1118.0963 378.3106 1111.4159 374.57047 C 1104.73865 370.83041 1102.46655 373.58853 1102.46655 373.58853 C 1102.46655 373.58853 1105.8236 370.51877 1102.7499 365.99915 C 1099.68506 361.479 1083.79565 359.29755 1083.79565 359.29755 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width=".5"/></g></g></svg>
/***
|''Name''|TiddlySpaceFollowingPlugin|
|''Version''|0.5.1|
|''Description''|Provides a following macro|
|''Author''|Jon Robson|
|''Requires''|TiddlySpaceConfig ImageMacroPlugin|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
Tag a tiddler with "follow" to express a list of followers.
Using the {{{<<followTiddlers X>>}}}
will reveal the number of tiddlers with name X in the set of spaces the *current* user viewing your space follows.
{{{<<following jon>>}}} will list all the users following Jon.
{{{<<followers jon>>}}} will list all the followers of jon.
If no name is given eg. {{{<<following>>}}} or {{{<<follow>>}}} it will default the current user.
!StyleSheet
.followTiddlersList li {
list-style:none;
}
.followButton {
width: 2em;
}
.followTiddlersList li .siteIcon {
height:48px;
width: 48px;
}
.followTiddlersList li .externalImage, .followTiddlersList li .image {
display: inline;
}
!Code
***/
//{{{
(function($) {
config.annotations.FollowersTemplate = "This tiddler is used in the display of tiddlers from spaces you are following. Use the wildcard $1 for the space name, $2 for the space uri and $3 for the tiddler text.";
config.shadowTiddlers.FollowersTemplate = "[[$1|$2]]";
var tweb = config.extensions.tiddlyweb;
var tiddlyspace = config.extensions.tiddlyspace;
var imageMacro = config.macros.image;
var name = "StyleSheetFollowing";
config.shadowTiddlers[name] = store.getTiddlerText(tiddler.title +
"##StyleSheet");
store.addNotification(name, refreshStyles);
// provide support for sucking in tiddlers from the server
tiddlyspace.displayServerTiddler = function(src, title, workspace) {
var adaptor = store.getTiddlers()[0].getAdaptor();
tweb.getStatus(function(status) {
var context = {
workspace: workspace,
headers: { "X-ControlView": "false" }
};
var isPublic = workspace.indexOf("_public") > -1;
var space = workspace.substr(workspace.indexOf("/") + 1).
replace("_public", "").replace("_private", "");
if(tiddlyspace.currentSpace.name == space) {
space = isPublic ? "public" : "private";
} else {
space = "@%0".format([space]);
}
var callback = function(context, userParams) {
var tiddler = context.tiddler;
tiddler.fields.doNotSave = "true";
tiddler.title = "%0 [%1]".format([title, space]);
store.addTiddler(tiddler); // overriding existing allows updating
var el = story.displayTiddler(src || null, tiddler.title);
var refresh = story.getTiddler(tiddler.title);
if(refresh) {
story.refreshTiddler(tiddler.title, null, true);
}
return el;
};
adaptor.getTiddler(title, context, null, callback);
});
};
var followMacro = config.macros.followTiddlers = {
locale: {
followListHeader: "Here are tiddlers from spaces you follow using the follow tag which match this name.",
noTiddlersFromFollowers: "None of the spaces you follow contain a tiddler with this name.",
errorMessage: "There was a problem retrieving tiddlers from the server. Please try again later."
},
beforeSend: function(xhr) {
xhr.setRequestHeader("X-ControlView", "false");
},
followTag: "follow",
follower_names_cache: {},
getHosts: function(callback) {
tweb.getStatus(function(status) {
callback(tweb.host, tiddlyspace.getHost(status.server_host, "%0"));
});
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var title = params[0] || tiddler.fields["server.title"] || tiddler.title;
var user = params[1] || false; // allows a user to use the macro on another username
this.getFollowers(function(followers) {
var bagQuery = followMacro._constructBagQuery(followers);
followMacro.getHosts(function(host, tsHost) {
if(followers.length > 0) { // only run the search if we have a list of followers
var url = '%0/search?q=title:"%1" %2'.
format([host, encodeURI(title), bagQuery]);
ajaxReq({
dataType: "json",
beforeSend: followMacro.beforeSend,
url: url,
success: function(tiddlers) {
followMacro.constructInterface(place, tiddlers, { host: tsHost });
}
});
} else {
followMacro.constructInterface(place, [], {});
}
});
}, user);
},
constructInterface: function(place, tiddlers, options) {
var ul = $('<ul class="followTiddlersList" />');
var host = options.host || "";
var handler = function(ev) {
var link = $(ev.target);
var spaceName = link.attr("space");
var title = link.attr("title");
tiddlyspace.displayServerTiddler(null, title, "bags/%0_public".format([spaceName]));
};
for(var i = 0; i < tiddlers.length; i++) {
var tiddler = tiddlers[i];
var title = tiddler.title;
var spaceName = tiddler.bag.replace(/([^_]*)_public/i, "$1");
var tsHost = host.format([spaceName]);
var modifier = tiddler.modifier;
var link = $('<a href="#" title="%0" class="alienTiddlerLink">%0</a>'.format([title])).
attr("space", spaceName).click(handler);
var li = $("<li />");
imageMacro.renderImage(li[0],
"%0/bags/%1_public/tiddlers/SiteIcon".format([tsHost, spaceName]),
{ imageClass: "siteIcon" });
li.append(link);
var modifierLink = host.format([modifier]);
var spaceLink = host.format([spaceName]);
$('<span> (last modified by <a href="%2">%0</a> in <a href="%3">%1</a>)</span>'.
format([modifier, spaceName, modifierLink, spaceLink])).
appendTo(li);
ul.append(li);
}
var txt = tiddlers.length;
if(tiddlers.length === 0) {
if(options.error) {
txt = "?";
$("<li />").text(followMacro.locale.errorMessage).appendTo(ul);
} else {
$("<li />").text(followMacro.locale.noTiddlersFromFollowers).appendTo(ul);
}
}
var container = $('<div class="followButton" />').
click(function(ev) {
followMacro.followingOnClick(ev,ul[0]);
}).appendTo(place)[0];
$('<a class="followedTiddlers">%0</a>'.format([txt])).
appendTo('<div class="followedTiddlers" />').appendTo(container);
},
followingOnClick: function(ev, list) {
var target = ev.target;
var el = $(story.findContainingTiddler(target));
var place = $(".concertina", el)[0];
var headerTxt = followMacro.locale.followListHeader;
var contentEl = $("<div />").
append('<div class="followHeader">%0</div>'.format([headerTxt])).
append(list);
if(!place) {
var popup = Popup.create(target,"div");
addClass(popup ,"taggedTiddlerList followList");
place = popup;
$(popup).append(contentEl);
Popup.show();
} else {
if($(place).attr("openedby") == "followTiddlers") {
el.removeClass("concertinaOn");
$(place).attr("openedby","").empty().append(contentEl).
slideUp(500);
} else {
el.addClass("concertinaOn");
$(place).empty().append(contentEl).slideDown(500).
attr("openedby", "followTiddlers");
}
}
ev.stopPropagation();
},
_constructBagQuery: function(followers) {
var querySegments = [];
var currentSpaceName = tiddlyspace.currentSpace.name;
for(var i = 0; i < followers.length; i++) {
var follower = followers[i];
if(follower != currentSpaceName) {
querySegments.push("bag:%0_public".format([encodeURI(follower)]));
}
}
var searchArg = "(%0)".format([querySegments.join("%20OR%20")]);
return querySegments.length > 0 ? searchArg : false;
},
getFollowers: function(callback, username) {
// returns a list of spaces being followed by the existing space
var followersCallback = function(user) {
var followers = [];
if(!user.anon) {
var username = user.name;
if(username == tiddlyspace.currentSpace.name) {
// just get the tiddlers in the local store
var followerTiddlers = store.getTaggedTiddlers(followMacro.followTag);
for(var i = 0; i < followerTiddlers.length; i++) {
followers.push(followerTiddlers[i].title);
}
callback(followers);
} else {
var adaptor = store.getTiddlers()[0].getAdaptor();
if(followMacro.follower_names_cache[username]) {
// use cached list to save ajax requests
return callback(followMacro.follower_names_cache[username]);
}
followMacro.getHosts(function(host, tsHost) {
var context = {
host: host,
workspace: "bags/%0_public".format([user.name]),
filters: "select=tag:%0".format([followMacro.followTag]),
headers: { "X-ControlView": "false" }
};
var tiddlerListCallback = function(context){
var tiddlers = context.tiddlers || [];
for(var i = 0; i < tiddlers.length; i++) {
followers.push(tiddlers[i].title);
}
followMacro.follower_names_cache[username] = followers;
callback(followers);
};
adaptor.getTiddlerList(context, null, tiddlerListCallback);
});
}
}
};
if(!username) {
tweb.getUserInfo(followersCallback);
} else {
followersCallback({ name: username });
}
}
};
var followersMacro = config.macros.followers = {
locale: {
loggedOut: "Please login to see the list of followers",
noSupport: "We were unable to retrieve followers as your browser does not support following.",
pleaseWait: "Please wait while we look this up...",
error: "Whoops something went wrong. I was unable to find the followers of this user.",
noone: "No-one. :("
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var locale = followersMacro.locale;
var args = paramString.parseParams("name", null, true, false, true)[0];
var fat = args.fat ? "&fat=y" : "";
var username = params[0] || false;
var container = $('<div class="followers" />').text(locale.pleaseWait).
appendTo(place)[0];
var followersCallback = function(user) {
if(user.anon) {
$("<span />").text(locale.loggedOut).appendTo(container);
} else {
followMacro.getHosts(function(host, tsHost) {
var url = '%0/search?q=(title:"%1" AND tag:%2)%3'.
format([host, user.name,followMacro.followTag, fat]);
followersMacro.listUsers(container, url, locale,
{ field: "bag", link: true, host: tsHost });
});
}
};
if(!username) {
tweb.getUserInfo(followersCallback);
} else {
followersCallback({ name: username });
}
},
listUsers: function(place, url, locale, options) {
options = options ? options: {};
options.template = options.template ? options.template : "FollowersTemplate";
locale = locale ? locale : {};
var host = options.host || "/";
var field = options.field;
try {
ajaxReq({
url: url,
dataType: "json",
beforeSend: followMacro.beforeSend,
success: function(tiddlers) {
$(place).empty();
var list = $("<ul />").appendTo(place);
for(var i = 0; i < tiddlers.length; i++) {
var tiddler = tiddlers[i];
var spaceName = tiddler[field];
if(field == "bag") {
spaceName = spaceName.replace("_public", "");
}
var spaceURI = host.format([spaceName]);
var item = $('<li class="spaceName" />').appendTo(list)[0];
config.macros.tiddler.handler(item,null,null,null,
'name:%0 with:"%1" with:"%2" with:"%3"'.
format([options.template, spaceName, spaceURI, tiddler.text]));
}
if(tiddlers.length === 0) {
$("<li />").text(locale.noone).appendTo(list);
}
},
error: function() {
$("<span />").text(locale.error).appendTo(place);
}
});
} catch(e) {
$('<span class="error"/>').text(locale.noSupport).appendTo(place);
}
}
};
var followingMacro = config.macros.following = {
locale: {
pleaseWait: followersMacro.locale.pleaseWait,
loggedOut: "Please login to see who you are following",
noSupport: followersMacro.locale.noSupport,
error: "Whoops something went wrong. I was unable to find who this user is following.",
noone: followersMacro.locale.noone
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var locale = followingMacro.locale;
var args = paramString.parseParams("name", null, true, false, true)[0];
var fat = args.fat ? "&fat=y" : "";
var username = params[0] || false;
var container = $('<div class="following" />').text(locale.pleaseWait).
appendTo(place)[0];
var followingCallback = function(user) {
if(user.anon) {
$("<span />").text(locale.loggedOut).appendTo(container);
} else {
followMacro.getHosts(function(host) {
var url = '%0/search?q=(bag:"%1_public" AND tag:%2)%3'.
format([host, user.name,followMacro.followTag, fat]);
followersMacro.listUsers(container, url, locale,
{ field: "title", link: true });
});
}
};
if(!username) {
tweb.getUserInfo(followingCallback);
} else {
followingCallback({ name: username });
}
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpacePublisher|
|''Version''||
|''Description''|Provides a batch publishing tool for managing lots of tiddlers in TiddlySpace|
|''Requires''|TiddlySpacePublishCommand TiddlySpaceTiddlerIconsPlugin|
|''Author''|Jon Robson|
|''Version''|0.3.0|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/blob/master/src/plugins/TiddlySpacePublisher.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
{{{
<<TiddlySpacePublisher>>
creates an interface with which you can manage unpublished versions of tiddlers.
}}}
!Parameters
filter: allows you to run the publisher on a filtered set of tiddlers.
eg. filter:[tag[systemConfig]]
!TODO
batch publishing for the other way round (public to private)
!Code
***/
//{{{
(function($) {
var currentSpace = config.extensions.tiddlyspace.currentSpace.name;
var originMacro = config.macros.tiddlerOrigin;
var macro = config.macros.TiddlySpacePublisher = {
locale: {
title: "Publisher",
updatedPrivateTiddler: "newer than published version (click {{viewPublicTiddler{%0}}} to view)",
makePublicLabel: "Make public",
noTiddlersText: "No tiddlers to publish",
makePublicPrompt: "Make all the selected tiddlers public.",
description: "Publish tiddlers to public version of this space",
pleaseWait: "please wait while we load the publisher... "
},
listViewTemplate: {
columns: [
{ name: "Selected", field: "Selected", rowName: "title", type: "Selector" },
{ name: "Tiddler", field: "tiddler", title: "Tiddler", type: "Tiddler" },
{ name: "Status", field: "status", title: "Status", type: "WikiText" }
],
rowClasses: [
{ className: "updated", field: "updated" },
{ className: "notPublished", field: "notPublished" }
]
},
publishedTiddlers: {}, // maps tiddler titles to a currently public tiddler where public tiddlers exist
getPublicTiddlers: function(listWrapper, paramString, spaceName, tiddler) { // fills in publishedTiddlers variable above
var adaptor = tiddler.getAdaptor();
var context = {
workspace: "recipes/%0_public".format([spaceName])
};
var callback = function(context, userParams) {
if(context.status) {
var tiddlers = context.tiddlers;
for(var i = 0; i < tiddlers.length; i++) {
var tid = tiddlers[i];
macro.publishedTiddlers[tid.title] = tid;
}
macro.refresh(listWrapper, paramString);
}
};
adaptor.getTiddlerList(context, null, callback);
},
makePublic: function(e, listWrapper, paramString) { // this is what is called when you click the publish button
var wizard = new Wizard(e.target);
var listView = wizard.getValue("listView");
var rowNames = ListView.getSelectedRows(listView);
var callback = function(status) {
macro.refresh(listWrapper, paramString);
};
var cmd = config.commands.publishTiddler;
var publicWorkspace;
for(var i = 0; i < rowNames.length; i++) {
var title = rowNames[i];
var tiddler = store.getTiddler(title);
if(!publicBag) {
publicBag = cmd.toggleBag(tiddler, "public");
}
macro.publishedTiddlers[title] = tiddler;
var newTiddler = {
title: tiddler.title,
fields: { "server.bag": publicBag }
};
config.commands.publishTiddler.moveTiddler(tiddler, newTiddler, true, callback);
}
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var wizard = new Wizard();
var locale = macro.locale;
wizard.createWizard(place, locale.title);
wizard.addStep(macro.locale.description, '<input type="hidden" name="markList" />');
var markList = wizard.getElement("markList");
var listWrapper = document.createElement("div");
markList.parentNode.insertBefore(listWrapper, markList);
listWrapper.setAttribute("refresh", "macro");
listWrapper.setAttribute("macroName", "SpaceManager");
listWrapper.setAttribute("params", paramString);
$(listWrapper).text(macro.locale.pleaseWait);
this.getPublicTiddlers(listWrapper, paramString, currentSpace, tiddler);
},
refresh: function(listWrapper, paramString) {
var wizard = new Wizard(listWrapper);
var locale = macro.locale;
var selectedRows = [];
ListView.forEachSelector(listWrapper, function(e, rowName) {
if(e.checked) {
selectedRows.push(e.getAttribute("rowName"));
}
});
removeChildren(listWrapper);
var params = paramString.parseParams("anon");
var publishCandidates = [];
var unpublishedTiddlers;
var filter = params[0].filter;
if(filter) {
unpublishedTiddlers = store.filterTiddlers(filter[0]);
} else {
unpublishedTiddlers = store.getTiddlers();
}
var publishedTiddlers = macro.publishedTiddlers;
var privateBag = currentSpace + "_private";
for(var t = 0; t < unpublishedTiddlers.length; t++) {
var include = false;
var tiddler = unpublishedTiddlers[t];
var bag = tiddler.fields["server.bag"];
if(!tiddler.tags.contains("excludePublisher")) {
if(bag == privateBag) {
var candidate = {
title: tiddler.title,
tiddler: tiddler
};
var publishedTiddler = publishedTiddlers[tiddler.title];
if(!publishedTiddler) {
candidate.status = "unpublished";
include = true;
candidate.notPublished = true;
} else if(!originMacro.areIdentical(tiddler, publishedTiddler)) {
candidate.status = locale.updatedPrivateTiddler.format([tiddler.title]);
candidate.publicTiddler = publishedTiddler;
candidate.updated = true;
include = true;
}
if(include) {
publishCandidates.push(candidate);
}
}
}
}
if(publishCandidates.length === 0) {
createTiddlyElement(listWrapper, "em", null, null, locale.noTiddlersText);
} else {
var listView = ListView.create(listWrapper, publishCandidates, macro.listViewTemplate);
wizard.setValue("listView", listView);
var btnHandler = function(ev) {
macro.makePublic(ev, listWrapper, paramString);
};
wizard.setButtons([
{ caption: locale.makePublicLabel, tooltip: locale.makePublicPrompt, onClick: btnHandler }
]);
}
var publicLinks = $(".viewPublicTiddler");
$.each(publicLinks, function(index, el) {
el = $(el);
var title = el.text();
el.empty();
var handler = function(ev) {
ev.preventDefault();
var tiddler = store.getTiddler(title);
config.extensions.tiddlyspace.spawnPublicTiddler(tiddler, el);
};
$('<a href="javascript:;" />').text(title).click(handler).appendTo(el);
});
}
};
var unpublishedTabText = 'Unpublished "Manage unpublished tiddlers" TabUnpublished';
config.shadowTiddlers.TabMore = config.shadowTiddlers.TabMore.replace(
"TabMoreShadowed", "TabMoreShadowed %0".format([unpublishedTabText]));
})(jQuery);
//}}}
{{annotation{
You are logged in as <<message options.txtUserName>>.
This identity is currently not associated with any registered TiddlySpace user.
Feel free to <<TiddlySpaceLoginLoader Authorization "Sign Up">> now.
}}}
/*{{{*/
body {
font-size: 1.0em;
font-family: helvetica, arial, sans-serif;
background-color: [[ColorPalette::Background]];
}
#displayArea {
margin: 0;
position: relative;
}
#tiddlerDisplay {
margin: 2em 23em 0 2em;
}
.public {
border-color: #C7EAFF;
}
.private {
border-color: #FFCAE9;
}
.revisionCloak {
position: absolute;
position: fixed !important;
height: 100%;
width: 100%;
top: 0;
left: 0;
border: 0;
margin: 0;
padding: 0;
opacity: 0.5;
filter: alpha(opacity=50);
background-color: black;
}
[[StyleSheetHeader]]
[[StyleSheetMenuBar]]
[[StyleSheetSideBar]]
[[StyleSheetTiddler]]
/*}}}*/
<!--{{{-->
<link rel='shortcut icon' href='/bags/tiddlyspace/tiddlers/favicon.ico' />
<!--}}}-->
<<TiddlySpaceLogin>>
<<TiddlySpaceRegister>>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="434 218 68 68"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 478.39694 232.53705 L 478.39694 232.53705
C 477.1145 231.85132 475.77875 231.30147 474.41058 230.88734 L 474.41058 218.24994 L 461.58942 218.24994
L 461.58942 230.88734 C 460.22125 231.30147 458.8855 231.85132 457.60306 232.53705 L 448.66824 223.60214
L 439.6022 232.66814 L 448.53717 241.60304 C 447.8515 242.8854 447.30157 244.22116 446.88745 245.58936
L 434.25 245.58936 L 434.25 258.41052 L 446.88745 258.41052
C 447.30157 259.77869 447.8515 261.11447 448.53717 262.39688 L 439.6022 271.33173 L 448.66824 280.3978
L 457.60306 271.46283 C 458.8855 272.14862 460.22125 272.69846 461.58942 273.11252 L 461.58942 285.74988
L 474.41058 285.74988 L 474.41058 273.11252 C 475.77875 272.69846 477.1145 272.14862 478.39694 271.46283
L 487.33176 280.3978 L 496.39767 271.33173 L 487.46286 262.39688
C 488.14853 261.11447 488.69836 259.77869 489.11255 258.41052 L 501.74988 258.41052 L 501.74988 245.58936
L 489.11255 245.58936 C 488.69836 244.22116 488.14853 242.8854 487.46286 241.60304 L 496.39767 232.66814
L 487.33176 223.60214 Z M 475.3328 244.66714 C 479.3825 248.71698 479.3825 255.2829 475.3328 259.33273
C 471.28296 263.3826 464.71704 263.3826 460.66724 259.33273
C 456.61737 255.2829 456.61737 248.71698 460.66724 244.66714
C 464.71704 240.61734 471.28296 240.61734 475.3328 244.66714" fill="#111"
class="glyph"/>
</g>
</g>
</svg>
/***
|''Name''|TiddlySpaceIdentities|
|''Version''|0.1.0|
|''Description''||
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceIdentities.js|
|''Requires''|TiddlySpaceConfig chrjs|
!HTMLForm
<form method="POST" action="#">
<fieldset>
<legend />
<dl>
<dt>Type:</dt>
<dd>
<select>
<option value="openid">OpenID</option>
</select>
</dd>
<dt>Identity:</dt>
<dd><input type="text" name="openid" /></dd>
</dl>
<input type="hidden" name="tiddlyweb_redirect" />
<input type="submit" />
</fieldset>
</form>
!TODO
* process config.extensions.tiddlyweb.challengers instead of hardcoding OpenID
!Code
***/
//{{{
(function($) {
var tweb = config.extensions.tiddlyweb;
var macro = config.macros.TiddlySpaceIdentities = {
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
locale: {
listError: "error retrieving identities for user %0",
addLabel: "Add Identity"
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
tweb.getUserInfo(function(user) {
if(!user.anon) {
var container = $("<div />").appendTo(place);
macro.refresh(container);
}
});
},
refresh: function(container) {
container.empty().append("<ul />").append(this.generateForm());
$.ajax({ // TODO: add (dynamically) to chrjs user extension?
url: "%0/users/%1/identities".format([tweb.host, tweb.username]),
type: "GET",
success: function(data, status, xhr) {
var identities = $.map(data, function(item, i) {
return $("<li />").text(item)[0];
});
$("ul", container).append(identities);
},
error: function(xhr, error, exc) {
displayMessage(macro.locale.listError.format([tweb.username]));
}
});
},
generateForm: function() {
var challenger = "tiddlywebplugins.tiddlyspace.openid";
var uri = "%0/challenge/%1".format([tweb.host, challenger]);
var redirect = tweb.serverPrefix + "#auth:OpenID=";
return $(this.formTemplate).attr("action", uri).submit(this.onSubmit).
find("legend").text(this.locale.addLabel).end().
find("[name=tiddlyweb_redirect]").val(redirect).end().
find("[type=submit]").val(this.locale.addLabel).end();
},
onSubmit: function(ev) {
var form = $(this);
var redirect = form.find("[name=tiddlyweb_redirect]");
var openid = form.find("[name=openid]").val();
redirect.val(redirect.val() + openid);
return true;
}
};
config.paramifiers.auth = {
locale: {
success: "successfully added identity %0",
error: "error adding identity %0: %1"
},
onstart: function(v) {
var identity = window.location.hash.split("auth:OpenID=")[1];
if(identity) {
this.addIdentity(identity);
}
},
addIdentity: function(name) {
var msg = config.paramifiers.auth.locale;
var tiddler = new tiddlyweb.Tiddler(name);
tiddler.bag = new tiddlyweb.Bag("MAPUSER", tweb.host);
var callback = function(data, status, xhr) {
displayMessage(msg.success.format([name]));
window.location = window.location.toString().split("#")[0] + "#";
};
var errback = function(xhr, error, exc) {
displayMessage(msg.error.format([name, error]));
};
tiddler.put(callback, errback);
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpacePubRevCommand|
|''Version''||
|''Description''||
|''Requires''|TiddlySpaceConfig BinaryTiddlersPlugin|
|''Source''||
!Code
***/
//{{{
(function($) {
var ns = config.extensions.tiddlyspace;
var cmd = config.commands.pubRev = { // TODO: rename
text: "public",
tooltip: "view public version",
loadingMsg: "retrieving public version of <em>%0</em>",
noPubError: "<em>%0</em> has not been published",
isEnabled: function(tiddler) {
if(readOnly) {
return false;
}
var space = ns.determineSpace(tiddler, true);
var bag = tiddler.fields["server.bag"];
return space && (bag ? bag == space.name + "_private" : true);
},
handler: function(ev, src, title) {
var tiddler = store.getTiddler(title);
var adaptor = tiddler.getAdaptor();
var space = ns.determineSpace(tiddler, false);
var context = {
host: adaptor.fullHostName(tiddler.fields["server.host"]),
workspace: "bags/%0_public".format([space.name])
};
var popup = Popup.create(src, "div");
var msg = cmd.loadingMsg.format([title]);
popup = $(popup).html(msg);
Popup.show(); // XXX: can be irritating if it just flashes quickly
var callback = function(context, userParams) {
if(context.status) {
ns.spawnPublicTiddler(context.tiddler, src);
Popup.remove();
} else {
var msg = cmd.noPubError.format([context.tiddler.title]);
msg = $('<div class="annotation" />').html(msg);
popup.empty().append(msg);
}
};
adaptor.getTiddler(title, context, null, callback);
return false;
}
};
// adds a Tiddler instance to the store as temporary tiddler and displays it
// src is passed to Story's displayTiddler as srcElement
ns.spawnPublicTiddler = function(tiddler, src) { // XXX: rename!?
tiddler.fields.doNotSave = "true";
tiddler.title = tiddler.title + this.spawnPublicTiddler.pubSuffix;
store.addTiddler(tiddler); // overriding existing allows updating
var refresh = story.getTiddler(tiddler.title);
var el = story.displayTiddler(src || null, tiddler.title);
if(refresh) {
story.refreshTiddler(tiddler.title, null, true);
}
return el;
};
ns.spawnPublicTiddler.pubSuffix = " [public]"; // XXX: hacky?
// hijack ServerSideSavingPlugin's sync to support virtual public tiddlers
var _sync = config.extensions.ServerSideSavingPlugin.sync;
config.extensions.ServerSideSavingPlugin.sync = function(tiddlers) {
_sync.apply(this, arguments);
store.forEachTiddler(function(title, tiddler) {
var pubRev = config.extensions.BinaryTiddlersPlugin.endsWith(title,
ns.spawnPublicTiddler.pubSuffix);
if(pubRev && tiddler.fields.doNotSave == "true") {
var tid = $.extend(new Tiddler(title), tiddler);
tid.fields = $.extend({}, tiddler.fields);
tid.title = tid.fields["server.title"];
delete tid.fields.doNotSave;
delete tid.fields["server.title"];
config.extensions.ServerSideSavingPlugin.saveTiddler(tid);
}
});
};
})(jQuery);
//}}}
The goal of TiddlySpace is to provide an environment on the web that supports open intellectual discourse while being inimical to spam and the tragedy of the commons.
The following people are members of the space ''<<message extensions.tiddlyspace.currentSpace.name>>''. Only members have access to the private tiddlers in a space.
<<TiddlySpaceMembers>>
<<TiddlySpaceChangePassword>>
<<closeAll>><<permaview>><<newTiddler>>
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options »" "Change TiddlyWiki advanced options">>
html, body, #container, #contentWrapper {
height: 100%;
min-width: 680px;
min-height: 550px;
padding: 0;
margin: 0;
color: #003355;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.95em;
background-color: #9E9E9E;
}
body > #container {
height: auto;
min-height: 100%;
}
#container {
background-color: #fff;
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#C7EAFF), to(#FFFFFF));
background: -moz-linear-gradient(0% 100% 90deg, #C7EAFF, #FFFFFF);
min-width: 43em;
}
#header {
background-color: #C7EAFF;
width: 100%;
height: 8em;
text-align: center;
border-bottom: 4px solid #86B2CC;
}
.about .public_bubble {
margin: -5em auto 0 auto;
width: 19.5em;
position: relative;
z-index: 100;
padding: 10em;
-webkit-transition: -webkit-transform 0.6s ease-in-out;
}
.about .public_bubble:hover {
-webkit-transform: rotate(0deg) scale(1.05);
-moz-transform: rotate(0deg) scale(1.05);
transform: rotate(0deg) scale(1.05);
}
#about .private_bubble {
width: 14em;
padding: 1em 2em 2em;
}
#footer {
color: #000;
clear: both;
position: relative;
width: 100%;
height: 100%;
min-height: 5em;
min-width: 43em;
text-align: center;
background-color: #9E9E9E;
border-top: 0.1em solid black;
padding-top: 1em;
margin-top: -5.1em;
z-index: 100;
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(white), to(#9E9E9E));
background: -moz-linear-gradient(0% 100% 90deg, #9E9E9E, white);
}
#footer * {
margin: 0;
padding: 0;
}
.siteTitle {
color: #337788;
position: relative;
top: -2.7em;
line-height: 3em;
font-size: 3em;
font-weight: bold;
}
.siteSubtitle {
position: relative;
top: -3.5em;
font-size: 1.3em;
display: block;
margin: 0 auto;
}
.login {
position: relative;
top: -2.75em;
}
a,
a:active,
a:visited {
color: #003355;
text-decoration: none;
}
a:hover {
color: #3399AA;
text-decoration: underline;
}
.warning {
z-index: 101;
background: none !important;
width: 50em;
margin: 5em auto 1em auto;
position: relative;
}
.public, .private, .external {
border-left: 0 !important;
}
#bubbleGraphic {
width: 100%;
height: 96%;
min-height: 490px;
margin: 0;
overflow: hidden;
position: relative;
background-color: #DBDBDB;
}
#displayArea {
width: 100%;
min-height: 4%;
min-width: 599px;
margin: 0;
background-color: #9E9E9E;
}
#tiddlerDisplay {
width: 80%;
margin-left: 10%;
}
.tiddler {
background-color: white;
border: 0.1em solid black !important;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
padding: 2em 2em 1em 2em;
margin-top: 1em;
margin-bottom: 1em;
-webkit-box-shadow: 2px 2px 4px #444;
-mox-box-shadow: 2px 2px 4px #444;
position: relative;
}
.toolbar {
top: 3px !important;
right: 3px !important;
}
.viewer {
padding: 0.5em;
}
#tiddlerDisplay .public {
}
#backstageButton, #backstage, #backstageArea, #backstageCloak {
display: none !important;
}
#messageArea {
display: none !important;
}
TiddlySpace is thoroughly open source, and you can follow and take part in the development [[on GitHub|http://github.com/TiddlySpace/tiddlyspace]] and in the TiddlyWeb [[discussion group|http://groups.google.com/group/TiddlyWeb]].
/***
|''Name''|TiddlySpaceMembers|
|''Version''|0.5.0|
|''Description''|provides a UI for managing space members|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceMembers.js|
|''Requires''|TiddlySpaceConfig TiddlySpaceUserControls|
!HTMLForm
<form action="#">
<fieldset>
<legend />
<dl>
<dt>Username:</dt>
<dd><input type="text" name="username" /></dd>
</dl>
<p class="annotation" />
<input type="submit" />
</fieldset>
</form>
!Code
***/
//{{{
(function($) {
var macro = config.macros.TiddlySpaceMembers = {
formTemplate: store.getTiddlerText(tiddler.title + "##HTMLForm"),
locale: {
authError: "list of members is only visible to members of space <em>%0</em>",
listError: "error retrieving members for space <em>%0</em>: %1",
addLabel: "Add member",
noUserError: "user <em>%0</em> does not exist",
delTooltip: "click to remove member",
delPrompt: "Are you sure you want to remove member %0?",
delError: "error removing member %0: %1"
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var space = config.extensions.tiddlyspace.currentSpace.name;
var host = config.extensions.tiddlyweb.host;
this.space = new tiddlyweb.Space(space, host); // XXX: singleton
var container = $("<div />").appendTo(place);
if(!readOnly) {
this.refresh(container);
} else {
var msg = this.locale.authError.format([this.space.name]);
this.notify(msg, container);
}
},
refresh: function(container) {
var callback = function(data, status, xhr) {
container.empty();
macro.displayMembers(data, container);
};
var errback = function(xhr, error, exc) {
var msg = xhr.status == 403 ? "authError" : "listError";
msg = macro.locale[msg].format([macro.space.name, error]);
macro.notify(msg, container);
};
this.space.members().get(callback, errback);
},
displayMembers: function(members, container) {
var items = $.map(members, function(member, i) {
var link = $('<a href="javascript:;" />').text(member); // TODO: link to space
var btn = $('<a class="deleteButton" href="javascript:;" />').
text("x"). // TODO: i18n (use icon!?)
attr("title", macro.locale.delTooltip).
data("username", member).click(macro.onClick);
return $("<li />").append(link).append(btn)[0];
});
$("<ul />").append(items).appendTo(container);
this.generateForm().appendTo(container);
},
generateForm: function() {
return $(this.formTemplate).submit(this.onSubmit).
find("legend").text(this.locale.addLabel).end().
find(".annotation").hide().end().
find("[type=submit]").val(this.locale.addLabel).end();
},
onSubmit: function(ev) {
var form = $(this).closest("form");
var selector = "[name=username]";
var username = form.find(selector).val();
var callback = function(data, status, xhr) {
var container = form.closest("div");
macro.refresh(container);
};
var errback = function(xhr, error, exc) {
var ctx = {
msg: { 409: macro.locale.noUserError.format([username]) },
form: form,
selector: selector
};
config.macros.TiddlySpaceLogin.displayError(xhr, error, exc, ctx);
};
macro.space.members().add(username, callback, errback);
return false;
},
onClick: function(ev) { // XXX: ambiguous; rename
var btn = $(this);
var username = btn.data("username");
var msg = macro.locale.delPrompt.format([username]);
var callback = function(data, status, xhr) {
if(username == config.extensions.tiddlyweb.username) { // assumes getStatus has completed
readOnly = true;
refreshDisplay();
}
var container = btn.closest("div");
macro.refresh(container);
};
var errback = function(xhr, error, exc) {
displayMessage(macro.locale.delError.format([username, error]));
};
if(confirm(msg)) {
macro.space.members().remove(username, callback, errback);
}
},
notify: function(msg, container) {
container.addClass("annotation").html(msg);
}
};
})(jQuery);
//}}}
/*{{{*/
#menuBar {
left: 0;
right: 0;
position: relative;
background-color: [[ColorPalette::PrimaryLight]];
margin: 0;
padding: 0.5em 0 0.5em 0;
min-height: 1em;
overflow: hidden;
border-top: 1px solid [[ColorPalette::PrimaryDark]];
border-bottom: 1px solid [[ColorPalette::PrimaryDark]];
width: 100%; /* for ie 6 */
}
#mainMenu {
position: static;
text-align: left;
min-height: 1em;
margin-left: 1em;
float: left;
width: auto;
padding: 0;
}
#sidebarOptions {
float: right;
font-size: 1.1em;
line-height: 1.6em;
min-height: 1em;
padding-top: 0;
}
#mainMenu a {
padding: 0.6em 0.25em;
}
#mainMenu a:hover {
background-color: [[ColorPalette::PrimaryMid]];
color: [[ColorPalette::Background]]
}
#sidebarOptions a {
border: 0 none;
margin: 0 0.2em;
padding: 0.6em 0.25em;
display: inline;
}
/*}}}*/
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="301 225 48 52"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 333.00003 234 L 306 258.75003 L 301.5 270 L 312.75 265.50003 L 339.75 240.74998 Z M 337.5 229.50002
L 335.24988 231.75008 L 341.99997 238.50003 L 344.24997 236.24995 Z M 342 225.00003 L 339.74988 227.25009
L 346.5 234.00005 L 348.75 231.75003 Z M 301.5 273.9719 C 301.5 273.9719 309.59888 277.99927 317.70013 273.97183
C 325.80066 269.94437 341.99997 276.65686 341.99997 276.65686 L 341.99997 273.97195
C 341.99997 273.97195 325.80014 267.2594 317.70013 271.28687 C 309.6 275.31451 301.5 271.28683 301.5 271.28683 Z"
fill="#101010" class="glyph"/>
</g>
</g>
</svg>
/***
http://github.com/tiddlyweb/chrjs/raw/master/main.js
***/
//{{{
// TiddlyWeb adaptor
// v0.9.0
//
// TODO:
// * ensure all routes are supported
// * Policy class (attributes read, write, create, delete, manage, accept and owner)
// * documentation
(function($) {
tiddlyweb = {
routes: {
// host is the TiddlyWeb instance's URI (including server_prefix)
// placeholders "_type" & "name" refer to the respective bag/recipe
root : "{host}/",
bags : "{host}/bags",
bag : "{host}/bags/{name}",
recipes : "{host}/recipes",
recipe : "{host}/recipes/{name}",
tiddlers : "{host}/{_type}s/{name}/tiddlers",
tiddler : "{host}/{_type}s/{name}/tiddlers/{title}",
revisions: "{host}/{_type}s/{name}/tiddlers/{title}/revisions",
revision : "{host}/{_type}s/{name}/tiddlers/{title}/revisions/{id}",
search : "{host}/search?q={query}"
}
};
// host (optional) is the URI of the originating TiddlyWeb instance
tiddlyweb.Resource = function(type, host) {
if(arguments.length) { // initialization
this._type = type; // XXX: somewhat redundant, as it generally corresponds to class name
if(host !== false) {
this.host = host !== undefined ? host.replace(/\/$/, "") : null;
}
}
};
$.extend(tiddlyweb.Resource.prototype, {
// retrieves resource from server
// callback is passed resource, status, XHR (cf. jQuery.ajax success)
// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
// filters is a filter string (e.g. "select=tag:foo;limit=5")
get: function(callback, errback, filters) {
var uri = this.route();
if(filters) {
var separator = uri.indexOf("?") == -1 ? "?" : ";";
uri += separator + filters;
}
var self = this;
return $.ajax({
url: uri,
type: "GET",
dataType: "json",
success: function(data, status, xhr) {
var resource = self.parse(data);
callback(resource, status, xhr);
},
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
});
},
// sends resource to server
// callback is passed data, status, XHR (cf. jQuery.ajax success)
// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
put: function(callback, errback) {
var uri = this.route();
var data = {};
var self = this;
$.each(this.data, function(i, item) {
var value = self[item];
if(value !== undefined) {
data[item] = value;
}
});
return $.ajax({
url: uri,
type: "PUT",
contentType: "application/json",
data: $.toJSON(data),
success: callback,
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
});
},
// deletes resource on server
// callback is passed data, status, XHR (cf. jQuery.ajax success)
// errback is passed XHR, error, exception, resource (cf. jQuery.ajax error)
"delete": function(callback, errback) {
var uri = this.route();
var self = this;
return $.ajax({
url: uri,
type: "DELETE",
success: callback,
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
});
},
// returns corresponding instance from raw JSON object (if applicable)
parse: function(data) {
return data;
},
// list of accepted keys in serialization
data: [],
// returns resource's URI
route: function() {
return supplant(tiddlyweb.routes[this._type], this);
}
});
var Container = function(type, name, host) {
if(arguments.length) { // initialization
tiddlyweb.Resource.apply(this, [type, host]);
this.name = name;
this.desc = "";
this.policy = null;
}
};
Container.prototype = new tiddlyweb.Resource();
$.extend(Container.prototype, {
tiddlers: function() {
return new TiddlerCollection(this);
},
parse: function(data) {
var type = tiddlyweb._capitalize(this._type);
var container = new tiddlyweb[type](this.name, this.host);
return $.extend(container, data);
},
data: ["desc", "policy"]
});
// attribs is an object whose members are merged into the instance (e.g. query)
tiddlyweb.Collection = function(type, host, attribs) {
if(arguments.length) { // initialization
tiddlyweb.Resource.apply(this, [type, host]);
$.extend(this, attribs);
}
};
tiddlyweb.Collection.prototype = new tiddlyweb.Resource();
var TiddlerCollection = function(container, tiddler) {
if(arguments.length) { // initialization
tiddlyweb.Collection.apply(this, [tiddler ? "revisions" : "tiddlers"]);
this.container = container || null;
this.tiddler = tiddler || null;
}
};
TiddlerCollection.prototype = new tiddlyweb.Collection();
$.extend(TiddlerCollection.prototype, {
parse: function(data) {
var host = this.container.host;
return $.map(data, function(item, i) { // TODO: DRY (cf. Tiddler's parse method)
var tiddler = new tiddlyweb.Tiddler(item.title);
tiddler.bag = new tiddlyweb.Bag(item.bag, host);
delete item.bag;
if(item.recipe) {
tiddler.recipe = new tiddlyweb.Recipe(item.recipe, host);
delete item.recipe;
}
return $.extend(tiddler, item);
});
},
route: function() {
if(this.tiddler) {
var container = this.tiddler.bag || this.tiddler.recipe;
var params = {
_type: container._type,
host: container.host,
name: container.name,
title: this.tiddler.title
};
} else {
params = this.container;
}
return supplant(tiddlyweb.routes[this._type], params);
}
});
// title is the name of the tiddler
// container (optional) is an instance of either Bag or Recipe
tiddlyweb.Tiddler = function(title, container) {
tiddlyweb.Resource.apply(this, ["tiddler", false]);
this.title = title;
this.bag = container && container._type == "bag" ? container : null;
this.recipe = container && container._type == "recipe" ? container : null;
var self = this;
$.each(this.data, function(i, item) {
self[item] = undefined; // exposes list of standard attributes for inspectability
});
};
tiddlyweb.Tiddler.prototype = new tiddlyweb.Resource();
$.extend(tiddlyweb.Tiddler.prototype, {
revisions: function() {
return new TiddlerCollection(this.bag || this.recipe, this);
},
route: function() {
var container = this.bag || this.recipe;
var params = $.extend({}, this, {
host: container ? container.host : null,
_type: this.bag ? "bag" : (this.recipe ? "recipe" : null),
name: container ? container.name : null
});
return supplant(tiddlyweb.routes[this._type], params);
},
parse: function(data) {
var tiddler = new tiddlyweb.Tiddler(this.title);
var container = this.bag || this.recipe;
tiddler.bag = new tiddlyweb.Bag(data.bag, container.host);
delete data.bag;
if(this.recipe) {
tiddler.recipe = this.recipe;
}
return $.extend(tiddler, data);
},
data: ["created", "modified", "modifier", "tags", "fields", "text", "type"]
});
tiddlyweb.Bag = function(name, host) {
Container.apply(this, ["bag", name, host]);
};
tiddlyweb.Bag.prototype = new Container();
tiddlyweb.Recipe = function(name, host) {
Container.apply(this, ["recipe", name, host]);
this.recipe = [];
};
tiddlyweb.Recipe.prototype = new Container();
$.extend(tiddlyweb.Recipe.prototype, {
data: ["recipe"].concat(Container.prototype.data)
});
/*
* utilities
*/
tiddlyweb._capitalize = function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
// adapted from Crockford (http://javascript.crockford.com/remedial.html)
var supplant = function(str, obj) {
return str.replace(/{([^{}]*)}/g, function (a, b) {
var r = obj[b];
r = typeof r === "string" || typeof r === "number" ? r : a;
return b == "host" ? r : encodeURIComponent(r); // XXX: special-casing
});
};
})(jQuery);
//}}}
AAABAAYAEBAQAAEABAAoAQAAZgAAABAQAAABAAgAaAUAAI4BAAAQEAAAAQAgAGgEAAD2BgAAICAQAAEABADoAgAAXgsAACAgAAABAAgAqAgAAEYOAAAgIAAAAQAgAKgQAADuFgAAKAAAABAAAAAgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAjD3WKwEAAAAQAAAAgACAM4CAAADAwMAigICAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAAAAALsREYh4h4gRERFId3d3d4QRFId3d3d3eEEYd3d3d3d3gYd3d3d3d3d4h3d3d3d3d3h3d3d3d3d3d4d3d3d3d3d4h3d3d3d3d3h3d3d3d3d3d4d3d3d3d3d4h3d3d3d3d3gYd3d3d3d3gRZ3d3d3d3dhEWh3d3d3hhEREYh4h4gREfgfAADgBwAAwAMAAIABAACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAIABAADAAwAA4AcAAPgfAAAoAAAAEAAAACAAAAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8z//wCZ//8AZv//ADP//4AA//+A/8z/gMzM/8CZzP+AZsz/ADPM/wAAzP8A/5n//8yZ//+Zmf//Zpn/ADOZ//8Amf///2b//8xm/8yZZv//Zmb/zDNm//8AZv/M/zP//8wz/yyZM//yZjP/LzMz//gAM/8s/wD//MwA/yyZAP/0ZgD/KDMA//QAAP8o///M9Mz/zCKZ/8z/Zv/MIjP/zP8A/8wi/8zM/8zMzCKZzMz/ZszM+DPMzP8AzMz//5nM8MyZzMCZmcyAZpnMgDOZzAAAmcwA/2bMAMxmzACZZswAZmbMADNmzAAAZswA/zPMgMwzzICZM8zAZjPM8DMzzAAAM8wA/wDMCswAzAqZAMwOZgDMdzMAzLcAAMy3//+Z+8z/mWWZ/5m7Zv+Z9DP/mQAA/5n+/8yZt8zMmbeZzJm7ZsyZtzPMmbsAzJm7/5mZVMyZmcuZmZmZZpmZJzOZmbsAmZm3/2aZt8xmmbuZZpl7ZmaZ+jNmmWUAZpkc/zOZmcwzmSiZM5m7ZjOZtzMzmbcAM5m7/wCZe8wAmXuZAJmyZgCZsTMAmfMAAJkA//9m/sz/ZruZ/2a3Zv9muzP/ZrcA/2a3/8xme8zMZrKZzGYcZsxmmTPMZikAzGa7/5lmt8yZZruZmWa3ZplmuzOZZrsAmWa7/2ZmG8xmZqmZZmaQZmZmyDNmZrIAZma7/zNmAcwzZgCZM2YEZjNmujMzZgEAM2YA/wBmAswAZvCZAGYAZgBm4TMAZssAAGaZ//8zDcz/MxGZ/zOqZv8zkDP/M6wA/zPL/8wzmczMMwuZzDO7ZswzmTPMMwkAzDOq/5kzkMyZM4iZmTMKZpkz6zOZMwAAmTMA/2YzCsxmMwCZZjMAZmYzAjNmM/8AZjMA/zMzAMwzMwCZMzMAZjMzADMzMwAAMzMA/wAzScwAMwCZADMAZgAzRzMAM2gAADMA//8AAMz/AACZ/wAAZv8AADP/AAAA/wAA/8wAAMzMAACZzAAAZswAADPMAAAAzAAA/5kAAMyZAACZmQAAZpkAADOZAAAAmQD//2YAAMxmAP+ZZgAAZmYA/zNmAAAAZgD//zMAAMwzAP+ZMwAAZjMA/zMzAAAAMwDM/wAAAMwAAMyZAAAAZgAAzDMAAAAAAO7MAADdAAAAu8wAAKoAAACIzAAAdwAAAFWZAABEAAAAIpkAABEAAO4AmQDdAAAAuwCZAKoAAACIAJkAdwAAAFUAmQBEAAAAIgBmABEAAO4AAGbdAAAAuwAAZqoAAACIAABmdwAAAFUAAGZEAAAAIgAAZhEAAADu7u4z3d3dALu7uzOqqqoAiIiIM3d3dwBVVVUzREREACIiIjMREREAAAAAM/////96eXl5eXl5ev////////15eU9OKipOT3l5/f///9B5TyoqKioqKioqT3nQ//95TyoqKioqKioqKipPef95eSoqKioxMjIxKioqKnl5eU8qKioxMQcHMTEqKipPeXlOKioxMQcHBwcxMSoqTnl5KioqMgcHBwcHBzIqKip5eSoqKjIHBwcHBwcyKioqeXlOKioxMQcHBwcxMSoqTnl5TyoqKjExBwcxMSoqKk95eXkqKioqMTIyMSoqKip5ef95TyoqKioqKioqKipPef//pXlPKioqKioqKipPeaX///+leXlPTioqTk95eaX///////95eXl5eXl5ef/////4HwAA4AcAAMADAACAAQAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAOAHAAD4HwAAKAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAwAAAAWghWMuu6F4lsClfOK+pHr4vqR6+MClfOK7oXiWoIVjLgAAAAUAAAADAAAAAQAAAAAAAAABAAAABCIiEQ+zm3WfwKV89tzCnPvw17L/+eG8//nhvP/w17L/3MKc+8ClfPazm3WfIiIRDwAAAAQAAAABAAAAATMzGQq8oXnHzbOL9fngvP/85cD//OXA//zlwP/85cD//OXA//zlwP/54Lz/zbOL9byhecczMxkKAAAAAQAAAAG+pXuZzbOL9fvjv//85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//vjv//Ns4v1vqV7mQAAAAG6m3YpwaZ99fngvP/85cD//OXA//DUwf/Fnsr/soXN/7KFzf/Fnsr/8NTB//zlwP/85cD/+eC8/8GmffW6m3YpvaV6lNzCnPv85cD//OXA//DUwf+0iM3/yqXh/92/8P/dv/D/yqXh/7SIzf/w1MH//OXA//zlwP/cwpz7vaV6lMGnfuHw17L//OXA//zlwP/Fnsr/yqXh/+HD8//hw/P/4cPz/+HD8//KpeH/xZ7K//zlwP/85cD/8Nex/8GnfuG+pXr3+eG8//zlwP/85cD/soXN/92/8P/hw/P/4cPz/+HD8//hw/P/3b/w/7KFzf/85cD//OXA//nhvP++pXr3vqV69/nhvP/85cD//OXA/7KFzf/dv/D/4cPz/+HD8//hw/P/4cPz/92/8P+yhc3//OXA//zlwP/54bz/vqV698GnfuHw17L//OXA//zlwP/Fnsr/yqXh/+HD8//hw/P/4cPz/+HD8//KpeH/xZ7K//zlwP/85cD/8Ney/8GnfuG9pXqU3MKc+/zlwP/85cD/8NTB/7SIzf/KpeH/3b/w/92/8P/KpeH/tIjN//DUwf/85cD//OXA/9zCnPu9pXqUupt2KcGmffX54Lz//OXA//zlwP/w1MH/xZ7K/7KFzf+yhc3/xZ7K//DUwf/85cD//OXA//ngvP/Bpn31upt2KQAAAAC9pHyYzrSN9Pvjv//85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//vjv//OtI30vaR8mAAAAAAAAAAAZmYzBcKmfsPOtI30+eC8//zlwP/85cD//OXA//zlwP/85cD//OXA//ngvP/OtI30wqZ+w2ZmMwUAAAAAAAAAAAAAAABmZjMFvaR8mMGmffXcwpz78Ney//nhvP/54bz/8Ney/9zCnPvBpn31vaR8mGZmMwUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC6m3YpvaV6lMGnfuG+pXr3vqV698GnfuG9pXqUupt2KQAAAAAAAAAAAAAAAAAAAAD4HwAA4AcAAMADAACAAQAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAOAHAAD4HwAAKAAAACAAAABAAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAjD3WKwEAAAAQAP15eU9OKipOT3l5/f///9B5TyoqKioqKioqT3nQ//95TyoqKioqKioqKipPef8REREREVyIiIiIxREREREREREREViIiIiIiIiFEREREREREZyIiIiIiIiIiMkRERERERWIiIiIiIiIiIiIURERERFYiIiIiIiIiIiIiIUREREViIiIiIiIiIiIiIiIURERWIiIiIiIiIiIiIiIiIUREYiIiIiIiIiIiIiIiIiIERyIiIiIiIgiIoiIiIiIiMEYiIiIiIgiIiIiiIiIiIiBWIiIiIgiInd3IiKIiIiIhYiIiIiIInd3d3ciiIiIiIiIiIiIgid3d3d3ciiIiIiIiIiIiIInd3d3d3IoiIiIiIiIiIgid3d3d3d3IoiIiIiIiIiIInd3d3d3dyKIiIiIiIiIiCJ3d3d3d3ciiIiIiIiIiIgid3d3d3d3IoiIiIiIiIiIgid3d3d3ciiIiIiIiIiIiIInd3d3d3IoiIiIiIiIiIiIInd3d3ciiIiIiIhYiIiIiCIid3ciIoiIiIiFGIiIiIiIIiIiIoiIiIiIgRyIiIiIiIgiIoiIiIiIiMERiIiIiIiIiIiIiIiIiIgREViIiIiIiIiIiIiIiIiFEREYiIiIiIiIiIiIiIiIgREREciIiIiIiIiIiIiIjBEREREYiIiIiIiIiIiIiIEREREREViIiIiIiIiIiIURERERERERyIiIiIiIiIwRERERERERERFYiIiIiIUREREREf/gB///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//gAAf/+AAf//4Af/KAAAACAAAABAAAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAAAABXSOAwEAAAAz//+AAP//gP/M/4DMzP/Amcz/gGbM/wAzzP8AAMz/AP+Z///Mmf//mZn//2aZ/wAzmf//AJn///9m///MZv/MmWb//2Zm/8wzZv//AGb/zP8z///MM/8smTP/8mYz/y8zM//4ADP/LP8A//zMAP8smQD/9GYA/ygzAP/0AAD/KP//zPTM/8wimf/M/2b/zCIz/8z/AP/MIv/MzP/MzMwimczM/2bMzPgzzMz/AMzM//+ZzPDMmczAmZnMgGaZzIAzmcwAAJnMAP9mzADMZswAmWbMAGZmzAAzZswAAGbMAP8zzIDMM8yAmTPMwGYzzPAzM8wAADPMAP8AzArMAMwKmQDMDmYAzHczAMy3AADMt///mfvM/5llmf+Zu2b/mfQz/5kAAP+Z/v/MmbfMzJm3mcyZu2bMmbczzJm7AMyZu/+ZmVTMmZnLmZmZmWaZmSczmZm7AJmZt/9mmbfMZpm7mWaZe2ZmmfozZpllAGaZHP8zmZnMM5komTOZu2YzmbczM5m3ADOZu/8AmXvMAJl7mQCZsmYAmbEzAJnzAACZAP//Zv7M/2a7mf9mt2b/Zrsz/2a3AP9mt//MZnvMzGaymcxmHGbMZpkzzGYpAMxmu/+ZZrfMmWa7mZlmt2aZZrszmWa7AJlmu/9mZhvMZmapmWZmkGZmZsgzZmayAGZmu/8zZgHMM2YAmTNmBGYzZrozM2YBADNmAP8AZgLMAGbwmQBmAGYAZuEzAGbLAABmmf//Mw3M/zMRmf8zqmb/M5Az/zOsAP8zy//MM5nMzDMLmcwzu2bMM5kzzDMJAMwzqv+ZM5DMmTOImZkzCmaZM+szmTMAAJkzAP9mMwrMZjMAmWYzAGZmMwIzZjP/AGYzAP8zMwDMMzMAmTMzAGYzMwAzMzMAADMzAP8AM0nMADMAmQAzAGYAM0czADNoAAAzAP//AADM/wAAmf8AAGb/AAAz/wAAAP8AAP/MAADMzAAAmcwAAGbMAAAzzAAAAMwAAP+ZAADMmQAAmZkAAGaZAAAzmQAAAJkA//9mAADMZgD/mWYAAGZmAP8zZgAAAGYA//8zAADMMwD/mTMAAGYzAP8zMwAAADMAzP8AAADMAADMmQAAAGYAAMwzAAAAAADuzAAA3QAAALvMAACqAAAAiMwAAHcAAABVmQAARAAAACKZAAARAADuAJkA3QAAALsAmQCqAAAAiACZAHcAAABVAJkARAAAACIAZgARAADuAABm3QAAALsAAGaqAAAAiAAAZncAAABVAABmRAAAACIAAGYRAAAA7u7uM93d3QC7u7szqqqqAIiIiDN3d3cAVVVVM0RERAAiIiIzERERAAAAADMBAQEBAQEBAQEBpXl5eXl5eXl5eXmlAQEBAQEBAQEBAQEBAQEBAQEBgHl5eXl5eXl5eXl5eXl5gAEBAQEBAQEBAQEBAQEB/Xp5eXlVT04qKioqTk9VeXl5ev0BAQEBAQEBAQEBAaV5eXlPKioqKioqKioqKioqT3l5eaUBAQEBAQEBAQGAeXlVTioqKioqKioqKioqKioqTlV5eYABAQEBAQEBgHl5VSoqKioqKioqKioqKioqKioqKlV5eYABAQEBAaV5eVUqKioqKioqKioqKioqKioqKioqKlV5eaUBAQEBeXlVKioqKioqKioqKioqKioqKioqKioqKlV5eQEBAXl5eU4qKioqKioqKjExMTExMSoqKioqKioqTnl5eQEBeXlPKioqKioqKjEyMjIyMjIyMjEqKioqKioqT3l5AXp5eSoqKioqKioxMjIxBwcHBzEyMjEqKioqKioqeXl6eXlVKioqKioqMTIxBwcHBwcHBwcxMjEqKioqKipVeXl5eU8qKioqKioyMgcHBwcHBwcHBwcyMioqKioqKk95eXl5TioqKioqMTIxBwcHBwcHBwcHBzEyMSoqKioqTnl5eXkqKioqKioxMgcHBwcHBwcHBwcHBzIxKioqKioqeXl5eSoqKioqKjEyBwcHBwcHBwcHBwcHMjEqKioqKip5eXl5KioqKioqMTIHBwcHBwcHBwcHBwcyMSoqKioqKnl5eXkqKioqKioxMgcHBwcHBwcHBwcHBzIxKioqKioqeXl5eU4qKioqKjEyMQcHBwcHBwcHBwcxMjEqKioqKk55eXl5TyoqKioqKjIyBwcHBwcHBwcHBzIyKioqKioqT3l5eXlVKioqKioqMTIxBwcHBwcHBwcxMjEqKioqKipVeXl6eXkqKioqKioqMTIyMQcHBwcxMjIxKioqKioqKnl5egF5eU8qKioqKioqMTIyMjIyMjIyMSoqKioqKipPeXkBAXl5eU4qKioqKioqKjExMTExMSoqKioqKioqTnl5eQEBAXl5VSoqKioqKioqKioqKioqKioqKioqKipVeXkBAQEB+nl5VSoqKioqKioqKioqKioqKioqKioqVXl5+gEBAQEBenl5VSoqKioqKioqKioqKioqKioqKlV5eXoBAQEBAQEBeXl5VU4qKioqKioqKioqKioqKk5VeXl5AQEBAQEBAQEBenl5eU8qKioqKioqKioqKipPeXl5egEBAQEBAQEBAQEB+nl5eXlVT04qKioqTk9VeXl5efoBAQEBAQEBAQEBAQEBAXl5eXl5eXl5eXl5eXl5eXkBAQEBAQEBAQEBAQEBAQEBAQF6eXl5eXl5eXl5eXoBAQEBAQEBAQEB/+AH//+AAf/+AAB//AAAP/gAAB/wAAAP4AAAB8AAAAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAYAAAAHAAAADwAAAA+AAAAfwAAAP+AAAH/wAAD/+AAB//4AB///gB/8oAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAACAAAAAwAAAAMAAAADAAAABG1bSA61m3JXuqB4mbuhd8m9o3jqvaF4+b2hePm9o3jqu6F3ybqgeJm1m3JXbVtIDgAAAAQAAAADAAAAAwAAAAMAAAACAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAwAAAAUAAAAGAAAACI98Wye0nXWavKF4876kev++pHr/vqR6/76kev++pHr/vqR6/76kev++pHr/vqR6/76kev+8oXjztJ11mo98WycAAAAIAAAABgAAAAUAAAADAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAQAAAAHAAAAChwcHBKulnGJvaN5+L6kev++pHr/y7GJ/9/Fnv/s1K7/9t25//rivv/64r7/9t25/+zUrv/fxZ7/y7GJ/76kev++pHr/vaN5+K6WcYkcHBwSAAAACgAAAAcAAAAEAAAAAgAAAAEAAAAAAAAAAAAAAAEAAAADAAAABwAAAAtuYkUst552z76kev++pHr+1LuS//Latf/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD/8tq1/9S7kv++pHr+vqR6/7eeds9uYkUsAAAACwAAAAcAAAADAAAAAQAAAAAAAAABAAAAAgAAAAQAAAAIi3hbNbqgd+a+pHr/xayD/+3Vr//85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+3Vr//FrIP/vqR6/7qgd+aJdVg0AAAACAAAAAQAAAACAAAAAQAAAAEAAAACAAAABIl8WSW8oXjlvqR6/8yyiv/54Lz//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//ngvP/Msor/vqR6/7yheOWJfFklAAAABAAAAAIAAAABAAAAAAAAAAFfXz8Iu6F4zL6kev/Msor/+uK+//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//rivv/Msor/vqR6/7uheMxfXz8IAAAAAQAAAAAAAAAAAAAAAbqid4K+pHr/xayD//ngvP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//fgvP/FrIP/vqR6/7qid4IAAAABAAAAAAAAAAC3l28gvaN5+L6kev7t1a///OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+/Twv/Qq8f/u5HK/7OGzP+zhsz/u5HK/9Crx//v08L//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+3Vr/++pHr+vaN5+LeXbyAAAAAAAAAAALuheJa+pHr/1LuS//zlwP/85cD//OXA//zlwP/85cD//OXA//riwP/Pq8f/r4HM/6+Bzf+vgc3/r4HN/6+Bzf+vgc3/r4HN/6+BzP/Pq8f/+uLA//zlwP/85cD//OXA//zlwP/85cD//OXA/9S5kv++pHr/u6F4lgAAAACii3MLvKF4876kev/y2rX//OXA//zlwP/85cD//OXA//zlwP/64sD/w5vJ/6+Bzf+vg83/w5vc/9W06v/dwPD/3cDw/9W06v/Dm9z/r4PN/6+Bzf/Dm8n/+uLA//zlwP/85cD//OXA//zlwP/85cD/8tq1/76kev+8oXjzootzC72feFW+pHr/y7GJ//zlwP/85cD//OXA//zlwP/85cD//OXA/8+rx/+vgc3/tIfQ/9a16//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Wtev/tIfQ/6+Bzf/Pq8f//OXA//zlwP/85cD//OXA//zlwP/85cD/y7GJ/76kev+9n3hVvaF4mL6kev/fxZ7//OXA//zlwP/85cD//OXA//zlwP/v08L/r4HM/6+Dzf/Wtev/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Wtev/r4PN/6+BzP/v08L//OXA//zlwP/85cD//OXA//zlwP/fxZ7/vqR6/72heJi8oXfIvqR6/+zUrv/85cD//OXA//zlwP/85cD//OXA/9Crx/+vgc3/w5vc/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Dm9z/r4HN/9Crx//85cD//OXA//zlwP/85cD//OXA/+zUrv++pHr/vKF3yL2jeOq+pHr/9t25//zlwP/85cD//OXA//zlwP/85cD/u5HK/6+Bzf/VtOr/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/9W06v+vgc3/u5HK//zlwP/85cD//OXA//zlwP/85cD/9t25/76kev+9o3jqvaF4+b6kev/64r7//OXA//zlwP/85cD//OXA//zlwP+zhsz/r4HN/93A8P/hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/3cDw/6+Bzf+zhsz//OXA//zlwP/85cD//OXA//zlwP/64r7/vqR6/72hePm9oXj5vqR6//rivv/85cD//OXA//zlwP/85cD//OXA/7OGzP+vgc3/3cDw/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//dwPD/r4HN/7OGzP/85cD//OXA//zlwP/85cD//OXA//rivv++pHr/vaF4+b2jeOq+pHr/9t25//zlwP/85cD//OXA//zlwP/85cD/u5HK/6+Bzf/VtOr/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/9W06v+vgc3/u5HK//zlwP/85cD//OXA//zlwP/85cD/9t25/76kev+9o3jqvKF3yL6kev/s1K7//OXA//zlwP/85cD//OXA//zlwP/Qq8f/r4HN/8Ob3P/hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/w5vc/6+Bzf/Qq8f//OXA//zlwP/85cD//OXA//zlwP/s1K7/vqR6/7yhd8i9oXiYvqR6/9/Fnv/85cD//OXA//zlwP/85cD//OXA/+/Twv+vgcz/r4PN/9a16//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//hw/P/4cPz/9a16/+vg83/r4HM/+/Twv/85cD//OXA//zlwP/85cD//OXA/9/Fnv++pHr/vaF4mL2feFW+pHr/y7GJ//zlwP/85cD//OXA//zlwP/85cD//OXA/8+rx/+vgc3/tIfQ/9a16//hw/P/4cPz/+HD8//hw/P/4cPz/+HD8//Wtev/tIfQ/6+Bzf/Pq8f//OXA//zlwP/85cD//OXA//zlwP/85cD/y7GJ/76kev+9n3hVootzC7yhePO+pHr/8tq1//zlwP/85cD//OXA//zlwP/85cD/+uLA/8Obyf+vgc3/r4PN/8Ob3P/VtOr/3cDw/93A8P/VtOr/w5vc/6+Dzf+vgc3/w5vJ//riwP/85cD//OXA//zlwP/85cD//OXA//Latf++pHr/vKF486KLcwsAAAAAu6N3l76kev/Uu5L//OXA//zlwP/85cD//OXA//zlwP/85cD/+uLA/8+rx/+vgcz/r4HN/6+Bzf+vgc3/r4HN/6+Bzf+vgc3/r4HM/8+rx//64sD//OXA//zlwP/85cD//OXA//zlwP/85cD/1LmS/76kev+7oXiWAAAAAAAAAAC3l28gvaN5+L6kev7t1a///OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+/Twv/Qq8f/u5HK/7OGzP+zhsz/u5HK/9Crx//v08L//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA/+3Vr/++pHr+vaN5+LeXbyAAAAAAAAAAAAAAAAC6oneCvqR6/8Wsg//54Lz//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/34Lz/xayD/76kev+6oneCAAAAAAAAAAAAAAAAAAAAAH9/VQa8oHjLvqR6/8yyiv/64r7//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD/+uK+/8yyiv++pHr/vKB4y39/VQYAAAAAAAAAAAAAAAAAAAAAAAAAALKhbh67o3nkvqR6/8yyiv/54Lz//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//ngvP/Msor/vqR6/7ujeeSyoW4eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqbdim7o3nkvqR6/8Wsg//t1a///OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/t1a//xayD/76kev+7o3nkupt2KQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKhbh68oHjLvqR6/76kev7Uu5L/8tq1//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/85cD//OXA//zlwP/y2rX/1LmS/76kev6+pHr/vKB4y7Khbh4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH9/VQa6oneCvaN5+L6kev++pHr/y7GJ/9/Fnv/s1K7/9t25//rivv/64r7/9t25/+zUrv/fxZ7/y7GJ/76kev++pHr/vaN5+Lqid4J/f1UGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3l28gu6F4lryhePO+pHr/vqR6/76kev++pHr/vqR6/76kev++pHr/vqR6/76kev++pHr/vKF487uheJa3l28gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAootzC72feFW9oXiYvKF3yL2jeOq9oXj5vaF4+b2jeOq8oXfIvaF4mL2feFWii3MLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gB///gAH//gAAf/wAAD/4AAAf8AAAD+AAAAfAAAADwAAAA4AAAAGAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//gAAf/+AAf//4Af/
/*{{{*/
#sidebar .wizard table {
margin: 0px;
}
#menuBar #sidebarOptions {
margin-right: 0.6em;
}
#sidebarTabs {
position: absolute;
right: 0;
top: 0;
width: 22.2em;
}
.tabset {
padding: 1em 6px 1px 0;
position: relative;
top: 2px;
}
#sidebarTabs .tabsetWrapper .tabset {
float: left;
height: auto;
display: inline;
width: 5.5em;
word-wrap: break-word;
top: 0;
padding: 0 0 1px;
}
#sidebarTabs .tabsetWrapper .tabsetWrapper .tabset {
float: none;
height: auto;
top: 1px;
padding: 0 0 1px;
}
.tab {
margin: 0.1em 0.25em 0 0;
padding: 6px 6px 0;
display: inline-block;
}
#sidebarTabs .tabsetWrapper .tabset .tab {
display: block;
margin: 0 0 1px 0.25em;
padding: 1em 6px 0.5em;
position: relative;
left: 3px;
border-right: 0;
border-bottom: 1px solid [[ColorPalette::TertiaryMid]];
border-color: [[ColorPalette::TertiaryMid]];
}
dd {
margin-left: 0px;
}
#sidebarTabs .tabsetWrapper .tabContents {
display: inline;
border-width: 1px 1px 1px 3px;
float: left;
border-color: [[ColorPalette::TertiaryMid]];
*height: expression(this.scrollHeight < 301? "300px" : "auto");
min-height: 25em;
background-color: [[ColorPalette::TertiaryPale]];
}
/*}}}*/
{{textRight{
<<TiddlySpaceLogout>>
<<tabs txtUserTab
"Your Identities" "Manage your identities" BackstageIdentities
"Your Spaces" "Maintain your spaces and create new ones" BackstageUserSpaces
"Your Password" "Change your password" BackstagePassword
>>
}}}
<!--{{{-->
<div macro='TiddlySpaceUserPrompt'></div>
<div id='bubbleGraphic'>
<div macro='tiddler Warning wikified' class='warning'></div>
<div macro='tiddler About wikified' class='about'></div>
<div macro='tiddler Bubbles'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='footer' refresh='content' tiddler='Footer'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/***
|''Name''|TiddlySpaceInitialization|
|''Version''|0.6.2|
|''Description''|Initializes new TiddlySpaces the first time they are created|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/blob/master/src/plugins/TiddlySpaceInit.js|
|''CoreVersion''|2.6.1|
|''Requires''|TiddlySpaceConfig RandomColorPalettePlugin chrjs|
!TODO
* robust error notification and recovery
!Code
***/
//{{{
(function($) {
var versionField = "tiddlyspaceinit_version";
var currentSpace = config.extensions.tiddlyspace.currentSpace;
var plugin = config.extensions.TiddlySpaceInit = {
version: "0.2",
SiteTitle: "%0",
SiteSubtitle: "a TiddlySpace",
flagTitle: "%0SetupFlag",
flagWarning: "Please do not modify this tiddler; it was created " +
"automatically upon space creation.",
dispatch: function() {
var title = plugin.flagTitle.format([currentSpace.name]);
config.annotations[title] = this.flagWarning;
if(currentSpace.type != "private") {
return;
}
var tiddlers = [];
var tid = store.getTiddler(title);
if(tid) {
curVersion = parseFloat(tid.fields[versionField]);
reqVersion = parseFloat(plugin.version);
if(curVersion < reqVersion) {
plugin.update(curVersion);
tid.fields[versionField] = plugin.version;
tid.incChangeCount();
tid = store.saveTiddler(tid);
tiddlers.push(tid);
}
} else { // first run
tid = new Tiddler(title);
tid.tags = ["excludeLists", "excludeSearch"];
tid.fields = $.extend({}, config.defaultCustomFields);
tid.fields[versionField] = plugin.version;
tid.text = "@@%0@@".format([plugin.flagWarning]);
tid = store.saveTiddler(tid);
tiddlers = tiddlers.concat(plugin.firstRun(), tid);
}
autoSaveChanges(null, tiddlers);
},
update: function(curVersion) {
if(curVersion < 0.2) {
this.createAvatar();
}
},
firstRun: function() {
var tiddlers = [];
var pubWorkspace = "bags/%0_public".format([currentSpace.name]);
// generate Site*itle
$.each(["SiteTitle", "SiteSubtitle"], function(i, item) {
var tid = new Tiddler(item);
tid.tags = ["excludeLists", "excludeSearch"];
tid.fields = $.extend({}, config.defaultCustomFields, {
"server.workspace": pubWorkspace
});
tid.text = plugin[item].format([currentSpace.name]);
tid = store.saveTiddler(tid);
tiddlers.push(tid);
});
// generate ColorPalette (ensuring it's public)
var wfield = "server.workspace";
var workspace = config.defaultCustomFields[wfield];
config.defaultCustomFields[wfield] = pubWorkspace; // XXX: hacky
config.macros.RandomColorPalette.generatePalette({}, true);
config.defaultCustomFields[wfield] = workspace;
// generate avatar
this.createAvatar();
return tiddlers;
},
createAvatar: function() {
var avatar = "SiteIcon";
var tweb = config.extensions.tiddlyweb;
var host = tweb.host;
var notify = function(xhr, error, exc) {
displayMessage("ERROR: could not create avatar - " + // TODO: i18n
"%0: %1".format([xhr.statusText, xhr.responseText]));
// TODO: resolve!?
};
var pubBag = currentSpace.name + "_public";
var tid = new tiddlyweb.Tiddler(avatar);
tid.bag = new tiddlyweb.Bag(pubBag, host);
var callback = function(data, status, xhr) {}; // avatar already exists; do nothing
var errback = function(xhr, error, exc) {
if(xhr.status != 404) {
return;
}
// copy default avatar
var _notify = function(tid, status, xhr) {
displayMessage("created avatar"); // TODO: i18n
};
var _callback = function(tid, status, xhr) {
tid.title = avatar;
tid.bag.name = pubBag;
tid.put(_notify, notify); // TODO: add to current session document (via adaptor?)
};
tweb.getUserInfo(function(user) {
var avatarTitle = currentSpace.name == user.name ?
"defaultUserIcon" : "defaultSiteIcon";
var tid = new tiddlyweb.Tiddler(avatarTitle);
tid.bag = new tiddlyweb.Bag("common", host);
tid.get(_callback, notify);
});
};
tid.get(callback, errback);
}
};
$(document).bind("startup", plugin.dispatch);
})(jQuery);
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="301 592 37 36" width="37pt" height="3pc"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2010-07-21 12:53Z</dc:date><!-- Produced by OmniGraffle Professional 5.2.3 --></metadata><defs></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><path d="M 303.9367 606.33264 C 305.2315 598.36346 312.91907 592.91986 321.09567 594.18182 C 329.2731 595.4438 334.8583 602.9364 333.56348 610.9065 C 332.26782 618.8758 324.58026 624.31934 316.40369 623.05737 C 308.22711 621.7954 302.64102 614.30194 303.9367 606.33264 Z" fill="#c1e6fd"/><path d="M 303.9367 606.33264 C 305.2315 598.36346 312.91907 592.91986 321.09567 594.18182 C 329.2731 595.4438 334.8583 602.9364 333.56348 610.9065 C 332.26782 618.8758 324.58026 624.31934 316.40369 623.05737 C 308.22711 621.7954 302.64102 614.30194 303.9367 606.33264 Z" stroke="#7aa3be" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/><path d="M 318.70273 614.1482 C 315.33759 614.1482 312.60602 611.4859 312.60602 608.20605 C 312.60602 604.9254 315.33759 602.2639 318.70273 602.2639 C 322.06784 602.2639 324.79944 604.9254 324.79944 608.20605 C 324.79944 611.4859 322.06784 614.1482 318.70273 614.1482 Z" fill="white"/><path d="M 318.70273 614.1482 C 315.33759 614.1482 312.60602 611.4859 312.60602 608.20605 C 312.60602 604.9254 315.33759 602.2639 318.70273 602.2639 C 322.06784 602.2639 324.79944 604.9254 324.79944 608.20605 C 324.79944 611.4859 322.06784 614.1482 318.70273 614.1482 Z" stroke="#6a96bd" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/><path d="M 315.1293 613.7912 C 316.02603 608.27203 321.35019 604.50195 327.01303 605.37598 C 332.67642 606.24994 336.54456 611.4391 335.64783 616.95892 C 334.75049 622.47815 329.42633 626.24823 323.76352 625.3742 C 318.10068 624.5002 314.23193 619.3105 315.1293 613.7912 Z" fill="white"/><path d="M 315.1293 613.7912 C 316.02603 608.27203 321.35019 604.50195 327.01303 605.37598 C 332.67642 606.24994 336.54456 611.4391 335.64783 616.95892 C 334.75049 622.47815 329.42633 626.24823 323.76352 625.3742 C 318.10068 624.5002 314.23193 619.3105 315.1293 613.7912 Z" stroke="#bebebe" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/><path d="M 325.3543 619.20392 C 323.02374 619.20392 321.13193 617.36005 321.13193 615.08856 C 321.13193 612.81653 323.02374 610.97327 325.3543 610.97327 C 327.68488 610.97327 329.5767 612.81653 329.5767 615.08856 C 329.5767 617.36005 327.68488 619.20392 325.3543 619.20392 Z" fill="#f4c4e2"/><path d="M 325.3543 619.20392 C 323.02374 619.20392 321.13193 617.36005 321.13193 615.08856 C 321.13193 612.81653 323.02374 610.97327 325.3543 610.97327 C 327.68488 610.97327 329.5767 612.81653 329.5767 615.08856 C 329.5767 617.36005 327.68488 619.20392 325.3543 619.20392 Z" stroke="#ce81b0" stroke-linecap="butt" stroke-linejoin="bevel" stroke-width="2"/></g></g></svg>
It allows participants to build their own distinct universe of knowledge or understanding, a space that is entirely under their own control. Spaces can link to one another, and take feeds from each other, to discuss and share content and ideas. It allows people to listen to the people they trust, and be heard by everyone. The aggregate of these individual spaces is a rich ecosystem of knowledge and discussion.
/***
|''Name:''|TiddlySpaceLinkPlugin|
|''Description:''|Formatter to reference other spaces from wikitext |
|''Author:''|PaulDowney (psd (at) osmosoft (dot) com) |
|''Source:''|http://whatfettle.com/2008/07/TiddlySpaceLinkPlugin/ |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/PaulDowney/plugins/TiddlySpaceLinkPlugin/ |
|''Version:''|0.6|
|''License:''|[[BSD License|http://www.opensource.org/licenses/bsd-license.php]] |
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''~CoreVersion:''|2.4|
!!Documentation
This plugin provides wikitext formatters for referencing another [[space|Space]] on the same TiddlySpace server, as in the following examples:
{{{@space}}} -- @psd
{{{~@space}}} -- ~@psd
{{{Tiddler@space}}} -- Tiddler@glossary
{{{[[Tiddler Name]]@space}}} -- [[How do I link to another space?]]@faq
{{{[[Link text|Tiddler Name]]@space}}} -- [[about spaces|Space]]@glossary
TiddlySpace includes the [[TiddlySpaceLinkPlugin]] which provides WikiText markup for linking to other spaces on the same server. For example @glossary is a link to the {{{glossary}}} [[space|Space]] and [[Small Trusted Group]]@glossary a link to an individual tiddler in the @glossary space. Prefixing the link with a tilde escapes the link, for example {{{~@space}}}. Email addresses, for example joe.bloggs@example.com and mary@had.a.little.lamb.org should be unaffected.
!!Code
***/
//{{{
/*jslint onevar: false nomen: false plusplus: false */
/*global jQuery config createTiddlyText createExternalLink */
function createSpaceLink(place, spaceName, title, alt) {
var link, a;
try {
// seems safe to expect this to have been initialised within TiddlySpace
link = config.extensions.tiddlyweb.status.server_host.url;
} catch (ex) {
link = "http://tiddlyspace.com";
}
// assumes a http URI without user:pass@ prefix
link = link.replace("http://", "http://" + spaceName.toLowerCase() + ".");
if (title) {
a = createExternalLink(place, link + "#" + encodeURIComponent(String.encodeTiddlyLink(title)), alt || title);
} else {
a = createExternalLink(place, link, spaceName);
}
jQuery(a).addClass('tiddlySpaceLink');
}
(function ($) {
version.extensions.TiddlySpaceLinkPlugin = {installed: true};
config.textPrimitives.spaceName = "[a-zA-Z][a-zA-Z0-9-]*";
config.textPrimitives.spaceNameStrict = "[a-z][a-z0-9-]*";
config.formatters.splice(0, 0, {
name: "spacenameLink",
match: config.textPrimitives.unWikiLink + "?" + config.textPrimitives.anyLetter + "*@" + config.textPrimitives.spaceName + ".?",
lookaheadRegExp: new RegExp(config.textPrimitives.unWikiLink + "?(" + config.textPrimitives.anyLetter + "*)@(" + config.textPrimitives.spaceName + ")", "mg"),
handler: function (w) {
if (w.matchText.substr(w.matchText.length-1, 1) === '.') {
w.outputText(w.output, w.matchStart, w.nextMatch);
return;
}
if (w.matchText.substr(0, 1) === config.textPrimitives.unWikiLink) {
w.outputText(w.output, w.matchStart + 1, w.nextMatch);
return;
}
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if (lookaheadMatch && lookaheadMatch.index === w.matchStart) {
createSpaceLink(w.output, lookaheadMatch[2], lookaheadMatch[1]);
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
},
{
name: "tiddlyLinkSpacenameLink",
match: "\\[\\[[^\\[]*\\]\\]@",
lookaheadRegExp: new RegExp("\\[\\[(.*?)(?:\\|(.*?))?\\]\\]@(" + config.textPrimitives.spaceName + ")", "mg"),
handler: function (w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if (lookaheadMatch && lookaheadMatch.index === w.matchStart) {
var title = lookaheadMatch[2] || lookaheadMatch[1];
var alt = lookaheadMatch[1] || lookaheadMatch[2];
createSpaceLink(w.output, lookaheadMatch[3], title, alt);
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
});
}(jQuery));
//}}}
[[About|TiddlySpace]] · [[FAQ|http://faq.tiddlyspace.com]] · [[Contact|http://osmosoft.com]] · [[Source|http://github.com/TiddlySpace/tiddlyspace]]
You can associate your account with multiple identities. If you have an open id for example you could log into TiddlySpace with that as well as a TiddlySpace user account.
{{inlineList{
<<TiddlySpaceIdentities>>
}}}
This space includes the public tiddlers from the following spaces:
<<TiddlySpaceInclusion list>>
<<TiddlySpaceInclusion passive>>
discoursive, social TiddlyWiki
/***
|''Name''|TiddlySpaceRevisionView|
|''Description''|Show tiddler revisions in a stack of cards view|
|''Author''|BenGillies|
|''Version''|0.1.1|
|''Status''|beta|
|''Source''|http://github.com/TiddlySpace/tiddlyspace|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Requires''|TiddlyWebAdaptor|
!Usage
The viewRevisions macro can be attached to any element, which should be passed
in as a parameter.
For example:
<<viewRevisions page:10 link:"<<view modified date>>">>
would show the revisions "stack of cards" view, 10 at a time, when the modified
date is clicked.
!Code
***/
//{{{
(function($) {
var me;
config.macros.viewRevisions = me = {
revisionTemplate: "RevisionTemplate",
revSuffix: " [rev. #%0]",
defaultPageSize: 10,
defaultLinkText: "View Revisions",
offsetTop: 30, //in px
offsetLeft: 10, //in px
shiftDownDelay: 50, //in ms
visibleSlideAmount: 20, //amount of revisions to show on left hand edge after sliding
zIndex: 100, //default z-index
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
params = paramString.parseParams(null, null, true)[0];
var tiddlerElem = story.findContainingTiddler(place);
//var revButton = $('<span class="button openRevisions" />')
var revButton;
var pageSize = parseInt(params.page[0], 10) || me.defaultPageSize;
var linkObj = params.link ? params.link[0] || me.defaultLinkText : false;
if(linkObj) {
revButton = $('<span class="button openRevisions" />')
.appendTo(place);
wikify(linkObj, revButton[0], null, tiddler);
} else {
revButton = place;
}
//wikify(linkObj, revButton[0], null, tiddler);
$(revButton).click(function() {
if (!$(tiddlerElem).hasClass("revisions")) {
me.showRevisions(tiddlerElem, tiddler, pageSize);
} else {
me.closeRevisions(tiddlerElem);
}
});
},
showRevisions: function(tiddlerElem, tiddler, pageSize) {
var context = {
host: tiddler.fields["server.host"],
workspace: tiddler.fields["server.workspace"]
};
$(tiddlerElem).addClass('revisions');
$(tiddlerElem).attr("revName", tiddler.title);
$("a", ".toolbar", tiddlerElem).each(function(index, btn) {
var _onclick = btn.onclick;
$(btn).click(function() {
me.closeRevisions(tiddlerElem);
_onclick.apply(this, arguments);
});
});
var type = tiddler.fields["server.type"];
var adaptor = new config.adaptors[type]();
var userParams = {
tiddlerElem: tiddlerElem,
pageSize: pageSize,
title: tiddler.title
};
me.createCloak(tiddlerElem);
adaptor.getTiddlerRevisionList(tiddler.title, null, context, userParams,
function (context, userParams) {
//strip the current revision
context.revisions.shift();
me.expandStack(context, userParams);
});
},
showRevision: function(place, revision, callback) {
var context = {
host: revision.fields["server.host"],
workspace: revision.fields["server.workspace"]
};
var userParams = {
revElem: place
};
var type = revision.fields["server.type"];
var adaptor = new config.adaptors[type]();
var revNo = revision.fields["server.page.revision"];
adaptor.getTiddlerRevision(revision.title, revNo, context, userParams,
function(context, userParams) {
var tiddler = context.tiddler;
tiddler.title += me.revSuffix
.format([$(place).attr("revision")]);
tiddler.fields.doNotSave = true;
if (store.getTiddler(tiddler.title)) {
store.deleteTiddler(tiddler.title);
}
store.addTiddler(tiddler);
//now, populate the existing div
var revElem = userParams.revElem;
$(revElem).attr('id', story.tiddlerId(tiddler.title));
$(revElem).attr("refresh", "tiddler");
story.refreshTiddler(tiddler.title, me.revisionTemplate, true);
callback(tiddler);
});
},
createCloak: function(promoteElem) {
//store for later
$(promoteElem).attr("zindex", $(promoteElem).css("z-index"));
$(promoteElem).attr("top", $(promoteElem).css("top"));
$(promoteElem).attr("left", $(promoteElem).css("left"));
$('<div class="revisionCloak" />').css("z-index", me.zIndex)
.click(function() {
me.closeRevisions(promoteElem);
})
.appendTo(document.body);
$(promoteElem).css("z-index", me.zIndex + 1);
},
closeRevisions: function(promoteElem) {
//revert the original tiddler back to its previous state
$(promoteElem)
.css("z-index", $(promoteElem).attr("zindex"))
.css("top", $(promoteElem).attr("top"))
.css("left", $(promoteElem).attr("left"))
.removeAttr("zindex")
.removeAttr("top")
.removeAttr("left")
.removeAttr("revName")
.removeClass("revisions");
//delete the previous revisions
$(".revisions").remove();
//remove the cloak
$(".revisionCloak").remove();
},
expandStack: function(context, userParams) {
var pageSize = userParams.pageSize;
var from = userParams.from || 0;
var tiddlerElem = userParams.tiddlerElem;
userParams.defaultHeight = $(tiddlerElem).height();
userParams.defaultWidth = $(tiddlerElem).width();
if (from < context.revisions.length) {
me.displayNextRevision(tiddlerElem, userParams, context, from,
from + pageSize - 1);
}
},
displayNextRevision: function(tiddlerElem, userParams, context, from, to) {
var revision = context.revisions[from];
function callback() {
var revText = revBtn.getRevisionText(tiddlerElem, revision);
tiddlerElem = me.createRevisionObject(tiddlerElem, context,
userParams, revText);
$(tiddlerElem)
.attr("revision", (context.revisions.length - from));
if ((from < to) && ((from + 1) < context.revisions.length)){
me.displayNextRevision(tiddlerElem, userParams, context,
from + 1, to);
} else if ((context.revisions.length - 1) > to) {
me.showMoreButton(tiddlerElem, context, userParams, to + 1);
}
}
me.shiftVisibleDown(userParams.title, callback);
},
createRevisionObject: function(tiddlerElem, context, userParams, text) {
var newPosition = me.calculatePosition(tiddlerElem, context);
return $('<div class="revisions tiddler" />')
.css({
position: "absolute",
top: newPosition.top,
left: newPosition.left,
"z-index": me.zIndex + 1,
height: userParams.defaultHeight,
width: userParams.defaultWidth
})
.attr("revName", userParams.title)
.append(text)
.insertBefore(tiddlerElem);
},
shiftVisibleDown: function(title, callback) {
var revisions = $("[revName=%0].revisions".format([title]));
var revisionCount = revisions.length;
$(revisions).animate({top: "+=" + me.offsetTop},
me.shiftDownDelay, function() {
revisionCount -= 1;
if ((callback) && (!revisionCount)) {
callback();
}
});
},
calculatePosition: function(elem, context) {
var offset = $(elem).offset();
var currentPosition = $(elem).position();
var newPosition = {
top: currentPosition.top - me.offsetTop
};
if ((context.restrictLeft) ||
((offset.left - me.offsetLeft) <
$("#contentWrapper").offset().left)) {
newPosition.left = 0;
context.restrictLeft = true;
} else {
newPosition.left = currentPosition.left - me.offsetLeft;
}
return newPosition;
},
showMoreButton: function(tiddlerElem, context, userParams, moreIndex) {
userParams.from = moreIndex + 1;
me.shiftVisibleDown(userParams.title, function() {
var btn = me.createRevisionObject(tiddlerElem, context, userParams,
"");
var more = createTiddlyButton(btn[0], "more...", "show more revisions",
function() {
if ($(".viewRevision").length) {
return;
}
userParams.tiddlerElem = btn[0];
$(btn).text("")
.append(revBtn
.getRevisionText(btn[0], context.revisions[moreIndex]))
.attr("revision", context.revisions.length - moreIndex);
me.expandStack(context, userParams);
});
$(more).css("float", "right");
});
},
stripRevFromTitle: function(revisionTitle) {
return revisionTitle.split(/ ?\[rev\. #[0-9]+\]$/)[0];
},
onClickRevision: function(revElem, revision, callback) {
// don't do anything if we are still loading
if ($(".revisions").hasClass("loading")) {
return null;
}
var origTitle = me.stripRevFromTitle(revision.title);
if ($(revElem).hasClass("viewRevision")) {
$(".revisions").addClass("loading");
me.slideIn(revElem, revision, origTitle, function() {
store.deleteTiddler(revision.title);
revision.title = origTitle;
$(revElem).text("").append(revBtn.getRevisionText(revElem,
revision))
.removeAttr("tags").removeAttr("tiddler")
.removeAttr("refresh").removeAttr("template")
.removeAttr("id");
$(".revisions").removeClass("loading");
if (callback) {
callback();
}
});
$(revElem).removeAttr("prevPos").removeClass("viewRevision");
} else {
var viewRevision = function() {
var prevPos = $(revElem).offset().left;
$(revElem).addClass("viewRevision").attr("prevPos", prevPos);
$(".revisions").addClass("loading");
me.showRevision(revElem, revision, function(rev) {
me.slideOut(revElem, rev, origTitle, function() {
$(".revisions").removeClass("loading");
});
});
};
//make sure another revision isn't already out
if ($(".viewRevision").length) {
var newRevElem = $(".viewRevision")[0];
var newRevision = store.getTiddler($(newRevElem)
.attr("tiddler"));
me.onClickRevision(newRevElem, newRevision, viewRevision);
} else {
viewRevision();
}
}
},
slideOut: function(revElem, revision, title, callback) {
var leftMostPos = $("[revName=%0].revisions".format([title]))
.offset().left;
var width = $(revElem).width();
var originalLeftPos = $(story.getTiddler(title))
.offset().left;
var slideAmount = leftMostPos + width - me.visibleSlideAmount;
$("[revName=%0].revisions:not(.viewRevision)".format([title]))
.animate({left: "-=" + slideAmount}, 1000);
$(revElem)
.attr("baseHeight", $(revElem).css("height"))
.css("height", "auto")
.animate({left: originalLeftPos}, 1000, callback);
},
slideIn: function(revElem, revision, title, callback) {
var slideAmount = $(revElem).offset().left -
$(story.getTiddler(title)).offset().left;
var origRevPos = $(revElem).attr("prevPos");
$("[revName=%0].revisions:not(.viewRevision)".format([title]))
.animate({left: "+=" + slideAmount}, 1000);
$(revElem).animate({left: origRevPos}, 1000, function() {
$(revElem)
.css("height", $(revElem).attr("baseHeight"))
.removeAttr("baseHeight");
callback();
});
}
};
var revBtn;
config.macros.slideRevision = revBtn = {
btnText: "created by %0 at %1 on %2",
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var btn = revBtn.getRevisionText(place, tiddler);
$(place).append(btn);
},
getRevisionText: function(place, revision) {
var text = revBtn.btnText.format([revision.modifier,
revision.modified.formatString("0hh:0mm"),
revision.modified.formatString("0DD MMM YYYY")]);
var btn = $('<a href="javascript:;" class="button revButton" />')
.text(text)
.click(function() {
var revElem = story.findContainingTiddler(this);
me.onClickRevision(revElem, revision);
});
return btn;
}
};
})(jQuery);
//}}}
#tiddlerAuthorization .title { /* hack to hide redundant title */
display: none;
}
[[BubblesCss]]
[[StyleSheetToolbar]]
[[HeaderCss]]
.public_bubble {
position: relative;
border: 2px solid red;
background-color: #C7EAFF;
border: 4px solid #86B2CC;
-webkit-border-radius: 20em;
-moz-border-radius: 20em;
border-radius: 20em;
}
.private_bubble {
background-color: #FFCAE9;
border: 4px solid #E48CBF;
margin: 0 auto;
padding: 1em;
text-align: center;
-webkit-border-radius: 20em;
-moz-border-radius: 20em;
border-radius: 20em;
}
.bubble {
position: absolute;
z-index: 10;
padding: 3em;
-webkit-transition: -webkit-transform 1.0s ease-in-out;
}
.bubble:hover {
-webkit-transform: rotate(0deg) scale(2.0);
-moz-transform: rotate(0deg) scale(2.0);
transform: rotate(0deg) scale(2.0);
}
.bubble .private_bubble {
height: 1em;
width: 1em;
}
.small {
padding: 1.5em;
}
.small .private_bubble {
height: 0.1em;
width: 0.1em;
}
.medium {
padding: 2em;
}
.medium .private_bubble {
height: 0.5em;
width: 0.5em;
}
#space1.public_bubble { top: 24em; left: 30em; z-index: 1; }
#space2.public_bubble { top: 6em; left: 24em; z-index: 1; }
#space3.public_bubble { bottom: 20em; left: 4em; z-index: 1; }
#space4.public_bubble { top: 3em; right: 76em; z-index: 1; }
#space5.public_bubble { bottom: 14em; left: 4em; z-index: 1; }
#space6.public_bubble { top: 28em; right: 77em; z-index: 1; }
#space7.public_bubble { top: 9em; right: 25em; z-index: 1; }
#space8.public_bubble { top: -3em; right: 39em; z-index: 1; }
#space9.public_bubble { bottom: 9em; right: 5em; z-index: 1; }
#space10.public_bubble { bottom: 29em; left: 35em; z-index: 1; }
#space11.public_bubble { bottom: 22em; left: 8em; z-index: 1; }
#space12.public_bubble { bottom: 7em; right: 12em; z-index: 1; }
#space13.public_bubble { bottom: 13em; left: 33em; z-index: 1; }
#space14.public_bubble { top: 19em; right: 35em; z-index: 1; }
#space15.public_bubble { bottom: 23em; left: 33em; z-index: 1; }
#space16.public_bubble { bottom: 15em; right: 9em; z-index: 1; }
#space17.public_bubble { top: 12em; left: 10em; z-index: 1; }
#space18.public_bubble { top: 9em; left: 36em; z-index: 1; }
#space19.public_bubble { top: 20em; left: 25em; z-index: 1; }
#space20.public_bubble { bottom: 34em; right: 59em; z-index: 1; }
#space21.public_bubble { top: 20em; right: 81em; z-index: 1; }
#space22.public_bubble { bottom: 4em; left: -3em; z-index: 1; }
#space23.public_bubble { bottom: 14em; left: 28em; z-index: 1; }
#space24.public_bubble { top: 16em; right: 51em; z-index: 1; }
#space25.public_bubble { top: 20em; right: 49em; z-index: 1; }
#space26.public_bubble { bottom: 25em; right: 2em; z-index: 1; }
#space27.public_bubble { bottom: 30em; right: 46em; z-index: 1; }
#space28.public_bubble { top: 24em; left: 22em; z-index: 1; }
#space29.public_bubble { top: 22em; right: 85em; z-index: 1; }
#space30.public_bubble { top: 18em; left: 33em; z-index: 1; }
TiddlySpot is a mature, popular service focused on publishing and sharing entire TiddlyWiki documents. TiddlySpace is more experimental, and directed towards publishing and sharing individual tiddlers between documents.
/***
|''Name''|TiddlySpaceToolbar|
|''Description''|augments tiddler toolbar commands with SVG icons|
|''Author''|Osmosoft|
|''Version''|0.6.2|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceToolbar.js|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|ImageMacroPlugin|
|''Keywords''|toolbar icons SVG|
!Description
replaces tiddler toolbar commands with SVG icons if available
!Notes
requires [[ImageMacroPlugin|http://svn.tiddlywiki.org/Trunk/contributors/JonRobson/plugins/ImageMacroPlugin/plugins/ImageMacroPlugin.tid]]
SVG icons are drawn from tiddlers titled {{{<command>.svg}}}
!TODO
* rename (IconToolbarPlugin?)
!Code
***/
//{{{
(function($) {
if(!config.macros.image) {
throw "Missing dependency: ImageMacroPlugin";
}
var macro = config.macros.toolbar;
macro.icons = {
cloneTiddler: "editTiddler"
};
var _handler = macro.handler;
macro.handler = function(place, macroName, params, wikifier,
paramString, tiddler) {
var toolbar = $(place);
toolbar.attr({
refresh: "macro",
macroName: macroName
}).data("args", arguments);
var status = _handler.apply(this, arguments);
if(tiddler.isReadOnly()) {
toolbar.addClass("toolbarReadOnly");
} else {
toolbar.removeClass("toolbarReadOnly");
}
var parsedParams = paramString.parseParams("name")[0];
if(parsedParams.icons && parsedParams.icons == "yes") {
this.augmentCommandButtons(place);
}
if(parsedParams.more && parsedParams.more == "popup") {
// note we must override the onclick event like in createTiddlyButton
// otherwise the click event is the popup AND the slider
$(".moreCommand", place)[0].onclick = macro.onClickMorePopUp;
}
return status;
};
macro.refresh = function(place, params) {
var args = $(place).empty().data("args");
this.handler.apply(this, args);
};
var imageMacro = config.macros.image;
macro.augmentCommandButtons = function(toolbar) {
$(".button", toolbar).each(function(i, el) {
var cmd = $(el).attr("commandname");
cmd = cmd ? cmd : "moreCommand"; // XXX: special-casing of moreCommand due to ticket #1234
var icon = store.tiddlerExists(cmd) ? cmd : macro.icons[cmd];
var text = $(el).text();
if(store.tiddlerExists(icon)) {
$(el).empty();
imageMacro.renderImage(el, icon, { alt: text });
}
});
};
// provide onClickMore to provide extra commands in a popup
macro.onClickMorePopUp = function(ev) {
ev = ev || window.event;
var sibling = this.nextSibling;
var commands = sibling.childNodes;
var popup = Popup.create(this);
addClass(popup ,"taggedTiddlerList");
for(var i = 0; i < commands.length; i++) {
var li = createTiddlyElement(popup, "li", null);
var oldCommand = commands[i];
var command = oldCommand.cloneNode(true);
command.onclick = oldCommand.onclick;
li.appendChild(command);
}
Popup.show();
ev.cancelBubble = true;
if(ev.stopPropagation) {
ev.stopPropagation();
}
return false;
};
})(jQuery);
//}}}
//{{{
(function($) {
// override Scroller to ensure that the screen scrolls to a desired height
// in this case, we want it to scroll almost (but not quite) 1 entire screen
_Scroller = Scroller; // keep original, just in case...
Scroller = function(targetElement) {
var offset = 50;
var endPoint = ensureVisible(targetElement);
var minScroll = $("#footer").offset().top - offset;
if(endPoint < minScroll) {
endPoint = minScroll;
}
// make sure the page has enough space to scroll into
var tiddlerDisplay = $("#tiddlerDisplay");
if($(tiddlerDisplay).height() < (screen.height - offset)) {
$(tiddlerDisplay).height(screen.height - offset);
}
var p = [{ style: "-tw-vertScroll", start: findScrollY(), end: endPoint }];
return new Morpher(targetElement, config.animDuration, p);
};
// add a macro to set the appropriate login form to open by default before
// loading the login tiddler
config.macros.TiddlySpaceLoginLoader = {
handler: function(place, macro, params, wikifier, paramString, tiddler) {
var cookie = "taggedTabs";
createTiddlyButton(place, params[1], params[1], function() {
var tabbedSignUp = $(".taggedTabs");
if(tabbedSignUp.length) { // it is already visible
config.macros.tabs.switchTab(tabbedSignUp[0], params[1]);
} else {
config.options[cookie] = params[1];
}
story.displayTiddler(place, params[0]);
}, "tiddlyLinkExisting");
}
};
})(jQuery);
//}}}
/***
http://github.com/tiddlyweb/chrjs/raw/master/users.js
***/
//{{{
// chrjs users extension
// v0.4.0
//
// requires tiddlywebplugins.socialusers
// http://pypi.python.org/pypi/tiddlywebplugins.socialusers
(function($) {
tiddlyweb.routes.users = "{host}/users";
tiddlyweb.routes.user = "{host}/users/{username}";
tiddlyweb.User = function(username, password, host) {
tiddlyweb.Resource.apply(this, ["user", host]);
this.username = username;
this.password = password;
};
tiddlyweb.User.prototype = new tiddlyweb.Resource();
$.extend(tiddlyweb.User.prototype, {
create: function(callback, errback) {
var uri = this.route().split("/"); // XXX: hacky!?
uri.pop();
uri = uri.join("/");
var data = {
username: this.username,
password: this.password
};
var self = this;
return $.ajax({
url: uri,
type: "POST",
contentType: "application/json",
data: $.toJSON(data),
success: callback,
error: function(xhr, error, exc) {
errback(xhr, error, exc, self);
}
});
},
setPassword: function(newPass, callback, errback) {
this.old_password = this.password; // XXX: should not use underscore (consistency)
this.password = newPass;
return this.put(callback, errback);
},
data: ["password", "old_password"]
});
})(jQuery);
//}}}
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]] icons:yes'></div>
<div class='heading'>
<div class='spaceSiteIcon' macro='tiddlerOrigin label:yes height:48 width:48'></div>
<div class='modifierIcon'
macro='view modifier SiteIcon label:yes height:48 width:48 labelPrefix:"last modified by "'>
</div>
<div class='editor title' macro='edit title'></div>
<div class='tagClear'></div>
</div>
<div class='annotationsBox' macro='annotations'>
<div macro='setPrivacy'></div>
</div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div>
<div class='editorFooter'>
<span macro='message views.editor.tagPrompt'></span>
<span macro='tagChooser excludeLists'></span>
</div>
<!--}}}-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="450 366 38 57"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 452.1094 421.2422 L 450 421.2422 L 450 423 L 487.9688 423 L 487.9688 421.2422 L 485.8595 421.2422
L 485.8595 377.29688 L 487.9688 377.29688 L 487.9688 375.53906 L 485.8595 375.53906
C 485.8595 375.53906 481.12463 371.59341 473.02023 370.52802 C 472.6824 368.9689 471.72098 366.75 468.9844 366.75
C 466.24783 366.75 465.28638 368.9689 464.94864 370.52802
C 456.84418 371.59341 452.1094 375.53906 452.1094 375.53906 L 450 375.53906 L 450 377.29688 L 452.1094 377.29688
Z M 467.12247 370.32086 L 467.12247 370.32086 C 467.3805 369.42395 467.90762 368.50781 468.9844 368.50781
C 470.0612 368.50781 470.5883 369.42395 470.84634 370.32086
C 470.24136 370.2848 469.62054 370.26562 468.9844 370.26562
C 468.34827 370.26562 467.72748 370.2848 467.12247 370.32086 Z M 454.21875 420.92804 L 454.21875 420.92804
C 455.46762 420.42087 456.32816 419.35281 456.32816 418.11716 L 456.32816 377.29688 L 458.4375 377.29688
L 458.4375 421.2422 L 454.21875 421.2422 Z M 460.5469 420.92804 L 460.5469 420.92804
C 461.79578 420.42087 462.65625 419.35281 462.65625 418.11716 L 462.65625 377.29688 L 464.76566 377.29688
L 464.76566 421.2422 L 460.5469 421.2422 Z M 466.87503 420.92804 L 466.87503 420.92804
C 468.1239 420.42087 468.9844 419.35281 468.9844 418.11716 L 468.9844 377.29688 L 471.09378 377.29688
L 471.09378 421.2422 L 466.87503 421.2422 Z M 473.2032 420.92804 L 473.2032 420.92804
C 474.45203 420.42087 475.31256 419.35281 475.31256 418.11716 L 475.31256 377.29688 L 477.4219 377.29688
L 477.4219 421.2422 L 473.2032 421.2422 Z M 479.5313 420.92804 L 479.5313 420.92804
C 480.78018 420.42087 481.64066 419.35281 481.64066 418.11716 L 481.64066 377.29688 L 483.75006 377.29688
L 483.75006 421.2422 L 479.5313 421.2422 Z" fill="black" class="glyph"/>
</g>
</g>
</svg>
/***
|''Name''|RandomColorPalettePlugin|
|''Description''|Adds a random color palette to TiddlyWiki|
|''Author''|Jon Robson|
|''Version''|1.2.4|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/contributors/JonRobson/plugins/RandomColorPalettePlugin/RandomColorPalettePlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
!Usage
{{{
<<RandomColorPalette>>
Sets and saves a random color palette on execution
<<RandomColorPaletteButton>>
Creates a button, which when clicked will change the color palette
}}}
!Parameters
rgb: yes
By default the ColorPalette is defined in hex. You can output the colours as rgb by simply including this parameter.
hue:[0,360]
Seeds the randomiser with this hue.
saturation:[0,1]
Seeds the randomiser with a given saturation
lightness:[0,1]
Seeds the randomiser with a value for the lightest color tone (0 being darkest, 1 being lightest).
darkest:[0,1]
Seeds the randomiser with a value for the darkest color tone (0 being darkest, 1 being lightest).
huevariance: [0,90]
Given a certain hue, specify the angle from the secondary colour to which the secondary and tertiary colours should be determined.
Note parameters can be discovered by viewing the ColorPaletteParameter slice within the generated ColorPalette.
!Code
***/
//{{{
(function($){
RGB.prototype.toRGBString = function() {
return "rgb(%0,%1,%2)".format([parseInt(this.r * 255, 10),
parseInt(this.g * 255, 10), parseInt(this.b * 255, 10)])
}
function HSL_TO_RGB(h, s, l){ // h (hue) between 0 and 360, s (saturation) & l (lightness) between 0 and 1
var c;
if(l <= 0.5) {
c = 2 * l * s;
} else {
c = ( 2 - (2 * l)) * s;
}
var h1 = h / 60;
var x = c * (1 - Math.abs((h1 % 2) - 1));
var r, g, b;
if(typeof(h) == 'undefined') {
r = 0;
g = 0;
b = 0;
} else if(0 <= h1 && h1 < 1) {
r = c;
g = x;
b = 0;
} else if(1 <= h1 && h1 < 2) {
r = x;
g = c;
b = 0;
} else if(2 <= h1 && h1 < 3) {
r = 0;
g = c;
b = x;
}
else if(3 <= h1 && h1 < 4) {
r = 0;
g = x;
b = c;
} else if(4 <= h1 && h1 < 5) {
r = x;
g = 0;
b = c;
} else if(5 <= h1 && h1 < 6) {
r = c;
g = 0;
b = x;
}
m = l - (0.5 * c);
r += m;
g += m;
b += m;
return new RGB(r, g, b);
}
var macro = config.macros.RandomColorPalette = {
messagesOn: false,
changedPaletteText: "We have assigned you a random theme by adjusting the [[ColorPalette]] tiddler.\nDon't like it? Click <<RandomColorPalette>> for another one.",
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
paramString = paramString || "";
var options = paramString.parseParams("name", null, true, false, true)[0];
var tiddler = macro.generatePalette(options, true);
},
generateRandomNumber: function(min, max, info) {
var num = (Math.random() * 1);
if(!info) {
info = { attempts:0 };
}
info.attempts += 1;
var good = true;
if(min == max) return max;
if(min && num < min) {
good = false;
} else if(max && num > max) {
good = false;
}
if(!good) {
if(info.attempts < 5) {
return macro.generateRandomNumber(min, max, info);
} else {
if(max) {
return max;
} else if(min) {
return min;
} else {
return 1;
}
}
}
return num;
},
getExistingPalette: function(asJSON) {
var title = "ColorPalette";
var tiddlerText;
if(store.tiddlerExists(title)) {
tiddlerText = store.getTiddlerText(title);
} else if(store.isShadowTiddler(title)){
tiddlerText = config.shadowTiddlers[title];
}
if(asJSON) {
var json = {};
if(tiddlerText) {
var lines = tiddlerText.split("\n");
for(var i = 0; i < lines.length; i++) {
var definition = lines[i].split(":");
if(definition.length == 2) {
var name = definition[0].trim();
var value = definition[1].trim();
json[name] = value;
}
}
}
return json;
} else {
return tiddlerText;
}
},
generatePalette: function(options, save) {
var outputRGB = options.rgb && options.rgb[0];
if(this.inprogress) {
return;
}
this.inprogress = true;
var palette = macro.getExistingPalette(true);
var hue = options.hue ? parseInt(options.hue[0]) : Math.floor(Math.random() * 359);
var saturation = options.saturation ? parseFloat(options.saturation[0]) : macro.generateRandomNumber(0.3, 0.7);
var dark = options.darkest ? parseFloat(options.darkest[0]) : macro.generateRandomNumber(0, 0.1);
var pale = options.lightness ? parseFloat(options.lightness[0]) : macro.generateRandomNumber(0.6 + dark, 1);
var lightness_values = {Dark:dark, Mid:pale - ( ( pale - dark ) / 2 ),
Light:pale - ( ( pale - dark ) / 4 ), Pale:pale};
var opposite_hue = (hue + 180) % 360;
var seed = options.huevariance ? options.huevariance[0] : Math.floor((85 * Math.random()) + 5); // we want it to be at least 5 degrees
var huetwo = (opposite_hue + seed) % 360;
var huethree = (opposite_hue - seed) % 360;
if(huetwo < 0) {
huetwo = 360 + huetwo;
}
if(huethree < 0) {
huethree = 360 + huethree;
}
for(var j in lightness_values) {
if(true) {
palette["Primary" + j] = HSL_TO_RGB(hue, saturation, lightness_values[j]);
palette["Secondary" + j] = HSL_TO_RGB(huetwo, saturation, lightness_values[j]);
palette["Tertiary" + j] = HSL_TO_RGB(huethree, saturation, lightness_values[j]);
}
}
palette.Background = HSL_TO_RGB(hue, saturation, 0.92);
palette.Foreground = HSL_TO_RGB(hue, saturation, 0.08);
palette.ColorPaletteParameters = ["HSL([", hue, "|", seed, "], [", saturation, "],",
"[", dark, "|", pale, "])"].join("");
// construct new ColorPalette
var text = ["/*{{{*/\n"];
var colorcode;
for(var id in palette) {
if(true) {
var color = palette[id];
if(outputRGB) {
colorcode = color.toRGBString();
} else {
colorcode = color.toString();
}
text.push("%0: %1\n".format([id, colorcode]));
}
}
text.push("/*}}}*/");
var tid = store.getTiddler('ColorPalette');
if(!tid) {
tid = new Tiddler('ColorPalette');
tid.fields = merge({}, config.defaultCustomFields);
tid.modifier ='RandomColorPalette Macro';
} else {
// save location may be different
tid.fields = merge(tid.fields, config.defaultCustomFields);
}
tid.text = text.join("");
this.inprogress = false;
if(save) {
macro.saveColorPalette(tid);
}
return tid;
},
saveColorPalette: function(tid) {
// save the color palette in tid
tid = store.saveTiddler(tid.title, tid.title, tid.text, tid.modifier, tid.modified,
tid.tags, tid.fields, false, tid.created, '');
// an interval is used to cope with users clicking on the palette button quickly.
if(macro._nextSave) {
window.clearTimeout(macro._nextSave);
}
macro._nextSave = window.setTimeout(function() {
autoSaveChanges(null, [tid]);
}, 2000);
refreshAll();
macro.reportChange();
},
reportChange: function() {
if(macro.messagesOn) { // only display message once..
var msgPlace = getMessageDiv();
if(!$(".changedPalette", msgPlace)[0]) {
var tempPlace = document.createElement("div");
wikify("{{changedPalette{" + macro.changedPaletteText + "}}}", tempPlace);
msgPlace.appendChild(tempPlace);
}
}
}
};
config.macros.RandomColorPaletteButton = {
text: "New ColorPalette",
tooltip: "Generate a random colour scheme for your TiddlyWiki",
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var btnHandler = function() {
config.macros.RandomColorPalette.handler(place, macroName, params, wikifier, paramString, tiddler);
};
createTiddlyButton(place, this.text, this.tooltip, btnHandler);
}
};
})(jQuery);
//}}}
[[What does TiddlySpace do?]]
[[What is the point of TiddlySpace?]]
[[What is the different between TiddlySpace and TiddlySpot?]]
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="78 222 60 60"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 107.92718 244.14815 L 86.651474 222.89253 L 78.85206 230.69925 L 100.120415 251.9476 L 78.774 273.27396
L 86.57342 281.08075 L 107.927216 259.74707 L 129.39981 281.19946 L 137.19922 273.39267 L 115.73397 251.94763
L 137.121155 230.58054 L 129.32175 222.77374 Z" fill="black" class="glyph"/>
</g>
</g>
</svg>
/***
|''Name''|TiddlyWebConfig|
|''Description''|configuration settings for TiddlyWebWiki|
|''Author''|FND|
|''Version''|1.3.1|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/TiddlyWebConfig.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Requires''|TiddlyWebAdaptor ServerSideSavingPlugin|
|''Keywords''|serverSide TiddlyWeb|
!Code
***/
//{{{
(function($) {
if(!config.extensions.ServerSideSavingPlugin) {
throw "Missing dependency: ServerSideSavingPlugin";
}
if(!config.adaptors.tiddlyweb) {
throw "Missing dependency: TiddlyWebAdaptor";
}
if(window.location.protocol != "file:") {
config.options.chkAutoSave = true;
}
var adaptor = tiddler.getAdaptor();
var recipe = tiddler.fields["server.recipe"];
var workspace = recipe ? "recipes/" + recipe : "bags/common";
var plugin = config.extensions.tiddlyweb = {
host: tiddler.fields["server.host"].replace(/\/$/, ""),
username: null,
status: {},
getStatus: null, // assigned later
getUserInfo: function(callback) {
this.getStatus(function(status) {
callback({
name: plugin.username,
anon: plugin.username == "GUEST"
});
});
},
hasPermission: function(type, tiddler) {
var perms = tiddler.fields["server.permissions"];
if(perms) {
return perms.split(", ").contains(type);
} else {
return true;
}
}
};
config.defaultCustomFields = {
"server.type": tiddler.getServerType(),
"server.host": plugin.host,
"server.workspace": workspace
};
// modify toolbar commands
config.shadowTiddlers.ToolbarCommands = config.shadowTiddlers.ToolbarCommands.
replace("syncing ", "revisions syncing ");
config.commands.saveTiddler.isEnabled = function(tiddler) {
return plugin.hasPermission("write", tiddler) && !tiddler.isReadOnly();
};
config.commands.deleteTiddler.isEnabled = function(tiddler) {
return !readOnly && plugin.hasPermission("delete", tiddler);
};
// hijack option macro to disable username editing
var _optionMacro = config.macros.option.handler;
config.macros.option.handler = function(place, macroName, params, wikifier,
paramString) {
if(params[0] == "txtUserName") {
params[0] = "options." + params[0];
var self = this;
var args = arguments;
args[0] = $("<span />").appendTo(place)[0];
plugin.getUserInfo(function(user) {
config.macros.message.handler.apply(self, args);
});
} else {
_optionMacro.apply(this, arguments);
}
};
// hijack isReadOnly to take into account permissions and content type
var _isReadOnly = Tiddler.prototype.isReadOnly;
Tiddler.prototype.isReadOnly = function() {
return _isReadOnly.apply(this, arguments) ||
!plugin.hasPermission("write", this);
};
var getStatus = function(callback) {
if(plugin.status.version) {
callback(plugin.status);
} else {
var self = getStatus;
if(self.pending) {
if(callback) {
self.queue.push(callback);
}
} else {
self.pending = true;
self.queue = callback ? [callback] : [];
var _callback = function(context, userParams) {
var status = context.serverStatus || {};
for(var key in status) {
if(key == "username") {
plugin.username = status[key];
config.macros.option.propagateOption("txtUserName",
"value", plugin.username, "input");
} else {
plugin.status[key] = status[key];
}
}
for(var i = 0; i < self.queue.length; i++) {
self.queue[i](plugin.status);
}
delete self.queue;
delete self.pending;
};
adaptor.getStatus({ host: plugin.host }, null, _callback);
}
}
};
(plugin.getStatus = getStatus)(); // XXX: hacky (arcane combo of assignment plus execution)
})(jQuery);
//}}}
/***
|''Name''|ToggleTiddlerPrivacyPlugin|
|''Version''|0.5.7|
|''Status''|@@beta@@|
|''Description''|Allows you to set the privacy of new tiddlers and external tiddlers within an EditTemplate|
|''Requires''|TiddlySpaceConfig|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/ToggleTiddlerPrivacyPlugin.js|
!Notes
When used in conjunction with TiddlySpaceTiddlerIconsPlugin changing the privacy setting will also interact with any privacy icons.
Currently use of
<<setPrivacy defaultValue:public>> is in conflict with <<newTiddler fields:"server.workspace:x_private">>
!Params
defaultValue:[private|public]
Allows you to set the default privacy value (Default is private)
!Code
***/
//{{{
(function($) {
var tiddlyspace = config.extensions.tiddlyspace;
config.macros.setPrivacy = {
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
var el = $(story.findContainingTiddler(place));
var args = paramString.parseParams("name", null, true, false, true)[0];
var container = $("<div />").addClass("privacySettings").appendTo(place)[0];
var currentSpace = tiddlyspace.currentSpace.name;
var currentWorkspace = tiddler ? tiddler.fields["server.workspace"] : false;
var isNewTiddler = el.hasClass("missing") || !currentWorkspace; // XXX: is this reliable?
if(isNewTiddler || this.isExternal(tiddler)) {
var userDefault = args.defaultValue;
userDefault = userDefault ? "bags/%0_%1".format([currentSpace, userDefault[0]]) : false;
var defaultValue = currentWorkspace || userDefault || false;
var options = config.macros.tiddlerOrigin ?
config.macros.tiddlerOrigin.getOptions(params, paramString) : false;
this.createRoundel(container, tiddler, currentSpace, defaultValue, options);
}
},
isExternal: function(tiddler) {
var bag = tiddler.fields["server.bag"] || "";
var prefix = "%0_".format([tiddlyspace.currentSpace.name]);
return bag.indexOf(prefix) != 0 || bag == "tiddlyspace";
},
createRoundel: function(container, tiddler, currentSpace, defaultValue, options) {
var el = $(story.findContainingTiddler(container));
var originButton = $(".originButton", el)[0];
var privateWorkspace = "bags/%0_private".format([currentSpace]);
var publicWorkspace = "bags/%0_public".format([currentSpace]);
var rbtn = $("<input />").attr("type", "radio").attr("name", tiddler.title);
var rPrivate = rbtn.clone().val("private").addClass("isPrivate").appendTo(container);
$("<label />").text("private").appendTo(container); // TODO: i18n
var rPublic = rbtn.clone().val("public").addClass("isPublic").appendTo(container);
$("<label />").text("public").appendTo(container); // TODO: i18n
var status = "private";
var refreshIcon = function(type) {
var originMacro = config.macros.tiddlerOrigin;
if(originButton && originMacro) {
$(originButton).empty();
originMacro.showPrivacyRoundel(tiddler, type, originButton, null, options);
}
};
var setWorkspace = function(workspace) {
var saveField = $("[edit=server.workspace]", el);
if(!workspace) {
workspace = saveField.val();
}
if(workspace) {
saveField.val(workspace);
tiddler.fields["server.workspace"] = workspace; // for external tiddlers
if(workspace.indexOf("_public") > -1) {
rPublic.attr("checked", true);
rPrivate.attr("checked", false);
status = "public";
} else {
rPrivate.attr("checked", true);
rPublic.attr("checked", false); // explicitly do this for ie
status = "private";
}
refreshIcon(status);
}
};
$("[type=radio]", container).click(function() {
var btn = $(this);
tiddler.fields["server.page.revision"] = "false";
if(btn.hasClass("isPrivate")) { // private button clicked.
el.addClass("isPrivate").removeClass("isPublic");
setWorkspace(privateWorkspace);
} else {
el.addClass("isPublic").removeClass("isPrivate");
setWorkspace(publicWorkspace);
}
});
// TODO: replace with a hijack of displayTiddler?
window.setTimeout(function() {
setWorkspace(defaultValue);
}, 200); // not ideal - but need to wait till finished displayTiddler for brand new tiddlers
}
};
})(jQuery);
//}}}
/***
|''Name''|TiddlySpaceRevertRevision|
|''Description''|Revert to a previous revision|
|''Author''|BenGillies|
|''Version''|0.1|
|''Status''|unstable|
|''Source''|http://github.com/TiddlySpace/tiddlyspace|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.6.0|
|''Requires''|TiddlyWebAdaptor TiddlySpaceRevisionView|
!Usage
Add a control button to revert to a particular revision.
The button must be called from within a revision, as generated by TiddlySpaceRevisionView
!Code
***/
//{{{
(function($) {
config.commands.revert = {
text: "revert",
tooltip: "make this revision the current one",
handler: function(ev, src, title) {
var revElem = story.getTiddler(title);
var tidToRevert = store.getTiddler($(revElem).attr("revName"));
var revision = store.getTiddler(title);
if ((revision) && (tidToRevert)) {
tidToRevert.text = revision.text;
var newFields = merge({}, revision.fields);
for (var fieldName in newFields) {
if (fieldName.substr(0, 7) === "server.") {
delete newFields[fieldName];
}
}
merge(tidToRevert.fields, newFields);
tidToRevert.tags = merge([], revision.tags);
tidToRevert.fields.changecount = 1;
delete tidToRevert.fields.doNotSave;
store.saveTiddler(tidToRevert.title, tidToRevert.title,
tidToRevert.text, null, null, tidToRevert.tags,
tidToRevert.fields, false, tidToRevert.created, tidToRevert.creator);
autoSaveChanges(true);
}
}
};
})(jQuery);
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="2 724 68 55"
width="30" height="30">
<g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1">
<g>
<path d="M 2.25 756 L 11.25 747 L 24.75 760.4994 L 60.750004 724.4994 L 69.75 733.49902
L 24.749977 778.49976 Z" fill="#101010" class="glyph"/>
</g>
</g>
</svg>
{{public_bubble{
{{private_bubble{
{{siteTitle{TiddlySpace}}}
{{siteSubtitle{
discoursive, social
[[TiddlyWiki|http://tiddlywiki.com]]
}}}
{{login{
<<TiddlySpaceLoginLoader "Authorization" "Sign Up">>, or <<TiddlySpaceLoginLoader "Authorization" "Log In">>
}}}
}}}
}}}
/*{{{*/
.publicLightText {
color: #C0E5FC;
}
.privateLightText {
color: #E2C1D6;
}
#backstageLogo {
margin: 1px auto auto -200px;
font-weight: bold;
width: 200px;
line-height:24px;
font-size: 1.2em;
padding: 0;
text-align: center;
top: 0;
position: absolute;
left: 50%;
}
#backstageLogo .svgIcon {
margin-top:-2px;
}
#backstageLogo .svgIconText {
display: none;
}
#backstageLogo .logoText {
position: absolute;
top: 0px;
margin-left: 5px;
}
#backstageArea {
z-index: 49;
color: white;
background-color: black;
background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #222),color-stop(0.5, #333),color-stop(1, #555));
background: -moz-linear-gradient(center bottom,#222 0%, #333 50%, #555 100%);
/* For Internet Explorer 5.5 - 7 */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff555555, endColorstr=#ff222222);
/* For Internet Explorer 8 */
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#ff555555, endColorstr=#ff222222)";
height: 24px;
padding: 0;
border-bottom: solid 1px black;
}
.backstageBackground {
fill: black;
}
#backstageButton {
overflow: hidden;
}
#backstageButton #backstageShow,
#backstageButton #backstageHide {
margin: 0px;
padding: 0px;
}
#backstageButton #backstageShow:hover,
#backstageButton #backstageHide:hover {
background: none;
color: none;
}
#backstageShow {
margin-right: -3px;
margin-top: -3px;
}
#backstageShow .svgIcon {
left: 8px;
position: relative;
top: -5px;
}
#messageArea {
top: 50px;
}
#backstageToolbar {
position: relative;
}
#backstageArea a {
padding: 0px;
margin-left: 0px;
color: white;
background: none;
}
#backstageArea a:hover {
background-color: white;
}
#backstage .tabContents ol,
#backstage .tabContents ul {
padding: auto;
}
#backstageButton a {
margin: 0;
}
.backstagePanelBody,
.backstagePanelBody .tabContents ul {
padding: 5px;
margin: 5px;
}
#backstage #backstagePanel {
margin-left: 5%;
padding: 0em;
margin-right: 5%;
}
#backstageToolbar a {
position: relative;
}
#backstageArea a.backstageSelTab,
#backstageToolbar .backstageTask {
line-height: 24px;
color: #767676;
}
.backstageTask .externalImage,
.backstageTask .image {
display: inline;
}
.backstageTask .txtUserName,
.backstageTask .spaceName {
color: #fff;
}
.backstageSelTab .txtUserName,
.backstageSelTab .spaceName,
a:hover .txtUserName,
a:hover .spaceName {
color: #000;
}
.spaceSiteIcon {
margin-right: 10px;
}
.userSiteIcon {
margin-left: 10px;
}
#backstageToolbar .task_space {
position: absolute;
top: 0px;
left: 0%;
}
#backstageToolbar .task_user span,
#backstageToolbar .task_login span {
display: block;
float: left;
}
#backstageToolbar .task_user,
#backstageToolbar .task_login {
display: block;
position: absolute;
top: 0px;
right: 5%;
}
#backstageToolbar .task_login img {
position: relative;
display: inline;
}
#backstageToolbar .task_space .svgIcon {
float: left;
position: relative;
z-index: 2;
}
#backstageToolbar a span {
z-index: 2;
}
#backstageToolbar .spaceSiteIcon {
float: left;
}
a.backstageTask {
display: block;
height: 53px;
}
#backstageToolbar a span.txtUserName,
#backstageToolbar a .txtUserName span {
display: inline;
float: none;
}
#backstage .deleteButton {
margin-left: 0.3em;
font-weight: bold;
color: red;
font-size: 1.6em;
}
#backstage .deleteButton:hover {
background: none;
}
#backstagePanel .TiddlySpaceLogin {
display: inline;
}
.backstagePanelBody .tabContents .button {
display: block;
}
.backstagePanelBody .tab {
margin: 0 0 0 0.6em;
padding: 0.4em 0.5em 1px 0.5em;
}
#backstage .tabContents{
padding: 1.5em;
}
#backstage .wizard {
border: 0px;
}
#backstage .txtSpaceTab li {
border: 1px solid #ddd;
background: #eee;
list-style: none;
margin: 0.5em;
padding: 0.5em;
width: 80%;
}
#backstage .txtSpaceTab li.annotation {
border: 2px solid [[ColorPalette::SecondaryMid]];
}
#backstage div li.listLink {
border: 0px;
width: 78%;
font-size: 0.7em;
}
#backstage div li.listTitle {
font-weight: bold;
text-decoration: underline;
font-size: 1em;
background: #ccc;
width: 100%;
}
#backstage div.txtSpaceTab li .deleteButton {
float: right;
}
#backstage fieldset {
border: solid 1px [[ColorPalette::Background]];
}
#backstage .viewer table,#backstage table.twtable {
border: 0px;
}
#backstageToolbar img {
padding: 0;
}
#backstage .wizard,
#backstage .wizardFooter {
background: none;
}
.viewer td, .viewer tr, .twtable td, .twtable tr {
border: 1px solid #eee;
}
#backstage .inlineList ul li {
background-color: [[ColorPalette::Background]];
border: solid 1px [[ColorPalette::TertiaryMid]];
display: block;
float: left;
list-style: none;
margin-right: 1em;
padding: 0.5em;
}
.backstageClear, .inlineList form {
clear: both;
display: block;
margin-top: 3em;
}
/*}}}*/
/***
|''Name''|TiddlySpaceTiddlerIconsPlugin|
|''Version''|0.6.1|
|''Status''|@@beta@@|
|''Author''|Jon Robson|
|''Description''|Provides ability to render SiteIcons and icons that correspond to the home location of given tiddlers|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceTiddlerIconsPlugin.js|
|''Requires''|TiddlySpaceConfig BinaryTiddlersPlugin ImageMacroPlugin TiddlySpacePublishingCommands|
!Notes
Provides an additional SiteIcon view for use with view macro
{{{<<view modifier SiteIcon>>}}}
will show the SiteIcon located in the space with the same name as modifier.
It also works if the attribute given ends with _private or _public (so {{{<<view server.bag SiteIcon>>}}} is usable).
{{{<<tiddlerOrigin>>}}} shows the origin of the tiddler it is being run on.
In TiddlySpace terms this means it will determine whether the tiddler is external, public or private.
Where private it will analyse whether a public version exists and distinguish between the different scenarios.
If a tiddler is external, the SiteIcon of that external space will be shown
When a ViewTemplate contains an element with class concertina, clicking on the icon outputted by the tiddlerOrigin macro
will reveal more detailed information on what the icon means.
!Parameters
both take the same parameters
width / height : define a width or height of the outputted icon
label: if label parameter is set to yes, a label will accompany the icon.
!!additional view parameters
labelPrefix / labelSuffix : prefix or suffix the label with additional text. eg. labelPrefix:'modified by '
!Code
***/
//{{{
(function($) {
if(!config.macros.image) {
throw "Missing dependency: ImageMacroPlugin";
}
var imageMacro = config.macros.image;
var tiddlyspace = config.extensions.tiddlyspace;
var getStatus = config.extensions.tiddlyweb.getStatus;
var cmd = config.commands.publishTiddler;
config.macros.view.views.SiteIcon = function(value, place, params, wikifier,
paramString, tiddler) {
var container = $('<div class="siteIcon" />').prependTo(place);
var extraArgs = params.splice(2, params.length - 2).join(" ");
var imageOptions = imageMacro.getArguments(extraArgs, []);
var imagePlace = $("<div />").appendTo(container)[0];
var pos;
var endsWith = config.extensions.BinaryTiddlersPlugin.endsWith;
if(endsWith(value, "_public")) {
pos = value.indexOf("_public");
value = value.substr(0, pos);
} else if(endsWith(value, "_private")) {
pos = value.indexOf("_private");
value = value.substr(0, pos);
}
var args = paramString.parseParams("name", null, true, false, true)[0];
var labelPrefix = args.labelPrefix ? args.labelPrefix[0] : "";
var labelSuffix = args.labelSuffix ? args.labelSuffix[0] : "";
if(!store.tiddlerExists(tiddler.title) || value == "None") { // some core tiddlers lack modifier
value = "unknown";
if(store.tiddlerExists("missingIcon")) {
imageMacro.renderImage(imagePlace, "missingIcon", imageOptions);
}
} else {
getStatus(function(status) {
var uri = tiddlyspace.getAvatar(status.server_host, value);
imageMacro.renderImage(imagePlace, uri, imageOptions);
if(!value) {
value = "tiddlyspace";
}
});
}
$('<div class="label" />').text(labelPrefix + value + labelSuffix).
appendTo(container);
$(container).attr("title", value).attr("alt", value);
};
var originMacro = config.macros.tiddlerOrigin = {
locale: {
"shadow": "shadow tiddler",
"missing": "missing tiddler",
"private": "private",
"unknown": "unknown state",
"public": "public",
"privateAndPublic": "public and private tiddler",
"privateNotPublic": "private different to public",
"external": "from %0",
"missing_info": "This tiddler does not currently exist in the space.\nIt is possible you reached this via a broken link",
"external_info": "This tiddler was written by %0 in the %1 space. \nIt is visible to all at:\n%2",
"private_info": "This tiddler is currently private.\n It is visible to only members of this space at:\n%2\n\n",
"public_info": "This tiddler is currently public with no private revision.\nIt is visible to all at:\n%2",
"privateAndPublic_info": "This tiddler is currently public without any later private revisions.\nIt is visible to all at:\n%2",
"privateNotPublic_info": "This tiddler is currently public, with a different private revision. You are currently viewing the private version.\nIt is visible to all at:\n%2\nbut the content will differ depending on permissions.\n\n",
"shadow_info": "This tiddler is a special tiddler that is part of the TiddlySpace application. It has no uri.",
"unknownUser": "an unknown user",
"makePublic": "Make this tiddler public",
"makePrivate": "Make this tiddler private",
"deletePrivate": "Delete the private version of this tiddler",
"deletePublic": "Delete the public version of this tiddler",
publishPrivateDeletePrivate: "Are you sure you want to publish this tiddler?\nNote that all private versions of this tiddler will be deleted however all public versions will be retained.\n Hit cancel to abort.",
publishPrivateKeepPrivate: "Are you sure you want to publish this tiddler?\nNote that any existing public versions of this tiddler will be deleted. Hit cancel to abort.",
retainPrivateRevisions: "Also copy over the private revisions of this tiddler",
retainPublicRevisions: "Also copy over the public revisions of this tiddler",
moveToPrivate: "Are you sure you want to make this private? It will no longer be publically available to non-members of the space and you will lose any existing revisions.",
moveToPrivateKeep: "Are you sure you want to make this tiddler and all its revisions private? It will no longer be publically available to non-members of the space.",
"publicConfirmDelete": "Are you sure you want to delete all the public revisions of this tiddler?",
"privateConfirmDelete": "Are you sure you want to delete all the private revisions of this tiddler?",
pleaseWait: "please wait.."
},
handler: function(place, macroName, params,wikifier, paramString, tiddler){
var adaptor = tiddler.getAdaptor();
var locale = originMacro.locale;
var type = "private";
if(tiddler && tiddler.fields["server.workspace"]) {
name = tiddler.fields["server.workspace"].replace("recipes/", "").
replace("bags/", "");
} else {
name = tiddler;
}
var options = originMacro.getOptions(params, paramString);
options.space = tiddlyspace.determineSpace(name, true);
var concertinaContentEl = $("<div />")[0];
var concertinaButton = originMacro.createConcertinaButton(place, concertinaContentEl);
type = originMacro.determineTiddlerType(tiddler, options, function(type) {
originMacro.renderIcon(tiddler, type, concertinaButton,
concertinaContentEl, options);
});
},
createConcertinaButton: function(place, concertinaContent) {
var concertinaButton = $('<a class="originButton" href="javascript:;" />').
click(function(ev) {
var tidEl = $(story.findContainingTiddler(place));
var concertina = $(".concertina", tidEl);
concertina.empty().
append(concertinaContent);
if(concertina.attr("openedby") == "origin") {
tidEl.removeClass("concertinaOn");
concertina.slideUp(500).attr("openedby", "");
} else {
tidEl.addClass("concertinaOn");
concertina.slideDown(500).
attr("openedby", "origin");
}
}).appendTo(place);
return concertinaButton[0];
},
determineTiddlerType: function(tiddler, options, callback) {
var isShadow = store.isShadowTiddler(tiddler.title);
var exists = store.tiddlerExists(tiddler.title);
if(isShadow && !exists) {
callback("shadow");
} else if(!exists) {
callback("missing");
} else {
var space = options.space;
if(space && space.name == tiddlyspace.currentSpace.name) {
var parts = tiddler.fields["server.workspace"].split("_"); // TODO: use the split function in TiddlySpaceConfig
var spaceType = parts[parts.length - 1];
var type = ["public", "private"].contains(spaceType) ? spaceType : false;
originMacro.distinguishPublicPrivateType(tiddler, options, type, callback);
} else {
callback("external");
}
}
},
distinguishPublicPrivateType: function(tiddler, options, type, callback) {
var space = options.space;
var adaptor = tiddler.getAdaptor();
var determineType = function(privateTiddler, publicTiddler) {
if(publicTiddler && !privateTiddler) {
return "public";
} else if(privateTiddler && !publicTiddler) {
return "private";
} else if(originMacro.areIdentical(privateTiddler, publicTiddler)) {
return "privateAndPublic";
} else {
return "privateNotPublic";
}
};
var context;
if(type == "private") { //check for a public version
// is there a public version in store?
var title = tiddler.title;
var publicVersion = store.getTiddler("%0 [public]".format([title]));
if(!publicVersion) {
context = {
workspace: "bags/%0_public".format([space.name])
};
adaptor.getTiddler(tiddler.title, context, null, function(context) {
if(context) {
var publicTiddler = context.status ? context.tiddler : false;
callback(determineType(tiddler, publicTiddler));
}
});
} else { // we have a public tiddler in the local store.
callback(determineType(tiddler, publicVersion));
}
} else {
var serverTitle = tiddler.fields["server.title"];
if(serverTitle && serverTitle != tiddler.title) { // viewing a spawned public tiddler
callback(determineType(store.getTiddler(serverTitle), tiddler));
} else {
context = {
workspace: "bags/%0_private".format([space.name])
};
adaptor.getTiddler(tiddler.title, context, null, function(context) {
if(context) {
var privateTiddler = context.status ? context.tiddler : false;
callback(determineType(privateTiddler, tiddler));
}
});
}
}
},
getOptions: function(params, paramString) {
var options = {
labelOptions: originMacro._getLabelOptions(paramString.parseParams("name")),
imageOptions: imageMacro.getArguments(paramString, [])
};
return options;
},
_getLabelOptions: function(parsedParams) {
var parsedParams = parsedParams[0];
var includeLabel = !parsedParams.label || ( parsedParams.label && parsedParams.label[0] == "yes" );
return { includeLabel: includeLabel };
},
renderIcon: function(tiddler, type, concertinaButton, concertinaContentEl, options) {
var locale = originMacro.locale;
if(type != "external") {
originMacro.showPrivacyRoundel(tiddler, type, concertinaButton,
concertinaContentEl, options);
} else {
var label = locale.external.format([options.space.name || "tiddlyspace"]);
getStatus(function(status) {
var uri = tiddlyspace.getAvatar(status.server_host, options.space.name);
imageMacro.renderImage(concertinaButton, uri, options.imageOptions);
var labelOptions = options.labelOptions;
labelOptions.label = label;
originMacro.showLabel(concertinaButton, type, labelOptions);
originMacro.fillConcertina(concertinaContentEl, type, tiddler);
});
}
},
areIdentical: function(tiddler1, tiddler2) {
var sameText = tiddler1.text == tiddler2.text;
var sameTags = true;
var tags1 = tiddler1.tags;
var tags2 = tiddler2.tags;
if(tags1.length != tags2.length) {
sameTags = false;
} else {
for(var i = 0; i < tags2.length; i++) {
if(!tags1.contains(tags2[i])) {
sameTags = false;
}
}
}
var fields1 = tiddler1.fields;
var fields2 = tiddler2.fields;
var allFields = fields1;
var field;
for(field in fields2) {
if(typeof(allFields[field]) == "undefined") {
allFields[field] = false;
}
}
var sameFields = true;
var ignoreList = ["changecount", "doNotSave"];
for(field in allFields) {
if(field.indexOf("server.") !== 0 && !ignoreList.contains(field)) { // ignore server fields
if(!fields2[field]) {
sameFields = false;
} else if(fields2[field] != fields1[field]) {
sameFields = false;
}
}
}
return sameText && sameTags && sameFields;
},
showPrivacyRoundel: function(thisTiddler, privacyType, concertinaButton, concertinaContentEl, options) {
// there is a public tiddler as well as the current tiddler!
// to do: not this is not enough.. we also need to check if the public tiddler is the same as..
// .. the private tiddler to determine whether this is a draft
// use of hashes would be useful here.
imageMacro.renderImage(concertinaButton, "%0Icon".format([privacyType]), options.imageOptions);
originMacro.showLabel(concertinaButton, privacyType, options.labelOptions);
originMacro.fillConcertina(concertinaContentEl, privacyType, thisTiddler);
},
showLabel: function(concertinaButton, type, options) {
var locale = originMacro.locale;
var tidEl = $(story.findContainingTiddler(concertinaButton));
label = options.label ? options.label : locale[type];
tidEl.
removeClass("private public external privateAndPublic privateNotPublic shadow").
addClass(type);
if(options && options.includeLabel) {
$('<div class="roundelLabel" />').text(label || locale.unknown).appendTo(concertinaButton);
}
$(concertinaButton).attr("title", label);
},
fillConcertina: function(place, privacyType, tiddler) {
if(!place) {
return;
} else {
var locale = originMacro.locale;
var space = tiddlyspace.determineSpace(tiddler);
space = space.name ? space.name : false;
getStatus(function(status) {
var modifier = tiddler.modifier;
if(modifier == "None") {
modifier = locale.unknownUser;
}
var spaceLink, link;
var title = tiddler.fields["server.title"] || tiddler.title;
if(!space) {
space = "core";
link = "[[/%0|/%0]]".format([title]);
} else {
spaceLink = tiddlyspace.getHost(status.server_host, space);
space = "[[%0|%1]]".format([space, spaceLink]);
link = "[[%0/%1|%0/%1]]".format([spaceLink, title]);
}
var localeString = locale["%0_info".format([privacyType])];
if(localeString){
wikify(localeString.format([modifier, space, link]), place);
}
var command = originMacro.concertinaCommands[privacyType];
if(command && tiddler) {
command(place, tiddler);
}
});
}
},
concertinaCommands: {
"public": function(place, tiddler) {
var locale = originMacro.locale;
var chk = $('<input type="checkbox" checked="true" name="retainPublicRevisions" />');
var inProgress = false;
var doPublish = function(ev) {
if(inProgress) {
return;
}
var checked = chk.attr("checked");
var msg = checked ? locale.moveToPrivateKeep : locale.moveToPrivate;
var answer = confirm(msg);
if(answer) {
inProgress = true;
var target = $(ev.target);
var oldText = target.text();
target.text(locale.pleaseWait);
var onComplete = function(info) {
target.text(oldText);
inProgress = false;
};
var privateBag= cmd.toggleBag(tiddler, "private");
cmd.moveTiddler(tiddler, {
title: tiddler.title,
fields: { "server.bag": privateBag }
}, chk.attr("checked"), onComplete);
}
};
var toggleCheckbox = function(ev) {
if (chk.attr("checked")) {
chk.attr("checked", true);
} else {
chk.attr("checked", false);
}
};
var link = $('<a class="publishButton" />').text(locale.makePrivate).
click(doPublish).appendTo(place);
chk.appendTo(place);
$("<span />").click(toggleCheckbox).
text(locale.retainPublicRevisions).appendTo(place);
},
"private": function(place, tiddler) {
var locale = originMacro.locale;
var adaptor = tiddler.getAdaptor();
var chk = $('<input type="checkbox" checked="true" name="retainRevisions" />');
var toggleCheckbox = function(ev) {
if (chk.attr("checked")) {
chk.attr("checked", true);
} else {
chk.attr("checked", false);
}
};
var inProgress;
var doPublish = function(ev) {
if(inProgress) {
return;
}
var publishTo = tiddler.fields["server.publish.name"];
var workspace = "bags/%0".format([tiddler.fields["server.bag"]]);
tiddler.fields["server.workspace"] = workspace;
var publicBag = cmd.toggleBag(tiddler, "public");
var msg;
var checked = chk.attr("checked");
msg = checked ? locale.publishPrivateKeepPrivate : locale.publishPrivateDeletePrivate;
var title = tiddler.title;
var newTitle = publishTo || tiddler.title;
tiddler.fields["server.page.revision"] = "false";
store.addTiddler(tiddler);
var answer = confirm(msg);
if(answer) {
inProgress = true;
var target = $(ev.target);
var oldText = target.text();
target.text(locale.pleaseWait);
var onComplete = function(info) {
target.text(oldText);
inProgress = false;
};
cmd.moveTiddler(tiddler, {
title: newTitle,
fields: { "server.bag": publicBag }
}, checked, onComplete);
}
};
var link = $('<a class="publishButton" />').text(locale.makePublic).
click(doPublish).appendTo(place);
chk.appendTo(place);
$("<span />").click(toggleCheckbox).
text(locale.retainPrivateRevisions).appendTo(place);
},
privateNotPublic: function(place, tiddler) {
originMacro.concertinaCommands["private"](place, tiddler);
originMacro.concertinaCommands.privateAndPublic(place, tiddler);
},
privateAndPublic: function(place, tiddler) {
var locale = originMacro.locale;
var inProgress;
var deleteTiddler = function(ev, type) {
if(inProgress) {
return;
}
type = type ? type.toLowerCase() : "public";
var bag = cmd.toggleBag(tiddler, type);
if(confirm(locale["%0ConfirmDelete".format([type])])) {
inProgress = true;
var target = $(ev.target);
var oldText = target.text();
target.text(locale.pleaseWait);
var onComplete = function(info) {
target.text(oldText);
inProgress = false;
};
config.commands.deleteTiddler.deleteResource(tiddler, bag, onComplete);
}
};
var deletePublic = function(ev) {
deleteTiddler(ev, "public");
};
var deletePrivate = function(ev) {
deleteTiddler(ev, "private");
};
$('<a class="publishButton" />').text(locale.deletePublic).
click(deletePublic).appendTo(place);
$('<a class="publishButton" />').text(locale.deletePrivate).
click(deletePrivate).appendTo(place);
}
}
};
})(jQuery);
//}}}
<<tabs txtMainTab "Timeline" "Timeline" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>
/***
|''Name''|ServerSideSavingPlugin|
|''Description''|server-side saving|
|''Author''|FND|
|''Version''|0.6.4|
|''Status''|stable|
|''Source''|http://svn.tiddlywiki.org/Trunk/association/plugins/ServerSideSavingPlugin.js|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.3|
|''Keywords''|serverSide|
!Notes
This plugin relies on a dedicated adaptor to be present.
The specific nature of this plugin depends on the respective server.
!Revision History
!!v0.1 (2008-11-24)
* initial release
!!v0.2 (2008-12-01)
* added support for local saving
!!v0.3 (2008-12-03)
* added Save to Web macro for manual synchronization
!!v0.4 (2009-01-15)
* removed ServerConfig dependency by detecting server type from the respective tiddlers
!!v0.5 (2009-08-25)
* raised CoreVersion to 2.5.3 to take advantage of core fixes
!!v0.6 (2010-04-21)
* added notification about cross-domain restrictions to ImportTiddlers
!To Do
* conflict detection/resolution
* rename to ServerLinkPlugin?
* document deletion/renaming convention
!Code
***/
//{{{
(function($) {
readOnly = false; //# enable editing over HTTP
var plugin = config.extensions.ServerSideSavingPlugin = {};
plugin.locale = {
saved: "%0 saved successfully",
saveError: "Error saving %0: %1",
saveConflict: "Error saving %0: edit conflict",
deleted: "Removed %0",
deleteError: "Error removing %0: %1",
deleteLocalError: "Error removing %0 locally",
removedNotice: "This tiddler has been deleted.",
connectionError: "connection could not be established",
hostError: "Unable to import from this location due to cross-domain restrictions."
};
plugin.sync = function(tiddlers) {
tiddlers = tiddlers && tiddlers[0] ? tiddlers : store.getTiddlers();
$.each(tiddlers, function(i, tiddler) {
var changecount = parseInt(tiddler.fields.changecount, 10);
if(tiddler.fields.deleted === "true" && changecount === 1) {
plugin.removeTiddler(tiddler);
} else if(tiddler.isTouched() && !tiddler.doNotSave() &&
tiddler.getServerType() && tiddler.fields["server.host"]) {
delete tiddler.fields.deleted;
plugin.saveTiddler(tiddler);
}
});
};
plugin.saveTiddler = function(tiddler) {
try {
var adaptor = this.getTiddlerServerAdaptor(tiddler);
} catch(ex) {
return false;
}
var context = {
tiddler: tiddler,
changecount: tiddler.fields.changecount,
workspace: tiddler.fields["server.workspace"]
};
var serverTitle = tiddler.fields["server.title"]; // indicates renames
if(!serverTitle) {
tiddler.fields["server.title"] = tiddler.title;
} else if(tiddler.title != serverTitle) {
return adaptor.moveTiddler({ title: serverTitle },
{ title: tiddler.title }, context, null, this.saveTiddlerCallback);
}
var req = adaptor.putTiddler(tiddler, context, {}, this.saveTiddlerCallback);
return req ? tiddler : false;
};
plugin.saveTiddlerCallback = function(context, userParams) {
var tiddler = context.tiddler;
if(context.status) {
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;
}
plugin.reportSuccess("saved", tiddler);
store.setDirty(false);
} else {
if(context.httpStatus == 412) {
plugin.reportFailure("saveConflict", tiddler);
} else {
plugin.reportFailure("saveError", tiddler, context);
}
}
};
plugin.removeTiddler = function(tiddler) {
try {
var adaptor = this.getTiddlerServerAdaptor(tiddler);
} catch(ex) {
return false;
}
context = { tiddler: tiddler };
context.workspace = tiddler.fields["server.workspace"];
var req = adaptor.deleteTiddler(tiddler, context, {}, this.removeTiddlerCallback);
return req ? tiddler : false;
};
plugin.removeTiddlerCallback = function(context, userParams) {
var tiddler = context.tiddler;
if(context.status) {
if(tiddler.fields.deleted === "true") {
store.deleteTiddler(tiddler.title);
} else {
plugin.reportFailure("deleteLocalError", tiddler);
}
plugin.reportSuccess("deleted", tiddler);
store.setDirty(false);
} else {
plugin.reportFailure("deleteError", tiddler, context);
}
};
plugin.getTiddlerServerAdaptor = function(tiddler) { // XXX: rename?
var type = tiddler.fields["server.type"] || config.defaultCustomFields["server.type"];
return new config.adaptors[type]();
};
plugin.reportSuccess = function(msg, tiddler) {
displayMessage(plugin.locale[msg].format([tiddler.title]));
};
plugin.reportFailure = function(msg, tiddler, context) {
var desc = (context && context.httpStatus) ? context.statusText :
plugin.locale.connectionError;
displayMessage(plugin.locale[msg].format([tiddler.title, desc]));
};
config.macros.saveToWeb = { // XXX: hijack existing sync macro?
locale: { // TODO: merge with plugin.locale?
btnLabel: "save to web",
btnTooltip: "synchronize changes",
btnAccessKey: null
},
handler: function(place, macroName, params, wikifier, paramString, tiddler) {
createTiddlyButton(place, this.locale.btnLabel, this.locale.btnTooltip,
plugin.sync, null, null, this.locale.btnAccessKey);
}
};
// hijack saveChanges to trigger remote saving
var _saveChanges = saveChanges;
saveChanges = function(onlyIfDirty, tiddlers) {
if(window.location.protocol == "file:") {
_saveChanges.apply(this, arguments);
} else {
plugin.sync(tiddlers);
}
};
// override removeTiddler to flag tiddler as deleted -- XXX: use hijack to preserve compatibility?
TiddlyWiki.prototype.removeTiddler = function(title) { // XXX: should override deleteTiddler instance method?
var tiddler = this.fetchTiddler(title);
if(tiddler) {
tiddler.tags = ["excludeLists", "excludeSearch", "excludeMissing"];
tiddler.text = plugin.locale.removedNotice;
tiddler.fields.deleted = "true"; // XXX: rename to removed/tiddlerRemoved?
tiddler.fields.changecount = "1";
this.notify(title, true);
this.setDirty(true);
}
};
// hijack ImportTiddlers wizard to handle cross-domain restrictions
var _onOpen = config.macros.importTiddlers.onOpen;
config.macros.importTiddlers.onOpen = function(ev) {
var btn = $(resolveTarget(ev));
var url = btn.closest(".wizard").find("input[name=txtPath]").val();
if(window.location.protocol != "file:" && url.indexOf("://") != -1) {
var host = url.split("/")[2];
var macro = config.macros.importTiddlers;
if(host != window.location.host) {
btn.text(macro.cancelLabel).attr("title", macro.cancelPrompt);
btn[0].onclick = macro.onCancel;
$('<span class="status" />').text(plugin.locale.hostError).insertAfter(btn);
return false;
}
}
return _onOpen.apply(this, arguments);
};
})(jQuery);
//}}}
/***
|''Name''|taggedTabs|
|''Authors''|Simon McManus|
|''Version''|0.1|
|''Status''|stable|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Requires''||
!Description
Provides tabs containing all the tiddlers with the tag specified.
!Usage
{{{
<<taggedTabs tag>>
}}}
!Code
***/
config.macros.taggedTabs={
handler:function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
this.refresh(place,macroName,params,wikifier,paramString,tiddler,errorMsg);
},
refresh:function(place,macroName,params,wikifier,paramString,tiddler,errorMsg){
var params = paramString.parseParams("taggedTabset",null,true,false,false);
var tagged = store.getTaggedTiddlers(params[1].value,"title").reverse();
var cookie = "taggedTabs";
var wrapper = createTiddlyElement(null,"div",null,"tabsetWrapper taggedTabset" + cookie);
var tabset = createTiddlyElement(wrapper,"div",null,"tabset taggedTabs");
var validTab = false;
tabset.setAttribute("cookie",cookie);
for(var t=0; t<tagged.length; t++) {
var label = tagged[t].title;
tabLabel = label;
var prompt = tagged[t].title;
var tab = createTiddlyButton(tabset,tabLabel,prompt,config.macros.tabs.onClickTab,"tab tabUnselected");
tab.setAttribute("tab",label);
tab.setAttribute("content",label);
if(config.options[cookie] == label)
validTab = true;
}
if(!validTab)
config.options[cookie] = tagged[0].title;
place.appendChild(wrapper);
config.macros.tabs.switchTab(tabset, config.options[cookie]);
}
};
//}}}
/***
|''Name''|DiffFormatter|
|''Description''|highlighting of text comparisons|
|''Author''|FND|
|''Version''|0.9.0|
|''Status''|beta|
|''Source''|http://svn.tiddlywiki.org/Trunk/contributors/FND/formatters/DiffFormatter.js|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''Keywords''|formatting|
!Description
Highlights changes in a unified [[diff|http://en.wikipedia.org/wiki/Diff#Unified_format]].
!Notes
Based on Martin Budden's [[DiffFormatterPlugin|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/formatters/DiffFormatterPlugin.js]].
!Usage
The formatter is applied to blocks wrapped in <html><code>{{{diff{..}}}</code></html> within tiddlers tagged with "diff".
!Revision History
!!v0.9 (2010-04-07)
* initial release; fork of DiffFormatterPlugin
!StyleSheet
.diff { white-space: pre; font-family: monospace; }
.diff ins, .diff del { display: block; text-decoration: none; }
.diff ins { background-color: #dfd; }
.diff del { background-color: #fdd; }
.diff .highlight { background-color: [[ColorPalette::SecondaryPale]]; }
!Code
***/
//{{{
(function() {
config.shadowTiddlers.StyleSheetDiffFormatter = store.getTiddlerText(tiddler.title + "##StyleSheet");
store.addNotification("StyleSheetDiffFormatter", refreshStyles);
var formatters = [{
name: "diffWrapper",
match: "^\\{\\{diff\\{\n", // XXX: suboptimal
termRegExp: /(.*\}\}\})$/mg,
handler: function(w) {
var el = createTiddlyElement(w.output, "div", null, "diff");
w.subWikifyTerm(el, this.termRegExp);
}
}, {
name: "diffRange",
match: "^(?:@@|[+\\-]{3}) ",
lookaheadRegExp: /^(?:@@|[+\-]{3}) .*\n/mg,
handler: function(w) {
createTiddlyElement(w.output, "div", null, "highlight").
innerHTML = "…";
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
}, {
name: "diffAdded",
match: "^\\+",
termRegExp: /(\n)/mg,
handler: function(w) {
var el = createTiddlyElement(w.output, "ins", null, "added");
w.subWikifyTerm(el, this.termRegExp);
}
}, {
name: "diffRemoved",
match: "^-",
termRegExp: /(\n)/mg,
handler: function(w) {
var el = createTiddlyElement(w.output, "del", null, "removed");
w.subWikifyTerm(el, this.termRegExp);
}
}
];
config.parsers.diffFormatter = new Formatter(formatters);
config.parsers.diffFormatter.format = "diff";
config.parsers.diffFormatter.formatTag = "diff";
})();
//}}}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="364 157 64 51" width="64pt" height="51pt"><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><g><title>Layer 1</title><path d="M 364.50006 184.50061 L 386.99985 207.00037 L 396 198.00002 L 373.50003 175.50066 Z M 403.02295 181.97704 C 400.38693 179.34099 396.11307 179.34099 393.47702 181.97704 C 390.841 184.61307 390.841 188.88695 393.47702 191.52298 C 396.11307 194.15903 400.38693 194.15903 403.02295 191.52298 C 405.65906 188.88695 405.65906 184.61307 403.02295 181.97704 M 414.27298 170.72704 C 411.63693 168.091 407.36307 168.091 404.72702 170.72704 C 402.091 173.36308 402.091 177.63693 404.72702 180.27296 C 407.36307 182.90901 411.63693 182.90901 414.27298 180.27296 C 416.90903 177.63693 416.90903 173.36308 414.27298 170.72704 M 425.523 159.47705 C 422.88696 156.841 418.6131 156.841 415.97705 159.47705 C 413.341 162.11308 413.341 166.38695 415.97705 169.02295 C 418.6131 171.65903 422.88696 171.65903 425.523 169.02295 C 428.15906 166.38695 428.15906 162.11308 425.523 159.47705" fill="#020202"/></g></g></svg>
/***
|''Name''|TiddlySpaceCloneCommand|
|''Version''|0.5.2|
|''Description''|provides a toolbar command for cloning external tiddlers|
|''Status''|stable|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceCloneCommand.js|
|''Requires''|TiddlySpaceConfig|
!Code
***/
//{{{
(function($) {
var cmd = config.commands;
var ns = config.extensions.tiddlyspace;
var fieldStash = {}; // XXX: should not be private!?
cmd.cloneTiddler = {
text: cmd.editTiddler.text,
tooltip: "Create a copy of this tiddler in the current space",
errorMsg: "Error publishing %0: %1",
isEnabled: function(tiddler) {
if(!store.tiddlerExists(tiddler.title)) {
return true;
}
var bag = tiddler.fields["server.bag"];
if(readOnly) {
return false;
} else if(ns.coreBags.contains(bag)) {
return true;
} else {
var space = ns.determineSpace(tiddler, false);
return space && space.name != ns.currentSpace.name;
}
},
handler: function(ev, src, title) {
var tiddler = store.getTiddler(title);
if(tiddler) {
fieldStash[title] = $.extend({}, tiddler.fields);
tiddler.fields["server.workspace"] = "bags/%0_private".
format([ns.currentSpace.name]);
tiddler.fields["server.permissions"] = "read, write, create"; // no delete
delete tiddler.fields["server.page.revision"];
// special handling for pseudo-shadow tiddlers
if(tiddler.fields["server.bag"] == "tiddlyspace") {
tiddler.tags.remove("excludeLists");
}
} else { // ensure workspace is the current space
var el = story.findContainingTiddler(src);
el = $(el);
var fields = el.attr("tiddlyfields");
if(fields) { // inherited via TiddlyLink
fields = fields.decodeHashMap();
fields["server.workspace"] = config.
defaultCustomFields["server.workspace"];
} else {
fields = config.defaultCustomFields;
}
fields = String.encodeHashMap(fields);
el.attr("tiddlyfields", fields);
}
cmd.editTiddler.handler.apply(this, arguments);
return false;
}
};
cmd.editTiddler.isEnabled = function(tiddler) {
return !cmd.cloneTiddler.isEnabled.apply(this, arguments);
};
// hijack cancelTiddler to restore original fields
var _cancelHandler = cmd.cancelTiddler.handler;
cmd.cancelTiddler.handler = function(ev, src, title) {
var tiddler = store.getTiddler(title);
if(tiddler) {
tiddler.fields = fieldStash[title] || tiddler.fields;
delete fieldStash[title];
}
return _cancelHandler.apply(this, arguments);
};
// hijack saveTiddler to clear unused fields stash
var _saveHandler = cmd.saveTiddler.handler;
cmd.saveTiddler.handler = function(ev, src, title) {
delete fieldStash[title];
return _saveHandler.apply(this, arguments);
};
})(jQuery);
//}}}
|~ViewToolbar|closeTiddler +editTiddler +cloneTiddler > fields pubRev revisions syncing permalink references jump closeOthers|
|~EditToolbar|+saveTiddler saveDraft -cancelTiddler deleteTiddler|
|~RevisionToolbar|> fields revert|
<<tabs txtMainTab "Recent" "Recently edited tiddlers" TabTimeline "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "Missing" "Missing tiddlers" TabMoreMissing "Orphans" "Orphaned tiddlers" TabMoreOrphans "Shadows" "Shadowed tiddlers" TabMoreShadowed>>