From 996ee52cf9f5e15d95deaf0acf4206959d34432a Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Fri, 6 Sep 2019 17:40:03 +0100 Subject: [PATCH] External-attachments plugin: Fix bug on Windows Fixes #4237 --- .../external-attachments/startup.js | 84 +++++++++++-------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/plugins/tiddlywiki/external-attachments/startup.js b/plugins/tiddlywiki/external-attachments/startup.js index 174f43ff2..4967921c5 100644 --- a/plugins/tiddlywiki/external-attachments/startup.js +++ b/plugins/tiddlywiki/external-attachments/startup.js @@ -26,15 +26,15 @@ 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); +console.log("Wiki location",document.location.pathname) +console.log("File location",info.file.path) info.callback([ { title: info.file.name, type: info.type, "_canonical_uri": makePathRelative( - filePathParts.join("/"), - locationPathParts.join("/"), + info.file.path, + document.location.pathname, { useAbsoluteForNonDescendents: $tw.wiki.getTiddlerText(USE_ABSOLUTE_FOR_NON_DESCENDENTS_TITLE,"") === "yes", useAbsoluteForDescendents: $tw.wiki.getTiddlerText(USE_ABSOLUTE_FOR_DESCENDENTS_TITLE,"") === "yes" @@ -50,29 +50,47 @@ exports.startup = function() { }; /* -Given a source absolute path and a root absolute path, returns the source path expressed as a relative path from the root path. +Given a source absolute filepath and a root absolute path, returns the source filepath expressed as a relative filepath from the root path. + +sourcepath comes from the "path" property of the file object, with the following patterns: + /path/to/file.png for Unix systems + C:\path\to\file.png for local files on Windows + \\sharename\path\to\file.png for network shares on Windows +rootpath comes from document.location.pathname with urlencode applied with the following patterns: + /path/to/file.html for Unix systems + /C:/path/to/file.html for local files on Windows + /sharename/path/to/file.html for network shares on Windows */ function makePathRelative(sourcepath,rootpath,options) { options = options || {}; + // First we convert the source path from OS-dependent format to generic file:// format + if(options.isWindows || $tw.platform.isWindows) { + sourcepath = sourcepath.replace(/\\/g,"/"); + // If it's a local file like C:/path/to/file.ext then add a leading slash + if(sourcepath.charAt(0) !== "/") { + sourcepath = "/" + sourcepath; + } + // If it's a network share then remove one of the leading slashes + if(sourcepath.substring(0,2) === "//") { + sourcepath = sourcepath.substring(1); + } + } + // Split the path into parts 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"; - } + // urlencode the parts of the sourcepath + $tw.utils.each(sourceParts,function(part,index) { + sourceParts[index] = encodeURI(part); + }); // Identify any common portion from the start - var c = 1, + var c = 0, 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)) { + // Use an absolute path if there's no common portion, or if specifically requested + if(c === 1 || (options.useAbsoluteForNonDescendents && c < rootParts.length) || (options.useAbsoluteForDescendents && c === rootParts.length)) { return sourcepath; } // Move up a directory for each directory left in the root @@ -87,25 +105,21 @@ function makePathRelative(sourcepath,rootpath,options) { } 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; - } + var test = function(sourcepath,rootpath,result,options) { + if(makePathRelative(sourcepath,rootpath,options) !== result) { + throw "makePathRelative test failed: makePathRelative(" + sourcepath + "," + rootpath + "," + JSON.stringify(options) + ") is not equal to " + result; + } + }; + test("/Users/me/something/file.png","/Users/you/something","../../me/something/file.png"); + test("/Users/me/something/file.png","/Users/you/something","/Users/me/something/file.png",{useAbsoluteForNonDescendents: true}); + test("/Users/me/something/else/file.png","/Users/me/something","else/file.png"); + test("/Users/me/something/file.png","/Users/me/something/new","../file.png"); + test("/Users/me/something/file.png","/Users/me/something/new","/Users/me/something/file.png",{useAbsoluteForNonDescendents: true}); + test("/Users/me/something/file.png","/Users/me/something","file.png"); + test("C:\\Users\\me\\something\\file.png","/C:/Users/me/something","file.png",{isWindows: true}); + test("\\\\SHARE\\Users\\me\\something\\file.png","/SHARE/Users/me/somethingelse","../something/file.png",{isWindows: true}); + test("\\\\SHARE\\Users\\me\\something\\file.png","/C:/Users/me/something","/SHARE/Users/me/something/file.png",{isWindows: true}); } + })();