diff --git a/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js b/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js index be46a53d2d3..05f0dcb4679 100644 --- a/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js +++ b/plugins/tiddlywiki/multiwikiserver/modules/mws-server.js @@ -332,8 +332,14 @@ Server.prototype.findMatchingRoute = function(request,state) { } else { match = potentialRoute.path.exec(pathname); } - // Allow POST as a synonym for PUT because HTML doesn't allow PUT forms - if(match && (request.method === potentialRoute.method || (request.method === "POST" && potentialRoute.method === "PUT"))) { + // Allow POST as a synonym for PUT and DELETE because HTML doesn't allow these methods in forms + if(match && ( + request.method === potentialRoute.method || + (request.method === "POST" && ( + potentialRoute.method === "PUT" || + potentialRoute.method === "DELETE" + )) + )) { state.params = []; for(var p=1; p recipe.recipe_name === recipe_name); + if(!recipeExists) { + return {message: "Recipe does not exist"}; + } + + // Delete the recipe + self.sqlTiddlerDatabase.deleteRecipe(recipe_name); + self.dispatchEvent("change"); + return null; + }); +}; + +/* +Delete a bag. Returns null on success, or {message:} on error +*/ +SqlTiddlerStore.prototype.deleteBag = function(bag_name) { + var self = this; + return this.sqlTiddlerDatabase.transaction(function() { + // Check if bag exists + const bags = self.sqlTiddlerDatabase.listBags(); + const bagExists = bags.some(bag => bag.bag_name === bag_name); + if(!bagExists) { + return {message: "Bag does not exist"}; + } + + // Delete the bag + self.sqlTiddlerDatabase.deleteBag(bag_name); + self.dispatchEvent("change"); + return null; + }); +}; + /* Returns null if the argument is an array of valid bag/recipe names, or a string error message if not */ @@ -144,50 +184,50 @@ SqlTiddlerStore.prototype.processOutgoingTiddler = function(tiddlerFields,tiddle /* */ SqlTiddlerStore.prototype.processIncomingTiddler = function(tiddlerFields, existing_attachment_blob, existing_canonical_uri) { - let attachmentSizeLimit = $tw.utils.parseNumber(this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/AttachmentSizeLimit")); + let attachmentSizeLimit = $tw.utils.parseNumber(this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/AttachmentSizeLimit")); if(attachmentSizeLimit < 100 * 1024) { attachmentSizeLimit = 100 * 1024; } - const attachmentsEnabled = this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/EnableAttachments", "yes") === "yes"; - const contentTypeInfo = $tw.config.contentTypeInfo[tiddlerFields.type || "text/vnd.tiddlywiki"]; - const isBinary = !!contentTypeInfo && contentTypeInfo.encoding === "base64"; - - let shouldProcessAttachment = tiddlerFields.text && tiddlerFields.text.length > attachmentSizeLimit; - - if(existing_attachment_blob) { - const fileSize = this.attachmentStore.getAttachmentFileSize(existing_attachment_blob); - if(fileSize <= attachmentSizeLimit) { - const existingAttachmentMeta = this.attachmentStore.getAttachmentMetadata(existing_attachment_blob); - const hasCanonicalField = !!tiddlerFields._canonical_uri; - const skipAttachment = hasCanonicalField && (tiddlerFields._canonical_uri === (existingAttachmentMeta ? existingAttachmentMeta._canonical_uri : existing_canonical_uri)); - shouldProcessAttachment = !skipAttachment; - } else { - shouldProcessAttachment = false; - } - } - - if(attachmentsEnabled && isBinary && shouldProcessAttachment) { - const attachment_blob = existing_attachment_blob || this.attachmentStore.saveAttachment({ - text: tiddlerFields.text, - type: tiddlerFields.type, - reference: tiddlerFields.title, - _canonical_uri: tiddlerFields._canonical_uri - }); - - if(tiddlerFields && tiddlerFields._canonical_uri) { - delete tiddlerFields._canonical_uri; - } - - return { - tiddlerFields: Object.assign({}, tiddlerFields, { text: undefined }), - attachment_blob: attachment_blob - }; - } else { - return { - tiddlerFields: tiddlerFields, - attachment_blob: existing_attachment_blob - }; - } + const attachmentsEnabled = this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/EnableAttachments", "yes") === "yes"; + const contentTypeInfo = $tw.config.contentTypeInfo[tiddlerFields.type || "text/vnd.tiddlywiki"]; + const isBinary = !!contentTypeInfo && contentTypeInfo.encoding === "base64"; + + let shouldProcessAttachment = tiddlerFields.text && tiddlerFields.text.length > attachmentSizeLimit; + + if(existing_attachment_blob) { + const fileSize = this.attachmentStore.getAttachmentFileSize(existing_attachment_blob); + if(fileSize <= attachmentSizeLimit) { + const existingAttachmentMeta = this.attachmentStore.getAttachmentMetadata(existing_attachment_blob); + const hasCanonicalField = !!tiddlerFields._canonical_uri; + const skipAttachment = hasCanonicalField && (tiddlerFields._canonical_uri === (existingAttachmentMeta ? existingAttachmentMeta._canonical_uri : existing_canonical_uri)); + shouldProcessAttachment = !skipAttachment; + } else { + shouldProcessAttachment = false; + } + } + + if(attachmentsEnabled && isBinary && shouldProcessAttachment) { + const attachment_blob = existing_attachment_blob || this.attachmentStore.saveAttachment({ + text: tiddlerFields.text, + type: tiddlerFields.type, + reference: tiddlerFields.title, + _canonical_uri: tiddlerFields._canonical_uri + }); + + if(tiddlerFields && tiddlerFields._canonical_uri) { + delete tiddlerFields._canonical_uri; + } + + return { + tiddlerFields: Object.assign({}, tiddlerFields, { text: undefined }), + attachment_blob: attachment_blob + }; + } else { + return { + tiddlerFields: tiddlerFields, + attachment_blob: existing_attachment_blob + }; + } }; SqlTiddlerStore.prototype.saveTiddlersFromPath = function(tiddler_files_path,bag_name) { diff --git a/plugins/tiddlywiki/multiwikiserver/templates/get-index.tid b/plugins/tiddlywiki/multiwikiserver/templates/get-index.tid index 742e6aaf6dc..f2bce443fa1 100644 --- a/plugins/tiddlywiki/multiwikiserver/templates/get-index.tid +++ b/plugins/tiddlywiki/multiwikiserver/templates/get-index.tid @@ -87,6 +87,12 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
<$text text={{{ [jsonget[description]] }}}/>
+
+
jsonget[recipe_name]addprefix[/recipes/]] }}} method="post" onsubmit="return confirmRecipeDelete(this)"> + + +
+
@@ -127,14 +133,20 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index @@ -241,6 +253,27 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index display: block; } +.mws-delete-button { + background-color: #f44336; + color: white; + padding: 5px 10px; + border: none; + border-radius: 4px; + cursor: pointer; + margin-left: 10px; +} + +.mws-delete-button:hover { + background-color: #d32f2f; +} + +.mws-wiki-card-actions { + display: flex; + justify-content: flex-end; + margin-top: 10px; + margin-left: 1em; +} + .mws-admin-dropdown-content a:hover {background-color: #ddd;} .mws-admin-dropdown:hover .mws-admin-dropdown-content {display: block;} @@ -320,34 +353,34 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index } .mws-config-button:hover { - background-color: #45a049; + background-color: #45a049; } .mws-modal-content { - padding: 20px; + padding: 20px; } .mws-modal-section { - margin-bottom: 15px; + margin-bottom: 15px; } .mws-modal-buttons { - display: flex; - gap: 10px; - justify-content: flex-end; - margin-top: 20px; + display: flex; + gap: 10px; + justify-content: flex-end; + margin-top: 20px; } .mws-modal-button-primary { - background-color: #4CAF50; - color: white; - padding: 8px 16px; - border: none; - border-radius: 4px; - cursor: pointer; + background-color: #4CAF50; + color: white; + padding: 8px 16px; + border: none; + border-radius: 4px; + cursor: pointer; } .mws-modal-button-primary:hover { - background-color: #45a049; + background-color: #45a049; }