Multiple panels with different components/functionality

Greetings,

I have started working on a plugin and ran into an issue. I want multiple tabs in my plugin as putting everything in one tab would just make everything more confusing for the user. I have figured out how to make more tabs using the “entrypoints” in manifest.json, however, I can’t understand how to give the new panel components. I guess the functionality is mostly dependent on the id’s of the components so that shouldn’t matter in the script, but for the html, I am completely stuck. Any help?

What I want to know is if there is some simple way I can just make an HTML file for each tab and then somehow push it into the current panel or if I have to make it somehow differently? The API doesn’t help a lot.

Hi,
when you talk about “tabs”, do you mean panels (e.g., three separate palettes) or actual tabs, like this:
image

In any case, this might help.
Cheers,
—D.

Yes, sorry for not clarifying. I am talking about panels specifically. Didn’t realize there’s a thing called tabs.

I happen to be writing an example answering this very question for the 2nd edition of Professional Photoshop Scripting" :blue_book: (shameless :electric_plug:) like exactly now, this afternoon :grin:

You have your manifest with multiple objects in the entrypoints array, right? They all have their own id, let’s say for simplicity three of them: "pFirst", "pSecond", and "pThird".

At this point, add to index.html three wrapper <div>s, each one with the content for a panel. Give them ids (except the first one, which doesn’t need it). They don’t need to match the ones in the Manifest, but it’s easier.

<body>
  <div id="pFirst"> <!-- Panel 1 stuff --> <div>
  <div id="pSecond"> <!-- Panel 2 stuff --> <div>
  <div id="pThird"> <!-- Panel 3 stuff --> <div>
</body>

Cool. In main.js, add the entrypoints.setup()

const { entrypoints } = require("uxp");

entrypoints.setup({
    // Object containing Panels
panels: {
    "pFirst": { // <- must match the manifest id for panel #1
        // Lifecycle events
        show(body) {
            let content = document.querySelector("pFirst");
            body.appendChild(content);
        },
    },
    "pSecond": { // <- must match the manifest id for panel #2
        // Lifecycle events
        show(body) {
            let content = document.querySelector("pSecond");
            body.appendChild(content);
        },
    },
    "pThird": { // <- must match the manifest id for panel #3
        // Lifecycle events
        show(body) {
            let content = document.querySelector("pThird");
            body.appendChild(content);
        },
    },
});

This links distributes, so to speak, the content from index.html into the three panels.
Please note, the hide() lifecycle callback doesn’t work at all, and show() only fires once at creation, hence there are no concerns about appending duplicate content—otherwise you should removeChild() in the hide().

Bonus: actually, the first show() is not needed, the 1st panel will load its content anyway according to my tests.
Hope this helps!
(there’s more in the :blue_book:, double :electric_plug::electric_plug: :grin:)
Cheers,

—Davide

1 Like

Greetings,

I keep running into issues where the command appendChild doesn’t want to work at all. I get this error

Exception while invoking panel method on Plugin Id: TestYoutubeTutorial, Panel Id: export, Entrypoint: create, TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

Now, I have figured out why it might not work and after some searching it seems that the querySelector is returning a String rather than a node. I exchanged the querySelector for getElementById instead and the issue seems to be fixed. Saying this just so if you by any chance run into someone else with similar issues, you know why it might not work for them either. Of course, there might be a different issue that I just overlooked so if that’s the case, I would love some of your feedback still for future.

Here is the code that works for me now:

entrypoints.setup({

    // Object containing Panels
    panels: {

        "import": { // <- must match the manifest id for panel #1
            // Lifecycle events
            show(body) {
                let content = document.getElementById("import");
                body.appendChild(content);
            },
        },
        "export": { // <- must match the manifest id for panel #2
            // Lifecycle events
            show(body) {
                let content = document.getElementById("export");
                body.appendChild(content);
            },
        },
    }
});

Oh, that’s strange—my code runs fine with querySelector()—but I’m happy you’ve got it working.