Mini Kabibi Habibi
//
// Copyright 2023 Adobe, Inc. All Rights Reserved.
//
// This is generic code to display an "info" box, usually invoked by
// pressing an ⓘ button. The position of the dialog relative to the app
// is given by the leftoffset, topoffset attributes.
//
// 100+ lines of code to - display a dialog. Where did we go wrong?
//
const uxp = require("uxp");
const photoshop = require("photoshop");
// I'm kinda missing jQuery
$getID = (key) => document.querySelector(key);
$getList = (key) => document.querySelectorAll(key);
// Searches up the parent tree for a paricular tag (DIV, DIALOG, FORM, etc.)
function getParentByTag(item, tag)
{
var curItem = item.parentElement;
while (curItem && (curItem.tagName != tag))
curItem = curItem.parentElement;
return curItem;
}
///////////////////////////////////////////////////////////
// User interface
///////////////////////////////////////////////////////////
// Debug - used to make the first cut of the localization file from the HTML
function makeLocalizeJSON()
{
let locItems = $getList(".loc");
locItems.forEach( function(item)
{
// "commit_new_layer": "Nytt lag",
if (item.tagName == "SP-BODY") {
// The body is handled as a block of HTML so the formatting is retained.
console.log('"'+item.id + '": "'+ item.innerHTML.replace("\n", " ")+'",');
}
else
console.log('"'+item.id+'": "'+item.textContent+'",');
})
}
// UXP can only position dialogs by raw screen coordinates. This fetches the location
// of the PS application frame, so we can adjust the coordinates relative to that frame.
async function getAppCoords(alertID)
{
// Determine staging vs. production at startup; set global flag.
// First, check if we're on pre-release or release....
let getFrameDesc = {"_obj": "owlAction",
"_target":[{"_enum":"ordinal", "_ref":"application", "_value":"targetEnum"}],
"owlCommand":"getApplicationFrameInfo"};
let frameDesc = await photoshop.action.batchPlay( [getFrameDesc], {} );
let appRect = frameDesc[0].globalBounds;
// Once we have the frame, invoke the alert display in a then() clause.
// Then only allows one arg, so we have to mush the parameters together.
return new Promise( function(resolve, reject) {
resolve({"id":alertID, "bounds":appRect});
});
}
// Open the Info dialog
function displayInfoDialog(args)
{
let alertID = args.id;
let appRect = args.bounds;
let dialog = $getID("#" + alertID);
let offset = {left: appRect.left + Number(dialog.getAttribute("leftoffset")),
top: appRect.top + Number(dialog.getAttribute("topoffset"))};
dialog.show( {
titleVisibility: "hide",
title: photoshop.core.translateUIString( "$$$/Photoshop/infoDialog/dialogTitle=Information" ),
anchorOffset: offset});
// Hide the debug button, if present
let debugButton = $getID("#debug");
if (debugButton)
debugButton.style.display = 'none';
// Run all of the text through localization
let locItems = $getList(".loc");
locItems.forEach( function(item)
{
if (item.tagName == "SP-BODY")
// The body is handled as a block of HTML so the formatting is retained.
item.innerHTML = photoshop.core.translateUIString( "$$$/Photoshop/infoAlert/"+item.id+"="+item.innerHTML);
else
item.textContent = photoshop.core.translateUIString( "$$$/Photoshop/infoAlert/"+item.id+"="+item.textContent);
});
}
function runDisplayInfoDialog(alertID)
{
getAppCoords(alertID).then(displayInfoDialog);
}
// Walk through all of the close buttons, and give them a close onclick() method
$getList(".closebutton").forEach( function( button) {
button.onclick = function() { getParentByTag(this, "DIALOG").close(); }
});
// Debug button (normally hidden). This is a way of testing
// functionality w/o closing & re-opening the panel.
var debugButton = $getID("#debug");
if (debugButton)
debugButton.onclick = function()
{
console.log("Stop here to debug");
console.log("done");
}
// Entry points invoked from Photoshop. The ID corresponds to the alert invoked.
// Must match the ID in the HTML.
// Add a separate entry for each dialog added.
function displayCropFillInfo() { runDisplayInfoDialog("cropFillInfo"); }
// This seems to be just window dressing. The actual entry point is
// determined by the call to InvokeSynchronousExtensionCommand in
// Photoshop
function infoAlertInit() {}
uxp.entrypoints.setup({
commands: {
infoAlert: () => infoAlertInit()
}
});