diff --git a/editions/prerelease/tiddlywiki.info b/editions/prerelease/tiddlywiki.info index 99b5df532..88261c531 100644 --- a/editions/prerelease/tiddlywiki.info +++ b/editions/prerelease/tiddlywiki.info @@ -14,7 +14,8 @@ "tiddlywiki/qrcode", "tiddlywiki/bibtex", "tiddlywiki/savetrail", - "tiddlywiki/twitter" + "tiddlywiki/twitter", + "tiddlywiki/external-attachments" ], "themes": [ "tiddlywiki/vanilla", diff --git a/plugins/tiddlywiki/external-attachments/config.multids b/plugins/tiddlywiki/external-attachments/config.multids new file mode 100644 index 000000000..0a5f0dc80 --- /dev/null +++ b/plugins/tiddlywiki/external-attachments/config.multids @@ -0,0 +1,6 @@ +title: $:/config/ExternalAttachments/ + +Enable: yes +UseAbsoluteForDescendents: no +UseAbsoluteForNonDescendents: no + diff --git a/plugins/tiddlywiki/external-attachments/plugin.info b/plugins/tiddlywiki/external-attachments/plugin.info new file mode 100644 index 000000000..a2d4f9bea --- /dev/null +++ b/plugins/tiddlywiki/external-attachments/plugin.info @@ -0,0 +1,7 @@ +{ + "title": "$:/plugins/tiddlywiki/external-attachments", + "description": "External attachment support for TiddlyDesktop et al.", + "author": "Jeremy Ruston", + "core-version": ">=5.0.0", + "list": "readme settings" +} diff --git a/plugins/tiddlywiki/external-attachments/readme.tid b/plugins/tiddlywiki/external-attachments/readme.tid new file mode 100644 index 000000000..44a3c059d --- /dev/null +++ b/plugins/tiddlywiki/external-attachments/readme.tid @@ -0,0 +1,10 @@ +title: $:/plugins/tiddlywiki/external-attachments/readme + +! Introduction + +This plugin provides support for importing tiddlers as external attachments. That means that instead of importing binary files as self-contained tiddlers, they are imported as "skinny" tiddlers that reference the original file via the ''_canonical_uri'' field. This reduces the size of the wiki and thus improves performance. However, it does mean that the wiki is no longer fully self-contained. + +! Compatibility + +This plugin only works when using TiddlyWiki with platforms such as TiddlyDesktop that support the ''path'' attribute for imported/dragged files. + diff --git a/plugins/tiddlywiki/external-attachments/settings.tid b/plugins/tiddlywiki/external-attachments/settings.tid new file mode 100644 index 000000000..1ab3c4e27 --- /dev/null +++ b/plugins/tiddlywiki/external-attachments/settings.tid @@ -0,0 +1,11 @@ +title: $:/plugins/tiddlywiki/external-attachments/settings + +When used on platforms that provide the necessary support (such as ~TiddlyDesktop), you can optionally import binary files as external tiddlers that reference the original file via the ''_canonical_uri'' field. + +By default, a relative path is used to reference the file. Optionally, you can specify that an absolute path is used instead. You can do this separately for "descendent" attachments -- files that are contained within the directory containing the wiki -- vs. "non-descendent" attachments. + +<$checkbox tiddler="$:/config/ExternalAttachments/Enable" field="text" checked="yes" unchecked="no" default="no"> <$link to="$:/config/ExternalAttachments/Enable">Enable importing binary files as external attachments + +<$checkbox tiddler="$:/config/ExternalAttachments/UseAbsoluteForDescendents" field="text" checked="yes" unchecked="no" default="no"> <$link to="$:/config/ExternalAttachments/UseAbsoluteForDescendents">Use absolute paths for descendent attachments + +<$checkbox tiddler="$:/config/ExternalAttachments/UseAbsoluteForNonDescendents" field="text" checked="yes" unchecked="no" default="no"> <$link to="$:/config/ExternalAttachments/UseAbsoluteForNonDescendents">Use absolute paths for non-descendent attachments diff --git a/plugins/tiddlywiki/external-attachments/startup.js b/plugins/tiddlywiki/external-attachments/startup.js new file mode 100644 index 000000000..174f43ff2 --- /dev/null +++ b/plugins/tiddlywiki/external-attachments/startup.js @@ -0,0 +1,111 @@ +/*\ +title: $:/plugins/tiddlywiki/external-attachments/startup.js +type: application/javascript +module-type: startup + +Startup initialisation + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var ENABLE_EXTERNAL_ATTACHMENTS_TITLE = "$:/config/ExternalAttachments/Enable", + USE_ABSOLUTE_FOR_DESCENDENTS_TITLE = "$:/config/ExternalAttachments/UseAbsoluteForDescendents", + USE_ABSOLUTE_FOR_NON_DESCENDENTS_TITLE = "$:/config/ExternalAttachments/UseAbsoluteForNonDescendents"; + +// Export name and synchronous status +exports.name = "external-attachments"; +exports.platforms = ["browser"]; +exports.after = ["startup"]; +exports.synchronous = true; + +exports.startup = function() { + test_makePathRelative(); + $tw.hooks.addHook("th-importing-file",function(info) { + if(document.location.protocol === "file:" && info.isBinary && info.file.path && $tw.wiki.getTiddlerText(ENABLE_EXTERNAL_ATTACHMENTS_TITLE,"") === "yes") { + var locationPathParts = document.location.pathname.split("/").slice(0,-1), + filePathParts = info.file.path.split(/[\\\/]/mg).map(encodeURIComponent); + info.callback([ + { + title: info.file.name, + type: info.type, + "_canonical_uri": makePathRelative( + filePathParts.join("/"), + locationPathParts.join("/"), + { + useAbsoluteForNonDescendents: $tw.wiki.getTiddlerText(USE_ABSOLUTE_FOR_NON_DESCENDENTS_TITLE,"") === "yes", + useAbsoluteForDescendents: $tw.wiki.getTiddlerText(USE_ABSOLUTE_FOR_DESCENDENTS_TITLE,"") === "yes" + } + ) + } + ]); + return true; + } else { + return false; + } + }); +}; + +/* +Given a source absolute path and a root absolute path, returns the source path expressed as a relative path from the root path. +*/ +function makePathRelative(sourcepath,rootpath,options) { + options = options || {}; + var sourceParts = sourcepath.split("/"), + rootParts = rootpath.split("/"), + outputParts = []; + // Check that each path started with a slash + if(sourceParts[0] || rootParts[0]) { + throw "makePathRelative: both paths must be absolute"; + } + // Identify any common portion from the start + var c = 1, + p; + while(c < sourceParts.length && c < rootParts.length && sourceParts[c] === rootParts[c]) { + c += 1; + } + // Return "." if there's nothing left + if(c === sourceParts.length && c === rootParts.length ) { + return "." + } + // Use an absolute path if required + if((options.useAbsoluteForNonDescendents && c < rootParts.length) || (options.useAbsoluteForDescendents && c === rootParts.length)) { + return sourcepath; + } + // Move up a directory for each directory left in the root + for(p = c; p < rootParts.length; p++) { + outputParts.push(".."); + } + // Add on the remaining parts of the source path + for(p = c; p < sourceParts.length; p++) { + outputParts.push(sourceParts[p]); + } + return outputParts.join("/"); +} + +function test_makePathRelative() { + var msg = "makePathRelative test failed"; + if(makePathRelative("/Users/me/something","/Users/you/something") !== "../../me/something") { + throw msg; + } + if(makePathRelative("/Users/me/something","/Users/you/something",{useAbsoluteForNonDescendents: true}) !== "/Users/me/something") { + throw msg; + } + if(makePathRelative("/Users/me/something/else","/Users/me/something") !== "else") { + throw msg; + } + if(makePathRelative("/Users/me/something","/Users/me/something/new") !== "..") { + throw msg; + } + if(makePathRelative("/Users/me/something","/Users/me/something/new",{useAbsoluteForNonDescendents: true}) !== "/Users/me/something") { + throw msg; + } + if(makePathRelative("/Users/me/something","/Users/me/something") !== ".") { + throw msg; + } +} + +})();