diff --git a/editor/editor.php b/editor/editor.php index 98e57d85dc140f07254f5fc470222609dd7ae2db..2fc3a38c523dd43cfe9aaf965f032e1929147fc4 100644 --- a/editor/editor.php +++ b/editor/editor.php @@ -25,14 +25,14 @@ </br> <label for="node-image">Node Image</label> </br> - <img id="node-image-preview" class="preview-image" src="" /> + <img id="node-image-preview" style="color:red" class="preview-image" src="" /> </br> <input type="text" id="node-image" name="node-image" placeholder="Enter file name or URL" class="bottom-space" /> </br> <label for="node-detail-image">Info Image</label> </br> - <img id="node-detail-image-preview" class="preview-image" src="" /> + <img id="node-detail-image-preview" style="color:red" class="preview-image" src="" /> </br> <input type="text" id="node-detail-image" name="node-detail-image" placeholder="Enter file name or URL" class="bottom-space" /> diff --git a/editor/images/onerror.png b/editor/images/onerror.png new file mode 100644 index 0000000000000000000000000000000000000000..6f1d83eb40f02ea5fc2dc5590f63a04bfb592a99 Binary files /dev/null and b/editor/images/onerror.png differ diff --git a/editor/js/tools/menus/selectmenu.js b/editor/js/tools/menus/selectmenu.js index f564fdd997da1702b260fba29c26c5f4b6a7137b..e5d9478420b813d62cb2cc19f979e9af83614fdf 100644 --- a/editor/js/tools/menus/selectmenu.js +++ b/editor/js/tools/menus/selectmenu.js @@ -1,3 +1,4 @@ +import { PLUGIN_PATH } from "../../../../config"; import * as Graph from "../../graph"; import { CONTEXT } from "../../state"; import ToolMenu from "./toolmenu"; @@ -29,6 +30,7 @@ const NODE_MENU = [ NODE_DETAIL_IMG_ID, ]; +const IMAGE_MENU = [NODE_IMG_ID, NODE_DETAIL_IMG_ID]; const IMAGE_FIELDS = [ { uri: NODE_IMG_ID, @@ -45,6 +47,8 @@ const LINK_MENU = []; const MENU = [...NODE_MENU, ...LINK_MENU]; +const ERROR_IMG_PATH = PLUGIN_PATH + "editor/images/onerror.png"; + export class SelectMenu extends ToolMenu { constructor() { super(); @@ -63,33 +67,69 @@ export class SelectMenu extends ToolMenu { hookMenu() { MENU.forEach((menu) => { + if (IMAGE_MENU.includes(menu)) { + return; + } + // Subscribes to change event for each menu element this.find(menu).on("change", (e) => { - var newValue = e.target.value; - - var propertyKey = this.toProperty(menu); - var formatedValue = this.formatValue(propertyKey, newValue); - - // Modify stored selection - this.values[SELECTION_KEY][propertyKey] = formatedValue; - - // Notify tool - this.tool.onMenuChange( - SELECTION_KEY, - this.values[SELECTION_KEY] - ); + this.updateValue(menu, e.target.value); }); }); - // Special hook for image, to update the shown image with every change + // Special hooks for image, to update the shown image with every change IMAGE_FIELDS.forEach((imageField) => { + // In case image can't be loaded, show message + this.find(imageField.preview).on("error", (e) => { + var img = this.find(e.target); + + // Is source even set? + if (img.attr("src") === undefined || img.attr("src") === "") { + return; + } + + // Show error message + this.setImagePreview(ERROR_IMG_PATH, imageField.preview); + // Maybe graph image should also be updated, but we might not want to overwrite previously saved images. + }); + + // Test images before updating them this.find(imageField.uri).on("change", (e) => { - var uri = e.target.value; - this.setImagePreview(uri, imageField.preview); + var imageSource = e.target.value; + + // If source is empty, always apply it + if (imageSource === undefined || imageSource === "") { + this.updateValue(imageField.uri, imageSource); + this.setImagePreview(imageSource, imageField.preview); + return; + } + + // Try loading the image and only apply it on success + var img = new Image(); + img.addEventListener("load", () => { + this.updateValue(imageField.uri, imageSource); + this.setImagePreview(imageSource, imageField.preview); + }); + img.addEventListener("error", () => { + this.setImagePreview(ERROR_IMG_PATH, imageField.preview); + }); + + img.src = this.getFullImageSource(imageSource); }); }); } + updateValue(menu, newValue) { + var propertyKey = this.toProperty(menu); + var formatedValue = this.formatValue(propertyKey, newValue); + + // Modify stored selection + this.values[SELECTION_KEY][propertyKey] = formatedValue; + + // Notify tool + this.tool.onMenuChange(SELECTION_KEY, this.values[SELECTION_KEY]); + } + updateImagePreviews() { IMAGE_FIELDS.forEach((imageField) => { var uri = this.find(imageField.uri).val(); @@ -97,22 +137,24 @@ export class SelectMenu extends ToolMenu { }); } - setImagePreview(uri, previewId) { - var previewImage = this.find(previewId); - + getFullImageSource(uri) { if (uri === "") { // Show default empty image - previewImage.attr("src", ""); + return ""; } else if (uri.includes("/")) { // Is absolute URL - previewImage.attr("src", uri); + return uri; } else { // Is file name - var url = Graph.IMAGE_SRC + uri; - previewImage.attr("src", url); + return Graph.IMAGE_SRC + uri; } } + setImagePreview(uri, previewId) { + var previewImage = this.find(previewId); + previewImage.attr("src", this.getFullImageSource(uri)); + } + formatValue(propertyKey, rawValue) { var formattedValue = rawValue;