refactor "util" into ES6 modules for #3118

This commit is contained in:
Martin Raifer
2016-06-14 22:25:11 +02:00
committed by Tom MacWright
parent 6c7786ab27
commit 2b488b5567
8 changed files with 352 additions and 47 deletions

View File

@@ -45,7 +45,8 @@ $(BUILDJS_TARGETS): $(BUILDJS_SOURCES) build.js
MODULE_TARGETS = \
js/lib/id/actions.js \
js/lib/id/presets.js \
js/lib/id/validations.js
js/lib/id/validations.js \
js/lib/id/util.js
js/lib/id/actions.js: modules/
node_modules/.bin/rollup -f umd -n iD.actions modules/actions/index.js --no-strict > $@
@@ -56,6 +57,9 @@ js/lib/id/presets.js: modules/
js/lib/id/validations.js: modules/
node_modules/.bin/rollup -f umd -n iD.validations modules/validations/index.js --no-strict > $@
js/lib/id/util.js: modules/
node_modules/.bin/rollup -f umd -n iD.util modules/util/index.js --no-strict > $@
dist/iD.js: \
js/lib/bootstrap-tooltip.js \
js/lib/d3.v3.js \
@@ -85,9 +89,6 @@ dist/iD.js: \
js/id/services/taginfo.js \
js/id/services/wikidata.js \
js/id/services/wikipedia.js \
js/id/util.js \
js/id/util/session_mutex.js \
js/id/util/suggest_names.js \
js/id/geo.js \
js/id/geo/extent.js \
js/id/geo/intersection.js \

View File

@@ -36,10 +36,7 @@
<script src='js/id/id.js'></script>
<script src='js/lib/id/actions.js'></script>
<script src='js/lib/id/presets.js'></script>
<script src='js/id/util.js'></script>
<script src='js/id/util/session_mutex.js'></script>
<script src='js/id/util/suggest_names.js'></script>
<script src='js/lib/id/util.js'></script>
<script src='js/id/services.js'></script>
<script src='js/id/services/mapillary.js'></script>

272
js/lib/id/util.js Normal file
View File

