Skip to content
Snippets Groups Projects
selectmenu.js 7.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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 LINK_NAME_ID = "#link-name";
    
    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();
            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() {
    
            MENU.forEach((menu) => {
    
                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);
            });
        }
    
    
            if (uri === "") {
                // Show default empty image
    
            } else if (uri.includes("/")) {
                // Is absolute URL
    
            } else {
                // Is file name
    
                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;
        }
    
    
        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.fillLink(value);
    
                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.updateImagePreviews();
    
    
        fillLink(link) {
    
            this.find(LINK_NAME_ID).text(Graph.Graph.toStr(link));
    
    
            LINK_MENU.forEach((menu) => {
                this.find(menu).val(link[this.toProperty(menu)]);
            });
        }