change printWidth to 80 chars

This commit is contained in:
Stephan Meijer
2020-04-14 16:25:48 +02:00
parent ec0ca1ee68
commit 5223c434c7
16 changed files with 228 additions and 60 deletions

View File

@@ -15,4 +15,9 @@ module.exports = {
'@typescript-eslint/no-explicit-any': 'off',
curly: ['error', 'all'],
},
settings: {
react: {
version: 'detect',
},
},
};

View File

@@ -2,6 +2,6 @@ module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
printWidth: 80,
tabWidth: 2,
};

View File

@@ -5,4 +5,11 @@ export const ARROW_UP_KEY = 38;
export const ARROW_LEFT_KEY = 37;
export const ARROW_RIGHT_KEY = 39;
export const SPECIAL_KEYS = [ENTER_KEY, ESCAPE_KEY, ARROW_DOWN_KEY, ARROW_UP_KEY, ARROW_LEFT_KEY, ARROW_RIGHT_KEY];
export const SPECIAL_KEYS = [
ENTER_KEY,
ESCAPE_KEY,
ARROW_DOWN_KEY,
ARROW_UP_KEY,
ARROW_LEFT_KEY,
ARROW_RIGHT_KEY,
];

View File

@@ -13,7 +13,9 @@ export function createElement<T extends HTMLElement = HTMLElement>(
Object.keys(attributes).forEach((key) => {
if (typeof attributes[key] === 'function') {
// IE doesn't support startsWith
const type = (key.indexOf('on') === 0 ? key.substr(2).toLowerCase() : key) as keyof HTMLElementEventMap;
const type = (key.indexOf('on') === 0
? key.substr(2).toLowerCase()
: key) as keyof HTMLElementEventMap;
el.addEventListener(type, attributes[key] as () => void);
} else {
el.setAttribute(key, attributes[key] as string);
@@ -32,7 +34,10 @@ export function stopPropagation(event: Event) {
event.stopPropagation();
}
export function createScriptElement<T = object>(url: string, cb: string): Promise<T> {
export function createScriptElement<T = object>(
url: string,
cb: string,
): Promise<T> {
const script = createElement('script', null, document.body);
script.setAttribute('type', 'text/javascript');
@@ -47,9 +52,13 @@ export function createScriptElement<T = object>(url: string, cb: string): Promis
});
}
export const cx = (...classNames: (string | undefined)[]): string => classNames.filter(Boolean).join(' ').trim();
export const cx = (...classNames: (string | undefined)[]): string =>
classNames.filter(Boolean).join(' ').trim();
export function addClassName(element: Element, className: string | string[]): void {
export function addClassName(
element: Element,
className: string | string[],
): void {
if (!element || !element.classList) {
return;
}
@@ -63,7 +72,10 @@ export function addClassName(element: Element, className: string | string[]): vo
});
}
export function removeClassName(element: Element, className: string | string[]): void {
export function removeClassName(
element: Element,
className: string | string[],
): void {
if (!element || !element.classList) {
return;
}
@@ -77,7 +89,11 @@ export function removeClassName(element: Element, className: string | string[]):
});
}
export function replaceClassName(element: Element, find: string, replace: string): void {
export function replaceClassName(
element: Element,
find: string,
replace: string,
): void {
removeClassName(element, find);
addClassName(element, replace);
}

View File

@@ -3,7 +3,13 @@ import ResultList from './resultList';
import debounce from './lib/debounce';
import { createElement, addClassName, removeClassName } from './domUtils';
import { ENTER_KEY, SPECIAL_KEYS, ARROW_UP_KEY, ARROW_DOWN_KEY, ESCAPE_KEY } from './constants';
import {
ENTER_KEY,
SPECIAL_KEYS,
ARROW_UP_KEY,
ARROW_DOWN_KEY,
ESCAPE_KEY,
} from './constants';
const defaultOptions = () => ({
position: 'topleft',
@@ -37,7 +43,14 @@ const defaultOptions = () => ({
});
const wasHandlerEnabled = {};
const mapHandlers = ['dragging', 'touchZoom', 'doubleClickZoom', 'scrollWheelZoom', 'boxZoom', 'keyboard'];
const mapHandlers = [
'dragging',
'touchZoom',
'doubleClickZoom',
'scrollWheelZoom',
'boxZoom',
'keyboard',
];
const Control = {
initialize(options) {
@@ -49,7 +62,13 @@ const Control = {
...options,
};
const { style, classNames, searchLabel, autoComplete, autoCompleteDelay } = this.options;
const {
style,
classNames,
searchLabel,
autoComplete,
autoCompleteDelay,
} = this.options;
if (style !== 'button') {
this.options.classNames.container += ` ${options.style}`;
}
@@ -100,7 +119,11 @@ const Control = {
true,
);
input.addEventListener('keydown', (e) => this.selectResult(e), true);
input.addEventListener('keydown', (e) => this.clearResults(e, true), true);
input.addEventListener(
'keydown',
(e) => this.clearResults(e, true),
true,
);
}
form.addEventListener('mouseenter', (e) => this.disableHandlers(e), true);
@@ -120,7 +143,9 @@ const Control = {
if (style === 'bar') {
const { form } = this.searchElement.elements;
const root = map.getContainer().querySelector('.leaflet-control-container');
const root = map
.getContainer()
.querySelector('.leaflet-control-container');
const container = createElement('div', 'leaflet-control-geosearch bar');
container.appendChild(form);
@@ -186,7 +211,9 @@ const Control = {
},
selectResult(event) {
if ([ENTER_KEY, ARROW_DOWN_KEY, ARROW_UP_KEY].indexOf(event.keyCode) === -1) {
if (
[ENTER_KEY, ARROW_DOWN_KEY, ARROW_UP_KEY].indexOf(event.keyCode) === -1
) {
return;
}
@@ -208,7 +235,8 @@ const Control = {
}
// eslint-disable-next-line no-bitwise
const next = event.code === 'ArrowDown' ? ~~list.selected + 1 : ~~list.selected - 1;
const next =
event.code === 'ArrowDown' ? ~~list.selected + 1 : ~~list.selected - 1;
// eslint-disable-next-line no-nested-ternary
const idx = next < 0 ? max : next > max ? 0 : next;
@@ -325,12 +353,16 @@ const Control = {
const { retainZoomLevel, animateZoom } = this.options;
const resultBounds = new L.LatLngBounds(result.bounds);
const bounds = resultBounds.isValid() ? resultBounds : this.markers.getBounds();
const bounds = resultBounds.isValid()
? resultBounds
: this.markers.getBounds();
if (!retainZoomLevel && resultBounds.isValid()) {
this.map.fitBounds(bounds, { animate: animateZoom });
} else {
this.map.setView(bounds.getCenter(), this.getZoom(), { animate: animateZoom });
this.map.setView(bounds.getCenter(), this.getZoom(), {
animate: animateZoom,
});
}
},
@@ -342,7 +374,9 @@ const Control = {
export default function LeafletControl(...options) {
if (!L || !L.Control || !L.Control.extend) {
throw new Error('Leaflet must be loaded before instantiating the GeoSearch control');
throw new Error(
'Leaflet must be loaded before instantiating the GeoSearch control',
);
}
const LControl = L.Control.extend(Control);

View File

@@ -1,4 +1,8 @@
export default function hasShape(keys: string[], exact: boolean, object: object): boolean {
export default function hasShape(
keys: string[],
exact: boolean,
object: object,
): boolean {
if (exact && keys.length !== Object.keys(object).length) {
return false;
}

View File

@@ -21,9 +21,16 @@ describe('BingProvider', () => {
const callbackName = `BING_JSONP_CB_${now}`;
beforeAll(() => {
fetch.mockResponse(async () => ({ body: `${callbackName}(${JSON.stringify(fixtures)})` }));
fetch.mockResponse(async () => ({
body: `${callbackName}(${JSON.stringify(fixtures)})`,
}));
// eslint-disable-next-line @typescript-eslint/no-var-requires
jest.spyOn(require('../../domUtils'), 'createScriptElement').mockImplementation(jest.fn(async () => fixtures));
const domUtils = require('../../domUtils');
jest
.spyOn(domUtils, 'createScriptElement')
.mockImplementation(jest.fn(async () => fixtures));
});
afterAll(() => {
@@ -43,8 +50,12 @@ describe('BingProvider', () => {
const result = results[0];
expect(result.label).toBeTruthy();
expect(result.x).toEqual(fixtures.resourceSets[0].resources[0].point.coordinates[1]);
expect(result.y).toEqual(fixtures.resourceSets[0].resources[0].point.coordinates[0]);
expect(result.x).toEqual(
fixtures.resourceSets[0].resources[0].point.coordinates[1],
);
expect(result.y).toEqual(
fixtures.resourceSets[0].resources[0].point.coordinates[0],
);
expect(result.bounds[0][0]).toBeGreaterThan(result.bounds[0][1]);
expect(result.bounds[1][0]).toBeGreaterThan(result.bounds[1][1]);
expect(result.bounds[0][0]).toBeLessThan(result.bounds[1][0]);

View File

@@ -1,4 +1,9 @@
import AbstractProvider, { EndpointArgument, ParseArgument, SearchArgument, SearchResult } from './provider';
import AbstractProvider, {
EndpointArgument,
ParseArgument,
SearchArgument,
SearchResult,
} from './provider';
import { createScriptElement } from '../domUtils';
export interface RequestResult {
@@ -39,7 +44,10 @@ export interface RawResult {
matchCodes: string[];
}
export default class BingProvider extends AbstractProvider<RequestResult, RawResult> {
export default class BingProvider extends AbstractProvider<
RequestResult,
RawResult
> {
searchUrl = 'https://dev.virtualearth.net/REST/v1/Locations';
endpoint({ query, jsonp }: EndpointArgument & { jsonp: string }): string {
@@ -68,7 +76,10 @@ export default class BingProvider extends AbstractProvider<RequestResult, RawRes
async search({ query }: SearchArgument): Promise<SearchResult<RawResult>[]> {
const jsonp = `BING_JSONP_CB_${Date.now()}`;
const json = await createScriptElement<RequestResult>(this.endpoint({ query, jsonp }), jsonp);
const json = await createScriptElement<RequestResult>(
this.endpoint({ query, jsonp }),
jsonp,
);
return this.parse({ data: json });
}

View File

@@ -1,4 +1,8 @@
import AbstractProvider, { EndpointArgument, ParseArgument, SearchResult } from './provider';
import AbstractProvider, {
EndpointArgument,
ParseArgument,
SearchResult,
} from './provider';
interface RequestResult {
spatialReference: { wkid: number; latestWkid: number };
@@ -19,8 +23,12 @@ interface RawResult {
};
}
export default class EsriProvider extends AbstractProvider<RequestResult, RawResult> {
searchUrl = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find';
export default class EsriProvider extends AbstractProvider<
RequestResult,
RawResult
> {
searchUrl =
'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find';
endpoint({ query }: EndpointArgument): string {
const params = typeof query === 'string' ? { text: query } : query;

View File

@@ -1,4 +1,9 @@
import AbstractProvider, { EndpointArgument, LatLng, ParseArgument, SearchResult } from './provider';
import AbstractProvider, {
EndpointArgument,
LatLng,
ParseArgument,
SearchResult,
} from './provider';
export interface RequestResult {
results: RawResult[];
@@ -28,7 +33,10 @@ export interface RawResult {
types: string[];
}
export default class GoogleProvider extends AbstractProvider<RequestResult, RawResult> {
export default class GoogleProvider extends AbstractProvider<
RequestResult,
RawResult
> {
searchUrl = 'https://maps.googleapis.com/maps/api/geocode/json';
endpoint({ query }: EndpointArgument) {

View File

@@ -1,4 +1,6 @@
import OpenStreetMapProvider, { OpenStreetMapProviderOptions } from './openStreetMapProvider';
import OpenStreetMapProvider, {
OpenStreetMapProviderOptions,
} from './openStreetMapProvider';
export default class LocationIQProvider extends OpenStreetMapProvider {
constructor(options: OpenStreetMapProviderOptions) {

View File

@@ -1,4 +1,9 @@
import AbstractProvider, { EndpointArgument, LatLng, ParseArgument, SearchResult } from './provider';
import AbstractProvider, {
EndpointArgument,
LatLng,
ParseArgument,
SearchResult,
} from './provider';
export interface RequestResult {
results: RawResult[];
@@ -44,8 +49,18 @@ export interface RawResult {
speed_in: string;
};
sun: {
rise: { apparent: number; astronomical: number; civil: number; nautical: number };
set: { apparent: number; astronomical: number; civil: number; nautical: number };
rise: {
apparent: number;
astronomical: number;
civil: number;
nautical: number;
};
set: {
apparent: number;
astronomical: number;
civil: number;
nautical: number;
};
};
timezone: {
name: string;
@@ -64,7 +79,10 @@ export interface RawResult {
geometry: LatLng;
}
export default class OpenCageProvider extends AbstractProvider<RequestResult, RawResult> {
export default class OpenCageProvider extends AbstractProvider<
RequestResult,
RawResult
> {
searchUrl = 'https://api.opencagedata.com/geocode/v1/json';
endpoint({ query }: EndpointArgument) {

View File

@@ -30,15 +30,20 @@ export type OpenStreetMapProviderOptions = {
reverseUrl?: string;
} & ProviderOptions;
export default class OpenStreetMapProvider extends AbstractProvider<RawResult[], RawResult> {
export default class OpenStreetMapProvider extends AbstractProvider<
RawResult[],
RawResult
> {
searchUrl: string;
reverseUrl: string;
constructor(options: OpenStreetMapProviderOptions = {}) {
super(options);
this.searchUrl = options.searchUrl || 'https://nominatim.openstreetmap.org/search';
this.reverseUrl = options.reverseUrl || 'https://nominatim.openstreetmap.org/reverse';
this.searchUrl =
options.searchUrl || 'https://nominatim.openstreetmap.org/search';
this.reverseUrl =
options.reverseUrl || 'https://nominatim.openstreetmap.org/reverse';
}
endpoint({ query, type }: EndpointArgument): string {
@@ -55,7 +60,9 @@ export default class OpenStreetMapProvider extends AbstractProvider<RawResult[],
}
parse(response: ParseArgument<RequestResult>): SearchResult<RawResult>[] {
const records = Array.isArray(response.data) ? response.data : [response.data];
const records = Array.isArray(response.data)
? response.data
: [response.data];
return records.map((r) => ({
x: Number(r.lon),

View File

@@ -58,12 +58,16 @@ export default abstract class AbstractProvider<TRequestResult, TRawResult>
}
abstract endpoint(options: EndpointArgument): string;
abstract parse(response: ParseArgument<TRequestResult>): SearchResult<TRawResult>[];
abstract parse(
response: ParseArgument<TRequestResult>,
): SearchResult<TRawResult>[];
getParamString(params: ProviderParams = {}): string {
const set = { ...this.options.params, ...params };
return Object.keys(set)
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(set[key])}`)
.map(
(key) => `${encodeURIComponent(key)}=${encodeURIComponent(set[key])}`,
)
.join('&');
}

View File

@@ -20,7 +20,10 @@ export default class ResultList {
constructor({ handleClick, classNames = {} }: ResultListProps) {
this.handleClick = handleClick;
this.container = createElement<HTMLDivElement>('div', cx('results', classNames.container));
this.container = createElement<HTMLDivElement>(
'div',
cx('results', classNames.container),
);
this.container.addEventListener('click', this.onClick, true);
this.resultItem = createElement<HTMLDivElement>('div', cx(classNames.item));
@@ -46,7 +49,9 @@ export default class ResultList {
select(index: number): SearchResult {
// eslint-disable-next-line no-confusing-arrow
Array.from(this.container.children).forEach((child, idx) =>
idx === index ? addClassName(child, 'active') : removeClassName(child, 'active'),
idx === index
? addClassName(child, 'active')
: removeClassName(child, 'active'),
);
this.selected = index;
@@ -72,7 +77,11 @@ export default class ResultList {
return;
}
const target = event.target as HTMLDivElement;
if (!target || !this.container.contains(target) || !target.hasAttribute('data-key')) {
if (
!target ||
!this.container.contains(target) ||
!target.hasAttribute('data-key')
) {
return;
}

View File

@@ -1,4 +1,11 @@
import { createElement, addClassName, removeClassName, cx, stopPropagation, replaceClassName } from './domUtils';
import {
createElement,
addClassName,
removeClassName,
cx,
stopPropagation,
replaceClassName,
} from './domUtils';
import { ESCAPE_KEY, ENTER_KEY } from './constants';
interface SearchElementProps {
@@ -18,22 +25,39 @@ export default class SearchElement {
handleSubmit: (args: { query: string }) => void;
hasError = false;
constructor({ handleSubmit, searchLabel, classNames = {} }: SearchElementProps) {
this.container = createElement<HTMLDivElement>('div', cx('geosearch', classNames.container));
constructor({
handleSubmit,
searchLabel,
classNames = {},
}: SearchElementProps) {
this.container = createElement<HTMLDivElement>(
'div',
cx('geosearch', classNames.container),
);
this.form = createElement<HTMLFormElement>('form', ['', classNames.form].join(' '), this.container, {
autocomplete: 'none',
});
this.form = createElement<HTMLFormElement>(
'form',
['', classNames.form].join(' '),
this.container,
{
autocomplete: 'none',
},
);
this.input = createElement<HTMLInputElement>('input', ['glass', classNames.input].join(' '), this.form, {
type: 'text',
placeholder: searchLabel || 'search',
onInput: this.onInput,
onKeyUp: this.onKeyUp,
onKeyPress: this.onKeyPress,
onFocus: this.onFocus,
onBlur: this.onBlur,
});
this.input = createElement<HTMLInputElement>(
'input',
['glass', classNames.input].join(' '),
this.form,
{
type: 'text',
placeholder: searchLabel || 'search',
onInput: this.onInput,
onKeyUp: this.onKeyUp,
onKeyPress: this.onKeyPress,
onFocus: this.onFocus,
onBlur: this.onBlur,
},
);
this.handleSubmit = handleSubmit;
}