From 12e018964703dfaafe6ef1a5806d84a78615f8f4 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 15 Jan 2018 09:45:18 -0500 Subject: [PATCH 1/2] Improve support for the file protocol This change improves support for using the file protocol with page.js. Basically once you enable hashbang we treat the base as though it were `/`. Fixes #209 --- Makefile | 10 ++++++++++ index.js | 34 ++++++++++++++++++++++------------ test/support/jsdom.js | 16 +++++++++++++--- test/tests.js | 41 ++++++++++++++++++++++++++++++++++------- 4 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..4b2539ce --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +BROWSERIFY=node_modules/.bin/browserify +INFOLOG := \033[34m ▸\033[0m + +page.js: index.js + @echo "$(INFOLOG) Building page.js.." + @$(BROWSERIFY) index.js --standalone page -o page.js + +watch: + find index.js | entr make page.js +.PHONY: watch diff --git a/index.js b/index.js index 9e76ff69..12e3d2c0 100755 --- a/index.js +++ b/index.js @@ -24,7 +24,7 @@ var isDocument = ('undefined' !== typeof document); var isWindow = ('undefined' !== typeof window); - var isHistory = ('undefined' !== typeof history); + var hasHistory = ('undefined' !== typeof history); /** * Detect click event @@ -36,8 +36,7 @@ * history.location generated polyfill in https://github.com/devote/HTML5-History-API */ - var location = isWindow && (window.history.location || window.location); - var isLocation = !!location; + var isLocation = isWindow && !!(window.history.location || window.location); /** * Perform initial dispatch. @@ -248,7 +247,7 @@ if (page.len > 0) { // this may need more testing to see if all browsers // wait for the next tick to go back in history - isHistory && history.back(); + hasHistory && history.back(); page.len--; } else if (path) { setTimeout(function() { @@ -256,7 +255,7 @@ }); }else{ setTimeout(function() { - page.show(base, state); + page.show(getBase(), state); }); } }; @@ -359,7 +358,7 @@ var current; if (hashbang) { - current = isLocation && base + location.hash.replace('#!', ''); + current = isLocation && getBase() + location.hash.replace('#!', ''); } else { current = isLocation && location.pathname + location.search; } @@ -410,11 +409,12 @@ */ function Context(path, state) { - if ('/' === path[0] && 0 !== path.indexOf(base)) path = base + (hashbang ? '#!' : '') + path; + var pageBase = getBase(); + if ('/' === path[0] && 0 !== path.indexOf(pageBase)) path = pageBase + (hashbang ? '#!' : '') + path; var i = path.indexOf('?'); this.canonicalPath = path; - this.path = path.replace(base, '') || '/'; + this.path = path.replace(pageBase, '') || '/'; if (hashbang) this.path = this.path.replace('#!', '') || '/'; this.title = (isDocument && document.title); @@ -449,7 +449,7 @@ Context.prototype.pushState = function() { page.len++; - if (isHistory) { + if (hasHistory) { history.pushState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath); } }; @@ -461,7 +461,7 @@ */ Context.prototype.save = function() { - if (isHistory) { + if (hasHistory && location.protocol !== 'file:') { history.replaceState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath); } }; @@ -632,14 +632,15 @@ // same page var orig = path; + var pageBase = getBase(); - if (path.indexOf(base) === 0) { + if (path.indexOf(pageBase) === 0) { path = path.substr(base.length); } if (hashbang) path = path.replace('#!', ''); - if (base && orig === path) return; + if (pageBase && orig === path) return; e.preventDefault(); page.show(orig); @@ -680,4 +681,13 @@ location.port === url.port; } + /** + * Gets the `base`, which depends on whether we are using History or + * hashbang routing. + */ + function getBase() { + if(!!base) return base; + return (hashbang && location.protocol === 'file:') ? location.pathname : base; + } + page.sameOrigin = sameOrigin; diff --git a/test/support/jsdom.js b/test/support/jsdom.js index 4bbf3505..6f57f372 100644 --- a/test/support/jsdom.js +++ b/test/support/jsdom.js @@ -1,10 +1,14 @@ -before(function(next) { + +function setupJsdom(options, next) { + options = options || {}; + var jsdom = require('jsdom'); var html = ''; function setupGlobals(window) { window.console = console; - window.history.replaceState(null, '', '/'); + if(window.location.protocol !== 'file:') + window.history.replaceState(null, '', '/'); global.window = window; global.location = window.location; global.document = window.document; @@ -26,9 +30,15 @@ before(function(next) { }); } else { var dom = new jsdom.JSDOM(html, { - url: 'http://example.com' + url: options.url || 'http://example.com' }); setupGlobals(dom.window); next(); } +} + +exports.setup = setupJsdom; + +before(function(next) { + setupJsdom({}, next); }); diff --git a/test/tests.js b/test/tests.js index 64dbc15a..4d8a9467 100644 --- a/test/tests.js +++ b/test/tests.js @@ -8,6 +8,7 @@ called = false, html = '', base = '', + setbase = true, hashbang = false, decodeURLComponents = true, chai = this.chai, @@ -15,10 +16,11 @@ page = this.page, baseTag, htmlWrapper, - $; + $, + jsdomSupport; if (isNode) { - require('./support/jsdom'); + jsdomSupport = require('./support/jsdom'); } before(function() { @@ -69,12 +71,14 @@ called = true; }); - if (!baseTag) { - baseTag = document.createElement('base'); - $('head').appendChild(baseTag); - } + if(setbase) { + if (!baseTag) { + baseTag = document.createElement('base'); + $('head').appendChild(baseTag); + } - baseTag.setAttribute('href', (base ? base + '/' : '/')); + baseTag.setAttribute('href', (base ? base + '/' : '/')); + } htmlWrapper = document.createElement('div'); @@ -599,4 +603,27 @@ }); }); + var describei = jsdomSupport ? describe : describe.skip; + + describei('File protocol', function() { + before(function(){ + jsdomSupport.setup({ + url: 'file:///var/html/index.html' + }, Function.prototype); + + setbase = false; + hashbang = true; + beforeTests({ + hashbang: hashbang + }); + }); + + it('test', function(){ + page('/about', function(ctx){ + expect(ctx.path).to.equal('/about'); + }); + page('/about'); + }); + }); + }).call(this); From 17e2695082c288a653c8efe1966b20e542e0885c Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 15 Jan 2018 14:19:59 -0500 Subject: [PATCH 2/2] Properly set the URL when using Node 0.10 jsdom --- test/support/jsdom.js | 1 + test/tests.js | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/support/jsdom.js b/test/support/jsdom.js index 6f57f372..620e1b12 100644 --- a/test/support/jsdom.js +++ b/test/support/jsdom.js @@ -19,6 +19,7 @@ function setupJsdom(options, next) { if(jsdom.env) { jsdom.env({ html: html, + url: options.url || 'http://example.com', done: function(errors, window) { setupGlobals(window); if (errors) { diff --git a/test/tests.js b/test/tests.js index 4d8a9467..8d174d80 100644 --- a/test/tests.js +++ b/test/tests.js @@ -97,10 +97,7 @@ htmlWrapper.innerHTML = html; document.body.appendChild(htmlWrapper); - - page(options); - }, replaceable = function(route) { function realCallback(ctx) { @@ -525,6 +522,7 @@ page.strict(false); page('/'); base = ''; + setbase = true; };