@@ -0,0 +1,272 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.iD = global.iD || {}, global.iD.util = global.iD.util || {})));
}(this, function (exports) { 'use strict';
function tagText(entity) {
return d3.entries(entity.tags).map(function(e) {
return e.key + '=' + e.value;
}).join(', ');
}
function entitySelector(ids) {
return ids.length ? '.' + ids.join(',.') : 'nothing';
}
function entityOrMemberSelector(ids, graph) {
var s = entitySelector(ids);
ids.forEach(function(id) {
var entity = graph.hasEntity(id);
if (entity && entity.type === 'relation') {
entity.members.forEach(function(member) {
s += ',.' + member.id;
});
}
});
return s;
}
function displayName(entity) {
var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
}
function displayType(id) {
return {
n: t('inspector.node'),
w: t('inspector.way'),
r: t('inspector.relation')
}[id.charAt(0)];
}
function stringQs(str) {
return str.split('&').reduce(function(obj, pair){
var parts = pair.split('=');
if (parts.length === 2) {
obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
}
return obj;
}, {});
}
function qsString(obj, noencode) {
function softEncode(s) {
// encode everything except special characters used in certain hash parameters:
// "/" in map states, ":", ",", {" and "}" in background
return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
}
return Object.keys(obj).sort().map(function(key) {
return encodeURIComponent(key) + '=' + (
noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
}).join('&');
}
function prefixDOMProperty(property) {
var prefixes = ['webkit', 'ms', 'moz', 'o'],
i = -1,
n = prefixes.length,
s = document.body;
if (property in s)
return property;
property = property.substr(0, 1).toUpperCase() + property.substr(1);
while (++i < n)
if (prefixes[i] + property in s)
return prefixes[i] + property;
return false;
}
function prefixCSSProperty(property) {
var prefixes = ['webkit', 'ms', 'Moz', 'O'],
i = -1,
n = prefixes.length,
s = document.body.style;
if (property.toLowerCase() in s)
return property.toLowerCase();
while (++i < n)
if (prefixes[i] + property in s)
return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
return false;
}
var transformProperty;
function setTransform(el, x, y, scale) {
var prop = transformProperty = transformProperty || prefixCSSProperty('Transform'),
translate = iD.detect().opera ?
'translate(' + x + 'px,' + y + 'px)' :
'translate3d(' + x + 'px,' + y + 'px,0)';
return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
}
function getStyle(selector) {
for (var i = 0; i < document.styleSheets.length; i++) {
var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
for (var k = 0; k < rules.length; k++) {
var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
if (_.includes(selectorText, selector)) {
return rules[k];
}
}
}
}
function editDistance(a, b) {
if (a.length === 0) return b.length;
if (b.length === 0) return a.length;
var matrix = [];
for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
for (i = 1; i <= b.length; i++) {
for (j = 1; j <= a.length; j++) {
if (b.charAt(i-1) === a.charAt(j-1)) {
matrix[i][j] = matrix[i-1][j-1];
} else {
matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
Math.min(matrix[i][j-1] + 1, // insertion
matrix[i-1][j] + 1)); // deletion
}
}
}
return matrix[b.length][a.length];
}
// a d3.mouse-alike which
// 1. Only works on HTML elements, not SVG
// 2. Does not cause style recalculation
function fastMouse(container) {
var rect = container.getBoundingClientRect(),
rectLeft = rect.left,
rectTop = rect.top,
clientLeft = +container.clientLeft,
clientTop = +container.clientTop;
return function(e) {
return [
e.clientX - rectLeft - clientLeft,
e.clientY - rectTop - clientTop];
};
}
/* eslint-disable no-proto */
const getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
/* eslint-enable no-proto */
function asyncMap(inputs, func, callback) {
var remaining = inputs.length,
results = [],
errors = [];
inputs.forEach(function(d, i) {
func(d, function done(err, data) {
errors[i] = err;
results[i] = data;
remaining--;
if (!remaining) callback(errors, results);
});
});
}
// wraps an index to an interval [0..length-1]
function wrap(index, length) {
if (index < 0)
index += Math.ceil(-index/length)*length;
return index % length;
}
// A per-domain session mutex backed by a cookie and dead man's
// switch. If the session crashes, the mutex will auto-release
// after 5 seconds.
function SessionMutex(name) {
var mutex = {},
intervalID;
function renew() {
var expires = new Date();
expires.setSeconds(expires.getSeconds() + 5);
document.cookie = name + '=1; expires=' + expires.toUTCString();
}
mutex.lock = function() {
if (intervalID) return true;
var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
if (cookie) return false;
renew();
intervalID = window.setInterval(renew, 4000);
return true;
};
mutex.unlock = function() {
if (!intervalID) return;
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
clearInterval(intervalID);
intervalID = null;
};
mutex.locked = function() {
return !!intervalID;
};
return mutex;
}
function SuggestNames(preset, suggestions) {
preset = preset.id.split('/', 2);
var k = preset[0],
v = preset[1];
return function(value, callback) {
var result = [];
if (value && value.length > 2) {
if (suggestions[k] && suggestions[k][v]) {
for (var sugg in suggestions[k][v]) {
var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
if (dist < 3) {
result.push({
title: sugg,
value: sugg,
dist: dist
});
}
}
}
result.sort(function(a, b) {
return a.dist - b.dist;
});
}
result = result.slice(0,3);
callback(result);
};
}
exports.tagText = tagText;
exports.entitySelector = entitySelector;
exports.entityOrMemberSelector = entityOrMemberSelector;
exports.displayName = displayName;
exports.displayType = displayType;
exports.stringQs = stringQs;
exports.qsString = qsString;
exports.prefixDOMProperty = prefixDOMProperty;
exports.prefixCSSProperty = prefixCSSProperty;
exports.setTransform = setTransform;
exports.getStyle = getStyle;
exports.editDistance = editDistance;
exports.fastMouse = fastMouse;
exports.getPrototypeOf = getPrototypeOf;
exports.asyncMap = asyncMap;
exports.wrap = wrap;
exports.SessionMutex = SessionMutex;
exports.SuggestNames = SuggestNames;
Object.defineProperty(exports, '__esModule', { value: true });
}));

