Copy link to clipboard
Copied
Hi All,
I am looking for a solution in which I can pass json object as an argument to a scriptable method
I went through the scriptable plugin architecture and created a scriptable resource and added a method on document object as follows
resource VersionedScriptElementInfo(1)
{
//Contexts
{
kCS2ScriptVersion, kCoreScriptManagerBoss, kWildFS, k_Wild,
}
{
Method
{
kTestApplyScriptElement,
e_TestApplyTag,
"apply tag",
"Apply the tag",
Int32Type, // status code
"Status: 0 if ok, non-zero if error"
{
p_TagInfo, "tag info", "tag info ...", RecordType(kAnyObjectScriptElement), kRequired,
}
}
// Connects this plug-in's text attribute to scripting and INX round trip.
Provider
{
kTestProviderBoss,
{
Object{ kDocumentObjectScriptElement },
Method{ kTestApplyScriptElement }
}
}
}
my provider file look like as follows
=====
;
=====
Now what code I should write in TestProvider::ApplyTag to get the key value pair of json object which I send from jsx file while calling this function.
code in jsx file is look like as follows
function test() {
var info = {};
info["name"] = "abc";
info["id"] = "1";
info["address"] = "abc xyz";
info["code"] = "w12";
app.activeDocument.applyTag(info)
}
Please help me to get solve it.
Regards,
Alam
1 Correct answer
I achieved my goals by making following changes.
p_TagInfo, "tag info", "tag info ...", VariableArrayType( kVariableLength ){ StringArrayType(2) }
and use CusDtLnkOptionScriptProvider.cpp for storing data and fetching it.
in jsx file I pass data as follows
var testData = [];
testData.push(["key1", "val1");
testData.push(["key2", "val2");
app.activeDocument.applyTag(testData)
Copy link to clipboard
Copied
Is it possible to pass json object from jsx scripts to c++ plugin? if yes then what scriptDatatype I need to use in fr file and how to extract value in provider.cpp file.
Copy link to clipboard
Copied
JSON is a set of conditions that applies to a string. You can pass strings thru the scripting glue, but those JSON conditions are not enforced. At the C++ side, you'd also have to write your own parser or use e.g. the one provided by boost.
You can not pass arbitrary plain objects - property names must be predeclared in a ScriptInfo resource of any plug-in, the glue code will map the name to a ScriptID using the ScriptInfo database.
When you declare something to be RecordType(yourObjectType), that means the record is to be validated to use only properties from yourObjectType . I don't know whether there is any magic script element ID to accept arbitrary records, your RecordType(kAnyObjectScriptElement) is not used in the application itself. How did you come to that idea?
Anyway, if it works, your method (in the script provider) would have to extract the argument from its ScriptRequestData (ask for p_TagInfo). That would copy the value into a ScriptData. You can examine the ScriptData, ask whether it is indeed a record then extract that into a ScriptRecordData and iterate further on.
If your generic record approach fails, the closest you can get with a scriptable plug-in is to use AnyType instead of that RecordType. For a JavaScript object you'd receive a record with the subset of keys where the name could get found, other properties are just omitted. Of course AnyType would also accept other types (strings, numbers, arrays, native objects etc.), you'd have to weed them out yourself.
Another alternative could be the separate ExtendScript SDK resulting in an ExternalObject, with the disadvantage that ExternalObject is likely not supported in UXP scripting and the SDK is for thrill seekers at best. The SDK used to ship with ESTK, but nowadays the best bet would be the developer downloads of Bridge (the CC app). Be warned that it took me several days to get something going with it and it has many other limitations.
Copy link to clipboard
Copied
I try to use following api in provider class to fetch data that is send from jsx file.
const ScriptRecordData props = data->GetRequestData() ; and iterate it as follows
for ( ScriptRecordData::const_iterator iter = props.begin() ; iter != props.end() ; ++iter )
{
// but iter->Key() returns me scriptId not json key
// I could not debug the plugin because on xcode debug is not working an alert is shown when try to attach.
}
Do I need to follow the approach that is shown in snippetrunner plugin that for kSnpRunnableObjectScriptElement has some properties and for each property they used IStringData or IStringListData
and for my requirments where I have json objects tof 10-12 properties and need to pass that object into scriptable method, Do I need to add 10-12 IStringData interface to my boss class?
and also do I need to inherit my provider class with RepresentScriptProvider.?
Copy link to clipboard
Copied
Moreever in context of snippet runner plugin. in fr file there is a comment that
p_SnpRunnableName is bind to IID_ISNIPPETNAME, where is this binding code written?
Copy link to clipboard
Copied
In your ScriptInfo resource you declare the arguments of your method - namely p_TagInfo . You access the passed argument by that ScriptID using ExtractRequestData(). I already mentioned that above (extract the argument using its ScriptID).
With GetRequestData you get a record of all provided arguments where the argument ScriptID is the record key. Note that some arguments may be optional (see ScriptInfo resource) and missing if not provided by the caller at the JS side.
You should not need to attach Xcode, just launch the plug-in from within:
Go to Product >> Scheme >> Edit Scheme ... , in the "Run" panel, "Info" tab point to the appropriate executable.
Then launch InDesign from within Xcode.
When you follow snippet runner by implementing an own object matching kSnpRunnableObjectScriptElement, you will need a RepresentScriptProvider or something derived. When you just add a method somewhere else, you can stick to a smaller implementation. The use of these string interfaces is an implementation detail of SnippetRunner, not a requirement.
I'm not using SnippetRunner myself, so leaving further details to others. Anyway if I search the SDK with a good editor (excluding Xcode for that task, better have a look at BBEdit or others) there are several hits on IID_ISNIPPETNAME or p_SnpRunnableName. This is about a property of the snippet object, though while above we were talking about a method.
Copy link to clipboard
Copied
Regarding ScriptID vs. JSON key, I also mentioned above that the scripting glue is working on ScriptIDs. It is easier to compare 32 bit integers rather than strings, so all the example code is referring to p_someProperty and m_someMethod for a reason. Also, the mapping must be declared in the ScriptInfo resource, otherwise the particular property will be lost in your call.
If you really need to translate the ScriptID back to a string e.g. for debug output, you have to get hold of the appropriate ScriptInfoManager (see IScriptUtils) - the names are formatted differently per scripting language e.g. AppleScript may break them up using spaces instead of camelCase, while VBScript may use CamelCase ...
Copy link to clipboard
Copied
I achieved my goals by making following changes.
p_TagInfo, "tag info", "tag info ...", VariableArrayType( kVariableLength ){ StringArrayType(2) }
and use CusDtLnkOptionScriptProvider.cpp for storing data and fetching it.
in jsx file I pass data as follows
var testData = [];
testData.push(["key1", "val1");
testData.push(["key2", "val2");
app.activeDocument.applyTag(testData)
Copy link to clipboard
Copied
Thanks Dirk for your reply it helps me in analysis.
on XCode debugging.
After setting InDesign.exe in - Product >> Scheme >> Edit Scheme ... , in the "Run" panel,
Could not find any menu action which launch InDesign.
What menu action in XCode I need to use for launching InDesign
Copy link to clipboard
Copied
In the right "Info" panel see Executable "Adobe InDesign 2022.app". You can change the executable via the dropdown's "Other..." . As a result, the top left icon should become that of InDesign, also in Xcode's project window.
Xcode >> Product >> Run should then launch InDesign, the same way as the triangle button.
Note that different from the example projects I use InDesign version specific build configurations so I can support multiple versions with the same project. You can keep that to the typical pair of release/debug.
Copy link to clipboard
Copied
I followed same approach as you mentioned but application did not launched.
I am attaching screenshot here
Only difference is that I try with Release build as I don't have InDesign debug version.
My XCode version:- 14.1
OSX - 12.6
InDesign Version- CC2022

