Newer
Older
import { PLUGIN_PATH } from "../../../../config";
import * as Graph from "../../graph";
import { CONTEXT } from "../../state";
import ToolMenu from "./toolmenu";
const HIDDEN_CLASS = "hidden";
export const SELECTION_KEY = "selection";
const CONTEXT_NOTHING = "#nothing-selected";
const CONTEXT_NODE = "#node-selected";
const CONTEXT_LINK = "#link-selected";
const NODE_IMG_PREVIEW = "#node-image-preview";
const NODE_DETAIL_IMG_PREVIEW = "#node-detail-image-preview";
const NODE_NAME_ID = "#node-name";
const NODE_IMG_ID = "#node-image";
const NODE_DETAIL_IMG_ID = "#node-detail-image";
const NODE_DESC_ID = "#node-description";
const NODE_TYPE_ID = "#node-type";
const NODE_REF_ID = "#node-references";
const NODE_VIDEO_ID = "#node-video";
const NODE_MENU = [
NODE_NAME_ID,
NODE_IMG_ID,
NODE_DESC_ID,
NODE_TYPE_ID,
NODE_REF_ID,
NODE_VIDEO_ID,
NODE_DETAIL_IMG_ID,
];
const IMAGE_MENU = [NODE_IMG_ID, NODE_DETAIL_IMG_ID];
const IMAGE_FIELDS = [
{
uri: NODE_IMG_ID,
preview: NODE_IMG_PREVIEW,
},
{
uri: NODE_DETAIL_IMG_ID,
preview: NODE_DETAIL_IMG_PREVIEW,
},
];
const MENU = [...NODE_MENU, ...LINK_MENU];
const ERROR_IMG_PATH = PLUGIN_PATH + "editor/images/onerror.png";
export class SelectMenu extends ToolMenu {
constructor() {
super();
this.context = undefined;
this.map = [
{ menu: NODE_NAME_ID, property: Graph.NODE_LABEL },
{ menu: NODE_IMG_ID, property: Graph.NODE_IMAGE },
{ menu: NODE_DESC_ID, property: Graph.NODE_DESCRIPTION },
{ menu: NODE_TYPE_ID, property: Graph.NODE_TYPE },
{ menu: NODE_REF_ID, property: Graph.NODE_REFERENCES },
{ menu: NODE_VIDEO_ID, property: Graph.NODE_VIDEO },
{ menu: NODE_DETAIL_IMG_ID, property: Graph.NODE_DETAIL_IMAGE },
];
this.hooked = false; // Can only hook menu events once, but have to do it later, when they are loaded
}
hookMenu() {
if (IMAGE_MENU.includes(menu)) {
return;
}
// Subscribes to change event for each menu element
this.find(menu).on("change", (e) => {
this.updateValue(menu, e.target.value);
});
});
// 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 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();
this.setImagePreview(uri, imageField.preview);
});
}
getFullImageSource(uri) {
if (uri === "") {
// Show default empty image
return "";
} else if (uri.includes("/")) {
// Is absolute URL
return uri;
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;
if (propertyKey === Graph.NODE_REFERENCES) {
// Explode to list of url-lines
formattedValue = rawValue
.split("\n") // Every line is it's own url
.filter((url) => url); // Remove empty entries
}
return formattedValue;
}
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
toProperty(menu) {
for (var i = 0; i < this.map.length; i++) {
if (this.map[i].menu === menu) {
return this.map[i].property;
}
}
return undefined;
}
toMenu(property) {
for (var i = 0; i < this.map.length; i++) {
if (this.map[i].property === property) {
return this.map[i].menu;
}
}
return undefined;
}
setContext(context) {
if (context === this.context) {
return; // Only do something if it changes
}
// Disable previous context
this.getDomToContext(this.context).addClass(HIDDEN_CLASS);
// Store and activate new context
this.context = context;
this.getDomToContext(this.context).removeClass(HIDDEN_CLASS);
}
getDomToContext(context) {
var id = CONTEXT_NOTHING;
if (context === CONTEXT.link) {
id = CONTEXT_LINK;
} else if (context === CONTEXT.node) {
id = CONTEXT_NODE;
}
return this.find(id);
}
afterSet(key, value) {
if (this.hooked !== true) {
this.hookMenu();
this.hooked = true;
}
if (key !== SELECTION_KEY) {
return;
}
if (value.node) {
this.fillNode(value);
this.setContext(CONTEXT.node);
} else if (value.link) {
this.setContext(CONTEXT.link);
} else {
this.setContext(CONTEXT.nothing);
}
}
fillNode(node) {
NODE_MENU.forEach((menu) => {
var propertyKey = this.toProperty(menu);
var value = node[propertyKey];
var formattedValue = undefined;
if (propertyKey === Graph.NODE_REFERENCES && Array.isArray(value)) {
formattedValue = value.join("\n");
} else {
formattedValue = value;
}
this.find(menu).val(formattedValue);
});
this.find(LINK_NAME_ID).text(Graph.Graph.toStr(link));
LINK_MENU.forEach((menu) => {
this.find(menu).val(link[this.toProperty(menu)]);
});
}