18
modules/util/index.js Normal file
View File

@@ -0,0 +1,18 @@
export { tagText } from './util';
export { entitySelector } from './util';
export { entityOrMemberSelector } from './util';
export { displayName } from './util';
export { displayType } from './util';
export { stringQs } from './util';
export { qsString } from './util';
export { prefixDOMProperty } from './util';
export { prefixCSSProperty } from './util';
export { setTransform } from './util';
export { getStyle } from './util';
export { editDistance } from './util';
export { fastMouse } from './util';
export { getPrototypeOf } from './util';
export { asyncMap } from './util';
export { wrap } from './util';
export { SessionMutex } from './session_mutex';
export { SuggestNames } from './suggest_names';

View File

@@ -2,7 +2,7 @@
// switch. If the session crashes, the mutex will auto-release
// after 5 seconds.
iD.util.SessionMutex = function(name) {
export function SessionMutex(name) {
var mutex = {},
intervalID;
@@ -33,4 +33,4 @@ iD.util.SessionMutex = function(name) {
};
return mutex;
};
}

View File

@@ -1,4 +1,4 @@
iD.util.SuggestNames = function(preset, suggestions) {
export function SuggestNames(preset, suggestions) {
preset = preset.id.split('/', 2);
var k = preset[0],
v = preset[1];
@@ -25,4 +25,4 @@ iD.util.SuggestNames = function(preset, suggestions) {
result = result.slice(0,3);
callback(result);
};
};
}

View File

