Add support for recipe descriptions
This commit is contained in:
parent
138c7f2665
commit
f6d6478944
|
@ -50,10 +50,12 @@ title: MultiWikiServer Administration
|
||||||
\procedure bagPill(element-tag:"span",is-topmost:"no")
|
\procedure bagPill(element-tag:"span",is-topmost:"no")
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
<$genesis $type=<<element-tag>> class={{{ mws-bag-pill [<is-topmost>match[yes]then[mws-bag-pill-topmost]] +[join[ ]] }}}>
|
<$genesis $type=<<element-tag>> class={{{ mws-bag-pill [<is-topmost>match[yes]then[mws-bag-pill-topmost]] +[join[ ]] }}}>
|
||||||
<$image source=`/wiki/${ [{!!bag-name}encodeuricomponent[]] }$/bags/${ [{!!bag-name}encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico` class="mws-favicon-small"/>
|
<a class="mws-bag-pill-link" href=`/wiki/${ [{!!bag-name}encodeuricomponent[]] }$/bags/${ [{!!bag-name}encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||||
<span class="mws-bag-pill-label">
|
<$image source=`/wiki/${ [{!!bag-name}encodeuricomponent[]] }$/bags/${ [{!!bag-name}encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico` class="mws-favicon-small"/>
|
||||||
<$text text={{!!bag-name}}/>
|
<span class="mws-bag-pill-label">
|
||||||
</span>
|
<$text text={{!!bag-name}}/>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</$genesis>
|
</$genesis>
|
||||||
\end
|
\end
|
||||||
|
|
||||||
|
@ -62,24 +64,25 @@ title: MultiWikiServer Administration
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
<a class="mws-wiki-card" href=`/wiki/${ [{!!recipe-name}encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
<a class="mws-wiki-card" href=`/wiki/${ [{!!recipe-name}encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||||
<div class="mws-wiki-card-image">
|
<div class="mws-wiki-card-image">
|
||||||
<img src=`/wiki/${ [{!!recipe-name}encodeuricomponent[]] }$/recipes/${ [{!!recipe-name}encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico` class="mws-favicon"/>
|
<$image source=`/wiki/${ [{!!recipe-name}encodeuricomponent[]] }$/recipes/${ [{!!recipe-name}encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico` class="mws-favicon"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mws-wiki-card-content">
|
<div class="mws-wiki-card-content">
|
||||||
<div class="mws-wiki-card-header">
|
<div class="mws-wiki-card-header">
|
||||||
<$text text={{!!recipe-name}}/>
|
<$text text={{!!recipe-name}}/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mws-wiki-card-meta">
|
<div class="mws-wiki-card-meta">
|
||||||
<ol class="mws-horizontal-list">
|
<%if [list<currentTiddler>] %>
|
||||||
<$list filter="[list<currentTiddler>]" counter="counter">
|
<ol class="mws-horizontal-list">
|
||||||
<$transclude $variable="bagPill" is-topmost={{{ [<counter-last>match[yes]] }}} element-tag="li"/>
|
<$list filter="[list<currentTiddler>]" counter="counter">
|
||||||
</$list>
|
<$transclude $variable="bagPill" is-topmost={{{ [<counter-last>match[yes]] }}} element-tag="li"/>
|
||||||
</ol>
|
</$list>
|
||||||
|
</ol>
|
||||||
|
<%else%>
|
||||||
|
(no bags defined)
|
||||||
|
<%endif%>
|
||||||
</div>
|
</div>
|
||||||
<div class="mws-wiki-card-description">
|
<div class="mws-wiki-card-description">
|
||||||
DDDDDD
|
<$transclude $tiddler=<<currentTiddler>> $mode="inline"/>
|
||||||
</div>
|
|
||||||
<div class="mws-wiki-card-extra">
|
|
||||||
Additional Details
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@ -91,7 +94,7 @@ title: MultiWikiServer Administration
|
||||||
These are the wikis available on this server. Click on a wiki to visit it in a new browser tab.
|
These are the wikis available on this server. Click on a wiki to visit it in a new browser tab.
|
||||||
</p>
|
</p>
|
||||||
<ul class="mws-vertical-list">
|
<ul class="mws-vertical-list">
|
||||||
<$list filter="[prefix[$:/state/multiwikiserver/recipes/]]">
|
<$list filter="[prefix[_multiwikiserver/recipes/]]">
|
||||||
<li>
|
<li>
|
||||||
<<wikiCard>>
|
<<wikiCard>>
|
||||||
</li>
|
</li>
|
||||||
|
@ -105,7 +108,7 @@ title: MultiWikiServer Administration
|
||||||
</div>
|
</div>
|
||||||
<h1>Bags</h1>
|
<h1>Bags</h1>
|
||||||
<ul class="mws-vertical-list">
|
<ul class="mws-vertical-list">
|
||||||
<$list filter="[prefix[$:/state/multiwikiserver/bags/]]">
|
<$list filter="[prefix[_multiwikiserver/bags/]]">
|
||||||
<li>
|
<li>
|
||||||
<<bagPill>>
|
<<bagPill>>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -53,10 +53,6 @@ Styles specific to the full screen layout
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mws-wiki-card-extra {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.mws-vertical-list {
|
.mws-vertical-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -79,6 +75,11 @@ Styles specific to the full screen layout
|
||||||
padding: 0 0.25em;
|
padding: 0 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mws-bag-pill:hover {
|
||||||
|
background: <<colour foreground>>;
|
||||||
|
foreground: <<colour background>>;
|
||||||
|
}
|
||||||
|
|
||||||
.mws-bag-pill-topmost {
|
.mws-bag-pill-topmost {
|
||||||
background: <<colour very-muted-foreground>>;
|
background: <<colour very-muted-foreground>>;
|
||||||
}
|
}
|
||||||
|
@ -87,17 +88,23 @@ Styles specific to the full screen layout
|
||||||
margin-left: 0.5em;
|
margin-left: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mws-bag-pill-link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: currentcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mws-favicon.tc-image-loading, .mws-favicon-small.tc-image-loading,
|
||||||
.mws-favicon.tc-image-error, .mws-favicon-small.tc-image-error {
|
.mws-favicon.tc-image-error, .mws-favicon-small.tc-image-error {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mws-favicon {
|
.mws-favicon {
|
||||||
max-width: 4em;
|
width: 4em;
|
||||||
max-height: 4em;
|
max-height: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mws-favicon-small {
|
.mws-favicon-small {
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
max-width: 1em;
|
width: 1em;
|
||||||
max-height: 1em;
|
max-height: 1em;
|
||||||
}
|
}
|
|
@ -45,10 +45,10 @@ exports.startup = function() {
|
||||||
$tw.sqlTiddlerStore.createBag("bag-alpha");
|
$tw.sqlTiddlerStore.createBag("bag-alpha");
|
||||||
$tw.sqlTiddlerStore.createBag("bag-beta");
|
$tw.sqlTiddlerStore.createBag("bag-beta");
|
||||||
$tw.sqlTiddlerStore.createBag("bag-gamma");
|
$tw.sqlTiddlerStore.createBag("bag-gamma");
|
||||||
$tw.sqlTiddlerStore.createRecipe("recipe-rho",["bag-alpha","bag-beta"]);
|
$tw.sqlTiddlerStore.createRecipe("recipe-rho",["bag-alpha","bag-beta"],"First wiki");
|
||||||
$tw.sqlTiddlerStore.createRecipe("recipe-sigma",["bag-alpha","bag-gamma"]);
|
$tw.sqlTiddlerStore.createRecipe("recipe-sigma",["bag-alpha","bag-gamma"],"Second Wiki");
|
||||||
$tw.sqlTiddlerStore.createRecipe("recipe-tau",["bag-alpha"]);
|
$tw.sqlTiddlerStore.createRecipe("recipe-tau",["bag-alpha"],"Third Wiki");
|
||||||
$tw.sqlTiddlerStore.createRecipe("recipe-upsilon",["bag-alpha","bag-gamma","bag-beta"]);
|
$tw.sqlTiddlerStore.createRecipe("recipe-upsilon",["bag-alpha","bag-gamma","bag-beta"],"Fourth Wiki");
|
||||||
// Save tiddlers
|
// Save tiddlers
|
||||||
$tw.sqlTiddlerStore.saveBagTiddler({title: "$:/SiteTitle",text: "Bag Alpha"},"bag-alpha");
|
$tw.sqlTiddlerStore.saveBagTiddler({title: "$:/SiteTitle",text: "Bag Alpha"},"bag-alpha");
|
||||||
$tw.sqlTiddlerStore.saveBagTiddler({title: "$:/SiteTitle",text: "Bag Beta"},"bag-beta");
|
$tw.sqlTiddlerStore.saveBagTiddler({title: "$:/SiteTitle",text: "Bag Beta"},"bag-beta");
|
||||||
|
|
|
@ -40,10 +40,14 @@ exports.handler = function(request,response,state) {
|
||||||
// Require the recipe names to match
|
// Require the recipe names to match
|
||||||
if(recipe_name === recipe_name_2) {
|
if(recipe_name === recipe_name_2) {
|
||||||
var result = $tw.sqlTiddlerStore.saveRecipeTiddler(fields,recipe_name);
|
var result = $tw.sqlTiddlerStore.saveRecipeTiddler(fields,recipe_name);
|
||||||
response.writeHead(204, "OK",{
|
if(result) {
|
||||||
Etag: "\"" + result.bag_name + "/" + encodeURIComponent(title) + "/" + result.tiddler_id + ":\"",
|
response.writeHead(204, "OK",{
|
||||||
"Content-Type": "text/plain"
|
Etag: "\"" + result.bag_name + "/" + encodeURIComponent(title) + "/" + result.tiddler_id + ":\"",
|
||||||
});
|
"Content-Type": "text/plain"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
response.writeHead(400);
|
||||||
|
}
|
||||||
response.end();
|
response.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,8 @@ SqlTiddlerDatabase.prototype.createTables = function() {
|
||||||
-- Recipes have names...
|
-- Recipes have names...
|
||||||
CREATE TABLE IF NOT EXISTS recipes (
|
CREATE TABLE IF NOT EXISTS recipes (
|
||||||
recipe_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
recipe_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
recipe_name TEXT UNIQUE
|
recipe_name TEXT UNIQUE,
|
||||||
|
description TEXT
|
||||||
)
|
)
|
||||||
`,`
|
`,`
|
||||||
-- ...and recipes also have an ordered list of bags
|
-- ...and recipes also have an ordered list of bags
|
||||||
|
@ -139,23 +140,27 @@ SqlTiddlerDatabase.prototype.createBag = function(bagname) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns array of {recipe_name:,description:}
|
||||||
|
*/
|
||||||
SqlTiddlerDatabase.prototype.listRecipes = function() {
|
SqlTiddlerDatabase.prototype.listRecipes = function() {
|
||||||
const rows = this.runStatementGetAll(`
|
const rows = this.runStatementGetAll(`
|
||||||
SELECT recipe_name
|
SELECT recipe_name, description
|
||||||
FROM recipes
|
FROM recipes
|
||||||
ORDER BY recipe_name
|
ORDER BY recipe_name
|
||||||
`);
|
`);
|
||||||
return rows;
|
return rows;
|
||||||
};
|
};
|
||||||
|
|
||||||
SqlTiddlerDatabase.prototype.createRecipe = function(recipename,bagnames) {
|
SqlTiddlerDatabase.prototype.createRecipe = function(recipename,bagnames,description) {
|
||||||
// Run the queries
|
// Run the queries
|
||||||
this.runStatement(`
|
this.runStatement(`
|
||||||
-- Create the entry in the recipes table if required
|
-- Create the entry in the recipes table if required
|
||||||
INSERT OR IGNORE INTO recipes (recipe_name)
|
INSERT OR IGNORE INTO recipes (recipe_name, description)
|
||||||
VALUES ($recipe_name)
|
VALUES ($recipe_name, $description)
|
||||||
`,{
|
`,{
|
||||||
recipe_name: recipename
|
recipe_name: recipename,
|
||||||
|
description: description
|
||||||
});
|
});
|
||||||
this.runStatement(`
|
this.runStatement(`
|
||||||
-- Delete existing recipe_bags entries for this recipe
|
-- Delete existing recipe_bags entries for this recipe
|
||||||
|
@ -219,7 +224,7 @@ SqlTiddlerDatabase.prototype.saveBagTiddler = function(tiddlerFields,bagname) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns {tiddler_id:,bag_name:}
|
Returns {tiddler_id:,bag_name:} or null if the recipe is empty
|
||||||
*/
|
*/
|
||||||
SqlTiddlerDatabase.prototype.saveRecipeTiddler = function(tiddlerFields,recipename) {
|
SqlTiddlerDatabase.prototype.saveRecipeTiddler = function(tiddlerFields,recipename) {
|
||||||
// Find the topmost bag in the recipe
|
// Find the topmost bag in the recipe
|
||||||
|
@ -241,6 +246,9 @@ SqlTiddlerDatabase.prototype.saveRecipeTiddler = function(tiddlerFields,recipena
|
||||||
`,{
|
`,{
|
||||||
recipe_name: recipename
|
recipe_name: recipename
|
||||||
});
|
});
|
||||||
|
if(!row) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// Save the tiddler to the topmost bag
|
// Save the tiddler to the topmost bag
|
||||||
var info = this.saveBagTiddler(tiddlerFields,row.bag_name);
|
var info = this.saveBagTiddler(tiddlerFields,row.bag_name);
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -23,7 +23,7 @@ adminWiki - reference to $tw.Wiki object into which entity state tiddlers should
|
||||||
function SqlTiddlerStore(options) {
|
function SqlTiddlerStore(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
this.adminWiki = options.adminWiki || $tw.wiki;
|
this.adminWiki = options.adminWiki || $tw.wiki;
|
||||||
this.entityStateTiddlerPrefix = "$:/state/multiwikiserver/";
|
this.entityStateTiddlerPrefix = "_multiwikiserver/";
|
||||||
// Create the database
|
// Create the database
|
||||||
this.databasePath = options.databasePath || ":memory:";
|
this.databasePath = options.databasePath || ":memory:";
|
||||||
var SqlTiddlerDatabase = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-database.js").SqlTiddlerDatabase;
|
var SqlTiddlerDatabase = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-database.js").SqlTiddlerDatabase;
|
||||||
|
@ -57,7 +57,7 @@ SqlTiddlerStore.prototype.updateAdminWiki = function() {
|
||||||
this.saveEntityStateTiddler({
|
this.saveEntityStateTiddler({
|
||||||
title: "recipes/" + recipeInfo.recipe_name,
|
title: "recipes/" + recipeInfo.recipe_name,
|
||||||
"recipe-name": recipeInfo.recipe_name,
|
"recipe-name": recipeInfo.recipe_name,
|
||||||
text: "",
|
text: recipeInfo.description,
|
||||||
list: $tw.utils.stringifyList(this.getRecipeBags(recipeInfo.recipe_name).map(bag_name => {
|
list: $tw.utils.stringifyList(this.getRecipeBags(recipeInfo.recipe_name).map(bag_name => {
|
||||||
return this.entityStateTiddlerPrefix + "bags/" + bag_name;
|
return this.entityStateTiddlerPrefix + "bags/" + bag_name;
|
||||||
}))
|
}))
|
||||||
|
@ -110,12 +110,14 @@ SqlTiddlerStore.prototype.listRecipes = function() {
|
||||||
return this.sqlTiddlerDatabase.listRecipes();
|
return this.sqlTiddlerDatabase.listRecipes();
|
||||||
};
|
};
|
||||||
|
|
||||||
SqlTiddlerStore.prototype.createRecipe = function(recipename,bagnames) {
|
SqlTiddlerStore.prototype.createRecipe = function(recipename,bagnames,description) {
|
||||||
this.sqlTiddlerDatabase.createRecipe(recipename,bagnames);
|
bagnames = bagnames || [];
|
||||||
|
description = description || "";
|
||||||
|
this.sqlTiddlerDatabase.createRecipe(recipename,bagnames,description);
|
||||||
this.saveEntityStateTiddler({
|
this.saveEntityStateTiddler({
|
||||||
title: "recipes/" + recipename,
|
title: "recipes/" + recipename,
|
||||||
"recipe-name": recipename,
|
"recipe-name": recipename,
|
||||||
text: "",
|
text: description,
|
||||||
list: $tw.utils.stringifyList(bagnames.map(bag_name => {
|
list: $tw.utils.stringifyList(bagnames.map(bag_name => {
|
||||||
return this.entityStateTiddlerPrefix + "bags/" + bag_name;
|
return this.entityStateTiddlerPrefix + "bags/" + bag_name;
|
||||||
}))
|
}))
|
||||||
|
@ -162,12 +164,16 @@ Returns {bag_name:, tiddler: {fields}, tiddler_id:}
|
||||||
*/
|
*/
|
||||||
SqlTiddlerStore.prototype.getRecipeTiddler = function(title,recipename) {
|
SqlTiddlerStore.prototype.getRecipeTiddler = function(title,recipename) {
|
||||||
var tiddlerInfo = this.sqlTiddlerDatabase.getRecipeTiddler(title,recipename);
|
var tiddlerInfo = this.sqlTiddlerDatabase.getRecipeTiddler(title,recipename);
|
||||||
return Object.assign(
|
if(tiddlerInfo) {
|
||||||
{},
|
return Object.assign(
|
||||||
tiddlerInfo,
|
{},
|
||||||
{
|
tiddlerInfo,
|
||||||
tiddler: this.processOutgoingTiddler(tiddlerInfo.tiddler,tiddlerInfo.tiddler_id,tiddlerInfo.bag_name,recipename)
|
{
|
||||||
});
|
tiddler: this.processOutgoingTiddler(tiddlerInfo.tiddler,tiddlerInfo.tiddler_id,tiddlerInfo.bag_name,recipename)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue