Skip to content

Commit

Permalink
Configurable hash (#8596)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastien Corbin committed Aug 6, 2019
1 parent c85e505 commit d70a323
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 9 deletions.
41 changes: 36 additions & 5 deletions src/ui/hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ import type Map from './map';
class Hash {
_map: Map;
_updateHash: () => ?TimeoutID;
_hashName: ?string;

constructor() {
constructor(hashName: string | boolean) {
this._hashName = (typeof hashName === 'string' && hashName) || null;
bindAll([
'_getCurrentHash',
'_onHashChange',
'_updateHash'
], this);
Expand Down Expand Up @@ -67,18 +70,46 @@ class Hash {
if (mapFeedback) {
// new map feedback site has some constraints that don't allow
// us to use the same hash format as we do for the Map hash option.
hash += `#/${lng}/${lat}/${zoom}`;
hash += `/${lng}/${lat}/${zoom}`;
} else {
hash += `#${zoom}/${lat}/${lng}`;
hash += `${zoom}/${lat}/${lng}`;
}

if (bearing || pitch) hash += (`/${Math.round(bearing * 10) / 10}`);
if (pitch) hash += (`/${Math.round(pitch)}`);
return hash;

if (this._hashName && !mapFeedback) {
let found = false;
const parts = window.location.hash.slice(1).split('&').map(part => {
const key = part.split('=')[0];
if (key === this._hashName) {
found = true;
return `${key}=${hash}`;
}
return part;
}).filter(a => a);
if (!found) {
parts.push(`${this._hashName || ''}=${hash}`);
}
return `#${parts.join('&')}`;
}

return `#${hash}`;
}

_getCurrentHash() {
const hash = window.location.hash.replace('#', '');
if (this._hashName) {
const keyval = hash.split('&').map(
part => part.split('=')
).find(part => part[0] === this._hashName);
return (keyval ? keyval[1] || '' : '').split('/');
}
return hash.split('/');
}

_onHashChange() {
const loc = window.location.hash.replace('#', '').split('/');
const loc = this._getCurrentHash();
if (loc.length >= 3) {
this._map.jumpTo({
center: [+loc[2], +loc[1]],
Expand Down
6 changes: 4 additions & 2 deletions src/ui/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type IControl = {
/* eslint-enable no-use-before-define */

type MapOptions = {
hash?: boolean,
hash?: boolean | string,
interactive?: boolean,
container: HTMLElement | string,
bearingSnap?: number,
Expand Down Expand Up @@ -173,6 +173,8 @@ const defaultOptions = {
*
* @param {boolean} [options.hash=false] If `true`, the map's position (zoom, center latitude, center longitude, bearing, and pitch) will be synced with the hash fragment of the page's URL.
* For example, `http://path/to/my/page.html#2.59/39.26/53.07/-24.1/60`.
* If a string is provided, it will used as the name for a parameter-styled hash, for example:
* `http://path/to/my/page.html#map=2.59/39.26/53.07/-24.1/60&foo=bar`
* @param {boolean} [options.interactive=true] If `false`, no mouse, touch, or keyboard listeners will be attached to the map, so it will not respond to interaction.
* @param {number} [options.bearingSnap=7] The threshold, measured in degrees, that determines when the map's
* bearing will snap to north. For example, with a `bearingSnap` of 7, if the user rotates
Expand Down Expand Up @@ -378,7 +380,7 @@ class Map extends Camera {

bindHandlers(this, options);

this._hash = options.hash && (new Hash()).addTo(this);
this._hash = options.hash && (new Hash(options.hash)).addTo(this);
// don't set position from options if set through hash
if (!this._hash || !this._hash._onHashChange()) {
this.jumpTo({
Expand Down
109 changes: 107 additions & 2 deletions test/unit/ui/hash.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import window from '../../../src/util/window';
import { createMap as globalCreateMap } from '../../util';

test('hash', (t) => {
function createHash() {
const hash = new Hash();
function createHash(name) {
const hash = new Hash(name);
hash._updateHash = hash._updateHashUnthrottled.bind(hash);
return hash;
}
Expand Down Expand Up @@ -100,6 +100,70 @@ test('hash', (t) => {
t.end();
});

t.test('#_onHashChange named', (t) => {
const map = createMap(t);
const hash = createHash('map')
.addTo(map);

window.location.hash = '#map=10/3.00/-1.00&foo=bar';

hash._onHashChange();

t.equal(map.getCenter().lng, -1);
t.equal(map.getCenter().lat, 3);
t.equal(map.getZoom(), 10);
t.equal(map.getBearing(), 0);
t.equal(map.getPitch(), 0);

window.location.hash = '';

t.end();
});

t.test('#_getCurrentHash', (t) => {
const map = createMap(t);
const hash = createHash()
.addTo(map);

window.location.hash = '#10/3.00/-1.00';

const currentHash = hash._getCurrentHash();

t.equal(currentHash[0], '10');
t.equal(currentHash[1], '3.00');
t.equal(currentHash[2], '-1.00');

window.location.hash = '';

t.end();
});

t.test('#_getCurrentHash named', (t) => {
const map = createMap(t);
const hash = createHash('map')
.addTo(map);

window.location.hash = '#map=10/3.00/-1.00&foo=bar';

let currentHash = hash._getCurrentHash();

t.equal(currentHash[0], '10');
t.equal(currentHash[1], '3.00');
t.equal(currentHash[2], '-1.00');

window.location.hash = '#baz&map=10/3.00/-1.00';

currentHash = hash._getCurrentHash();

t.equal(currentHash[0], '10');
t.equal(currentHash[1], '3.00');
t.equal(currentHash[2], '-1.00');

window.location.hash = '';

t.end();
});

t.test('#_updateHash', (t) => {
function getHash() {
return window.location.hash.split('/');
Expand Down Expand Up @@ -145,6 +209,47 @@ test('hash', (t) => {
t.equal(newHash[3], '135');
t.equal(newHash[4], '60');

window.location.hash = '';

t.end();
});

t.test('#_updateHash named', (t) => {
const map = createMap(t);
createHash('map')
.addTo(map);

t.notok(window.location.hash);

map.setZoom(3);
map.setCenter([1.0, 2.0]);

t.ok(window.location.hash);

t.equal(window.location.hash, '#map=3/2/1');

map.setPitch(60);

t.equal(window.location.hash, '#map=3/2/1/0/60');

map.setBearing(135);

t.equal(window.location.hash, '#map=3/2/1/135/60');

window.location.hash += '&foo=bar';

map.setZoom(7);

t.equal(window.location.hash, '#map=7/2/1/135/60&foo=bar');

window.location.hash = '#baz&map=7/2/1/135/60&foo=bar';

map.setCenter([2.0, 1.0]);

t.equal(window.location.hash, '#baz&map=7/1/2/135/60&foo=bar');

window.location.hash = '';

t.end();
});

Expand Down

0 comments on commit d70a323

Please sign in to comment.