@@ -1,17 +1,15 @@
iD.util = {};
iD.util.tagText = function(entity) {
export function tagText(entity) {
return d3.entries(entity.tags).map(function(e) {
return e.key + '=' + e.value;
}).join(', ');
};
}
iD.util.entitySelector = function(ids) {
export function entitySelector(ids) {
return ids.length ? '.' + ids.join(',.') : 'nothing';
};
}
iD.util.entityOrMemberSelector = function(ids, graph) {
var s = iD.util.entitySelector(ids);
export function entityOrMemberSelector(ids, graph) {
var s = entitySelector(ids);
ids.forEach(function(id) {
var entity = graph.hasEntity(id);
@@ -23,22 +21,22 @@ iD.util.entityOrMemberSelector = function(ids, graph) {
});
return s;
};
}
iD.util.displayName = function(entity) {
export function displayName(entity) {
var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
};
}
iD.util.displayType = function(id) {
export function displayType(id) {
return {
n: t('inspector.node'),
w: t('inspector.way'),
r: t('inspector.relation')
}[id.charAt(0)];
};
}
iD.util.stringQs = function(str) {
export function stringQs(str) {
return str.split('&').reduce(function(obj, pair){
var parts = pair.split('=');
if (parts.length === 2) {
@@ -46,9 +44,9 @@ iD.util.stringQs = function(str) {
}
return obj;
}, {});
};
}
iD.util.qsString = function(obj, noencode) {
export function qsString(obj, noencode) {
function softEncode(s) {
// encode everything except special characters used in certain hash parameters:
// "/" in map states, ":", ",", {" and "}" in background
@@ -58,9 +56,9 @@ iD.util.qsString = function(obj, noencode) {
return encodeURIComponent(key) + '=' + (
noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
}).join('&');
};
}
iD.util.prefixDOMProperty = function(property) {
export function prefixDOMProperty(property) {
var prefixes = ['webkit', 'ms', 'moz', 'o'],
i = -1,
n = prefixes.length,
@@ -76,9 +74,9 @@ iD.util.prefixDOMProperty = function(property) {
return prefixes[i] + property;
return false;
};
}
iD.util.prefixCSSProperty = function(property) {
export function prefixCSSProperty(property) {
var prefixes = ['webkit', 'ms', 'Moz', 'O'],
i = -1,
n = prefixes.length,
@@ -92,18 +90,19 @@ iD.util.prefixCSSProperty = function(property) {
return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
return false;
};
}
iD.util.setTransform = function(el, x, y, scale) {
var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
var transformProperty;
export function setTransform(el, x, y, scale) {
var prop = transformProperty = transformProperty || prefixCSSProperty('Transform'),
translate = iD.detect().opera ?
'translate(' + x + 'px,' + y + 'px)' :
'translate3d(' + x + 'px,' + y + 'px,0)';
return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
};
}
iD.util.getStyle = function(selector) {
export function getStyle(selector) {
for (var i = 0; i < document.styleSheets.length; i++) {
var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
for (var k = 0; k < rules.length; k++) {
@@ -113,9 +112,9 @@ iD.util.getStyle = function(selector) {
}
}
}
};
}
iD.util.editDistance = function(a, b) {
export function editDistance(a, b) {
if (a.length === 0) return b.length;
if (b.length === 0) return a.length;
var matrix = [];
@@ -133,12 +132,12 @@ iD.util.editDistance = function(a, b) {
}
}
return matrix[b.length][a.length];
};
}
// a d3.mouse-alike which
// 1. Only works on HTML elements, not SVG
// 2. Does not cause style recalculation
iD.util.fastMouse = function(container) {
export function fastMouse(container) {
var rect = container.getBoundingClientRect(),
rectLeft = rect.left,
rectTop = rect.top,
@@ -149,13 +148,13 @@ iD.util.fastMouse = function(container) {
e.clientX - rectLeft - clientLeft,
e.clientY - rectTop - clientTop];
};
};
}
/* eslint-disable no-proto */
iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
export const getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
/* eslint-enable no-proto */
iD.util.asyncMap = function(inputs, func, callback) {
export function asyncMap(inputs, func, callback) {
var remaining = inputs.length,
results = [],
errors = [];
@@ -168,11 +167,11 @@ iD.util.asyncMap = function(inputs, func, callback) {
if (!remaining) callback(errors, results);
});
});
};
}
// wraps an index to an interval [0..length-1]
iD.util.wrap = function(index, length) {
export function wrap(index, length) {
if (index < 0)
index += Math.ceil(-index/length)*length;
return index % length;
};
}

View File

@@ -42,10 +42,14 @@
<script src='../js/id/id.js'></script>
<script src='../js/lib/id/actions.js'></script>
<<<<<<< 6c7786ab274f46879f15cbb3ba2016a540cf8df5
<script src='../js/lib/id/presets.js'></script>
<script src='../js/lib/id/validations.js'></script>
<script src='../js/id/util.js'></script>
=======
<script src='../js/lib/id/util.js'></script>
>>>>>>> refactor "util" into ES6 modules for #3118
<script src='../js/id/services.js'></script>
<script src='../js/id/services/mapillary.js'></script>
@@ -186,8 +190,22 @@
<script src='../js/id/core/tree.js'></script>
<script src='../js/id/core/tags.js'></script>
<<<<<<< 6c7786ab274f46879f15cbb3ba2016a540cf8df5
<script src='../js/id/util/session_mutex.js'></script>
<script src='../js/id/util/suggest_names.js'></script>
=======
<script src='../js/id/presets.js'></script>
<script src='../js/id/presets/preset.js'></script>
<script src='../js/id/presets/category.js'></script>
<script src='../js/id/presets/collection.js'></script>
<script src='../js/id/presets/field.js'></script>
<script src='../js/id/validations.js'></script>
<script src='../js/id/validations/deprecated_tag.js'></script>
<script src='../js/id/validations/many_deletions.js'></script>
<script src='../js/id/validations/missing_tag.js'></script>
<script src='../js/id/validations/tag_suggests_area.js'></script>
>>>>>>> refactor "util" into ES6 modules for #3118
<script src='../js/lib/locale.js'></script>