mirror of
https://github.com/maputnik/editor.git
synced 2025-12-06 06:10:00 +00:00
Fix missing font auto complete menu (#1491)
## Launch Checklist This fixes the position of the autocomplete list - CSS fix mostly. It also changes the loading of the metadata to be using promises instead of callbacks. I couldn't reproduce the following issue, so I'll be closing it for now. - Fixes #945 Before: <img width="563" height="577" alt="image" src="https://github.com/user-attachments/assets/6ea264e1-cb85-4a8a-8df5-ab50e7815333" /> After: <img width="563" height="577" alt="image" src="https://github.com/user-attachments/assets/27fa2901-dd96-44fd-9774-363fd4c5ed98" /> - [x] Briefly describe the changes in this PR. - [x] Link to related issues. - [x] Include before/after visuals or gifs if this PR includes visual changes. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -207,6 +207,20 @@ describe("layer editor", () => {
|
||||
it("compound filter");
|
||||
});
|
||||
|
||||
describe("layout", () => {
|
||||
it("text-font", () => {
|
||||
when.setStyle("font");
|
||||
when.collapseGroupInLayerEditor();
|
||||
when.collapseGroupInLayerEditor(1);
|
||||
when.collapseGroupInLayerEditor(2);
|
||||
when.doWithin("spec-field:text-font", () => {
|
||||
get.element(".maputnik-autocomplete input").first().click();
|
||||
});
|
||||
then(get.element(".maputnik-autocomplete-menu-item")).shouldBeVisible();
|
||||
then(get.element(".maputnik-autocomplete-menu-item")).shouldHaveLength(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("paint", () => {
|
||||
it("expand/collapse");
|
||||
it("color");
|
||||
|
||||
@@ -85,6 +85,13 @@ export class MaputnikDriver {
|
||||
fixture: "rectangles-style.json",
|
||||
},
|
||||
});
|
||||
this.helper.given.interceptAndMockResponse({
|
||||
method: "GET",
|
||||
url: baseUrl + "example-style-with-fonts.json",
|
||||
response: {
|
||||
fixture: "example-style-with-fonts.json",
|
||||
},
|
||||
});
|
||||
this.helper.given.interceptAndMockResponse({
|
||||
method: "GET",
|
||||
url: "*example.local/*",
|
||||
@@ -95,6 +102,11 @@ export class MaputnikDriver {
|
||||
url: "*example.com/*",
|
||||
response: [],
|
||||
});
|
||||
this.helper.given.interceptAndMockResponse({
|
||||
method: "GET",
|
||||
url: "https://www.glyph-server.com/*",
|
||||
response: ["Font 1", "Font 2", "Font 3"],
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -114,7 +126,7 @@ export class MaputnikDriver {
|
||||
this.helper.when.wait(200);
|
||||
},
|
||||
setStyle: (
|
||||
styleProperties: "geojson" | "raster" | "both" | "layer" | "rectangles" | "",
|
||||
styleProperties: "geojson" | "raster" | "both" | "layer" | "rectangles" | "font" | "",
|
||||
zoom?: number
|
||||
) => {
|
||||
const url = new URL(baseUrl);
|
||||
@@ -134,6 +146,9 @@ export class MaputnikDriver {
|
||||
case "rectangles":
|
||||
url.searchParams.set("style", baseUrl + "rectangles-style.json");
|
||||
break;
|
||||
case "font":
|
||||
url.searchParams.set("style", baseUrl + "example-style-with-fonts.json");
|
||||
break;
|
||||
}
|
||||
|
||||
if (zoom) {
|
||||
|
||||
38
cypress/fixtures/example-style-with-fonts.json
Normal file
38
cypress/fixtures/example-style-with-fonts.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"id": "test-style",
|
||||
"version": 8,
|
||||
"name": "Test Style",
|
||||
"metadata": {
|
||||
"maputnik:renderer": "mlgljs"
|
||||
},
|
||||
"sources": {
|
||||
"example": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features":[{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Dinagat Islands"
|
||||
},
|
||||
"geometry":{
|
||||
"type": "Point",
|
||||
"coordinates": [125.6, 10.1]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"glyphs": "https://www.glyph-server.com/fonts/{fontstack}/{range}.pbf",
|
||||
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"layers": [
|
||||
{
|
||||
"id": "label",
|
||||
"type": "symbol",
|
||||
"source": "example",
|
||||
"layout": {
|
||||
"text-font": ["Font"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -294,13 +294,13 @@ export default class App extends React.Component<any, AppState> {
|
||||
const accessToken = metadata["maputnik:openmaptiles_access_token"] || tokens.openmaptiles;
|
||||
|
||||
const glyphUrl = (typeof urlTemplate === "string")? urlTemplate.replace("{key}", accessToken): urlTemplate;
|
||||
downloadGlyphsMetadata(glyphUrl, fonts => {
|
||||
downloadGlyphsMetadata(glyphUrl).then(fonts => {
|
||||
this.setState({ spec: updateRootSpec(this.state.spec, "glyphs", fonts)});
|
||||
});
|
||||
}
|
||||
|
||||
updateIcons(baseUrl: string) {
|
||||
downloadSpriteMetadata(baseUrl, icons => {
|
||||
downloadSpriteMetadata(baseUrl).then(icons => {
|
||||
this.setState({ spec: updateRootSpec(this.state.spec, "sprite", icons)});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,44 +1,39 @@
|
||||
import npmurl from "url";
|
||||
|
||||
function loadJSON(url: string, defaultValue: any, cb: (...args: any[]) => void) {
|
||||
fetch(url, {
|
||||
mode: "cors",
|
||||
credentials: "same-origin"
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load metadata for " + url);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((body) => {
|
||||
cb(body);
|
||||
})
|
||||
.catch(() => {
|
||||
console.warn("Can not load metadata for " + url + ", using default value " + defaultValue);
|
||||
cb(defaultValue);
|
||||
async function loadJSON<T>(url: string, defaultValue: T): Promise<T> {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
mode: "cors",
|
||||
credentials: "same-origin"
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load metadata for " + url);
|
||||
}
|
||||
return await response.json();
|
||||
} catch {
|
||||
console.warn("Can not load metadata for " + url + ", using default value " + defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
export function downloadGlyphsMetadata(urlTemplate: string, cb: (...args: any[]) => void) {
|
||||
if(!urlTemplate) return cb([]);
|
||||
export async function downloadGlyphsMetadata(urlTemplate: string): Promise<string[]> {
|
||||
if(!urlTemplate) return [];
|
||||
|
||||
// Special handling because Tileserver GL serves the fontstacks metadata differently
|
||||
// https://github.com/klokantech/tileserver-gl/pull/104#issuecomment-274444087
|
||||
const urlObj = npmurl.parse(urlTemplate);
|
||||
const normPathPart = "/%7Bfontstack%7D/%7Brange%7D.pbf";
|
||||
const urlObj = new URL(urlTemplate);
|
||||
const normPathPart = "/" + encodeURIComponent("{fontstack}") + "/" + encodeURIComponent("{range}") + ".pbf";
|
||||
if(urlObj.pathname === normPathPart) {
|
||||
urlObj.pathname = "/fontstacks.json";
|
||||
} else {
|
||||
urlObj.pathname = urlObj.pathname!.replace(normPathPart, ".json");
|
||||
}
|
||||
const url = npmurl.format(urlObj);
|
||||
|
||||
loadJSON(url, [], cb);
|
||||
const url = urlObj.toString();
|
||||
const fonts = await loadJSON(url, [] as string[]);
|
||||
return [...new Set(fonts)];
|
||||
}
|
||||
|
||||
export function downloadSpriteMetadata(baseUrl: string, cb: (...args: any[]) => void) {
|
||||
if(!baseUrl) return cb([]);
|
||||
export async function downloadSpriteMetadata(baseUrl: string): Promise<string[]> {
|
||||
if(!baseUrl) return [];
|
||||
const url = baseUrl + ".json";
|
||||
loadJSON(url, {}, glyphs => cb(Object.keys(glyphs)));
|
||||
const glyphs = await loadJSON(url, {} as Record<string, string>);
|
||||
return Object.keys(glyphs);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
border: none;
|
||||
padding: 2px 0;
|
||||
margin-right: 10px;
|
||||
position: absolute;
|
||||
position: absolute !important;
|
||||
overflow: auto;
|
||||
max-height: 50%;
|
||||
background: vars.$color-gray;
|
||||
|
||||
Reference in New Issue
Block a user