diff --git a/src/model/structure.js b/src/model/structure.js
index 64990b9..a33b321 100644
--- a/src/model/structure.js
+++ b/src/model/structure.js
@@ -1,5 +1,6 @@
const path = require('path')
const urljoin = require('url-join')
+const url = require('./url')
const BROWSER_SUPPORTED_EXT = /(jpg|jpeg|png|gif)$/i
@@ -51,8 +52,8 @@ function photoExtension (filepath) {
}
function join (prefix, filepath) {
- if (prefix.match(/^https?:\/\//)) {
- return urljoin(prefix, filepath)
+ if (prefix.match(/^(http|https|file):\/\//)) {
+ return urljoin(prefix, url.fromPath(filepath))
} else {
return path.join(prefix, filepath)
}
diff --git a/src/model/url.js b/src/model/url.js
index 52a5641..953e38d 100644
--- a/src/model/url.js
+++ b/src/model/url.js
@@ -1,9 +1,19 @@
+const path = require('path')
const process = require('process')
exports.fromPath = function (filepath) {
+ // already a URL (typically provided as a CLI argument, e.g. link prefix)
+ if (filepath.match(/^(http|https|file):\/\//)) {
+ return filepath
+ }
+ // absolute paths should start with file://
+ const prefix = path.isAbsolute(filepath) ? 'file://' : ''
+ // convert \ to / but only on Windows
if (process.platform === 'win32') {
filepath = filepath.replace(/\\/g, '/')
}
- const encoded = encodeURIComponent(filepath)
- return encoded.replace(/%2F/g, '/')
+ // encode URLs, but decode overly-encoded slashes
+ filepath = encodeURIComponent(filepath).replace(/%2F/g, '/')
+ // prepend the prefix if needed
+ return prefix + filepath
}
diff --git a/src/steps/step-process.js b/src/steps/step-process.js
index d5ce2a9..e23e052 100644
--- a/src/steps/step-process.js
+++ b/src/steps/step-process.js
@@ -36,7 +36,9 @@ exports.create = function (files, opts, problems) {
const destDate = modifiedDate(dest)
const action = actionMap[f.output[out].rel]
// ignore output files that don't have an action (e.g. existing links)
- debug(`Comparing ${f.path} (${f.date}) and ${f.output[out].path} (${destDate})`)
+ if (action) {
+ debug(`Comparing ${f.path} (${f.date}) and ${f.output[out].path} (${destDate})`)
+ }
if (action && f.date > destDate) {
sourceFiles.add(f.path)
tasks[dest] = {
diff --git a/src/website/theme-base/helpers/relative.js b/src/website/theme-base/helpers/relative.js
index c845cf4..6eddf23 100644
--- a/src/website/theme-base/helpers/relative.js
+++ b/src/website/theme-base/helpers/relative.js
@@ -1,6 +1,10 @@
const path = require('path')
module.exports = (target, options) => {
+ // if already an absolute URL, do nothing
+ if (target.match(/^(http|https|file):\/\//)) {
+ return target
+ }
const albumPath = options.data.root.album.path
const relative = path.relative(path.dirname(albumPath), target)
const url = relative.replace(/\\/g, '/')
diff --git a/test/model/structure.spec.js b/test/model/structure.spec.js
index d587f73..5fe4dff 100644
--- a/test/model/structure.spec.js
+++ b/test/model/structure.spec.js
@@ -71,11 +71,31 @@ describe('Structure', () => {
should(folders('holidays/IMG_0001.mp4', 'video:poster')).endWith(ospath('IMG_0001.jpg'))
})
- it('can use a file system link', () => {
+ it('can use a relative file system link', () => {
const res = folders('holidays/IMG_0001.jpg', 'fs:link', { linkPrefix: '../..' })
should(res).eql(ospath('../../holidays/IMG_0001.jpg'))
})
+ itLinux('can use an absolute file system link', () => {
+ const res = folders('holidays/IMG_0001.jpg', 'fs:link', { linkPrefix: '/media' })
+ should(res).eql('/media/holidays/IMG_0001.jpg')
+ })
+
+ itLinux('can use a file:// system link', () => {
+ const res = folders('holidays/IMG_0001.jpg', 'fs:link', { linkPrefix: 'file:///media' })
+ should(res).eql('file:///media/holidays/IMG_0001.jpg')
+ })
+
+ itWindows('can use an absolute file system link', () => {
+ const res = folders('holidays/IMG_0001.jpg', 'fs:link', { linkPrefix: 'C:\\media' })
+ should(res).eql('C:\\media\\holidays\\IMG_0001.jpg')
+ })
+
+ itWindows('can use a file:// system link', () => {
+ const res = folders('holidays/IMG_0001.jpg', 'fs:link', { linkPrefix: 'file://C:/media' })
+ should(res).eql('file://C:/media/holidays/IMG_0001.jpg')
+ })
+
it('can use a remote HTTP link', () => {
const res = folders('holidays/IMG_0001.jpg', 'fs:link', { linkPrefix: 'http://test.com' })
should(res).eql('http://test.com/holidays/IMG_0001.jpg')
diff --git a/test/model/url.spec.js b/test/model/url.spec.js
index f62733a..9417153 100644
--- a/test/model/url.spec.js
+++ b/test/model/url.spec.js
@@ -15,21 +15,36 @@ describe('URLs', () => {
})
})
- itLinux('converts standard Linux paths', function () {
+ it('doesnt escape a file:// prefix', function () {
+ const res = url.fromPath('file:///media/photos/IMG_001.jpg')
+ should(res).eql('file:///media/photos/IMG_001.jpg')
+ })
+
+ itLinux('converts relative Linux paths', function () {
const res = url.fromPath('photos/holidays/IMG_001.jpg')
should(res).eql('photos/holidays/IMG_001.jpg')
})
+ itLinux('converts absolute Linux paths', function () {
+ const res = url.fromPath('/photos/holidays/IMG_001.jpg')
+ should(res).eql('file:///photos/holidays/IMG_001.jpg')
+ })
+
itLinux('encodes backslash in Linux paths', function () {
const res = url.fromPath('photos/my\\holidays.jpg')
should(res).eql('photos/my%5Cholidays.jpg')
})
- itWindows('converts standard Windows paths', function () {
+ itWindows('converts relative Windows paths', function () {
const res = url.fromPath('photos\\holidays\\IMG_001.jpg')
should(res).eql('photos/holidays/IMG_001.jpg')
})
+ itWindows('converts absolute Windows paths', function () {
+ const res = url.fromPath('C:\\photos\\holidays\\IMG_001.jpg')
+ should(res).eql('file://C:/photos/holidays/IMG_001.jpg')
+ })
+
itWindows('slashes are also valid path separators on Windows', function () {
const res = url.fromPath('photos/holidays/IMG_001.jpg')
should(res).eql('photos/holidays/IMG_001.jpg')
diff --git a/test/themes/helpers/relative.spec.js b/test/themes/helpers/relative.spec.js
index 7e1d0fd..15e3dd0 100644
--- a/test/themes/helpers/relative.spec.js
+++ b/test/themes/helpers/relative.spec.js
@@ -25,6 +25,14 @@ describe('Handlebars helpers: relative', () => {
should(res).eql('')
})
+ it('does not do anything if the path is an absolute URL', () => {
+ // This can happen when using --link-prefix
+ const url = 'http://example.com/photo.jpg'
+ const template = handlebars.compile(``)
+ const res = template({})
+ should(res).eql(``)
+ })
+
// TODO: this should not be needed anymore because all URLs are already escaped
it('escapes single quotes so they can be used in CSS background-image', () => {
const template = handlebars.compile(`background-image('{{relative url}}')`)