SkillAgentSearch skills...

Plugincc

Toolbox for building Adobe CC extensions with CEP

Install / Use

/learn @bigarobas/Plugincc
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Toolbox for building Adobe CC extensions with CEP

It probably needs a better name ^^

Purpose :

  • minimize code duplication in both contexts (JS / JSX)
  • ease communication between both contexts (JS / JSX)
  • bring independent tools as well as a full framework and workflow based on those tools.
  • no dependencies (except JSON and of course CEP)

To have a better understanding of what is at stake here I recommand you to read this wiki page about "mixed contexts" : Mixed context in Adobe CC extensions with CEP

JSXBridge

This is the central module around which this toolset is made. When creating a JSXBridge for an Object this object is auto implemented with the following methodes :

  • mirror(function_name,function_args,callback_or_expression)
  • bridgeCall(client_id,function_name,function_args,callback_or_expression,scope)
  • getContext()
  • checkContext(ctx)
  • listen(type,handler)
  • dispatch(type,data,scope)

These methodes allow us to :

  • easy mirroring methodes on both sides (JS/JSX)
//Let's say you have 2 files one on JS and the other on JSX context with code on global level :

//on JS side
a = new ClassA();
a.log("HELLO FROM JS");
function ClassA () { 
    this.bridge = new JSXBridge(this,"BRIDGE_ID_X");
    this.log = function(message) {
      //console is defined is JS context so we can use it
      console.log(message);
    }
}

//on JSX side
b = new ClassB();
b.log("HELLO FROM JSX");
function ClassB () { 
    this.bridge = new JSXBridge(this,"BRIDGE_ID_X");
    this.log = function(message) {
      //console is NOT defined is JSX context so we mirror the action to the JS side
      this.mirror('log',message);
    }
}

//RESULT in chrome console (JS context) :
> HELLO FROM JS
> HELLO FROM JSX
  • MIXED CONTEXT : you can also do the same thing with only 1 file (loaded both on JS and JSX context)
var a = new ClassA();
a.log();

function ClassA () { 
    this.bridge = new JSXBridge(this,"BRIDGE_ID_X");
    this.log("HELLO FROM "+this.getContext());
}

ClassA.prototype.log = function (message) {
  if (this.checkContext("js") {
    //console is defined is JS context so we can use it
    console.log(message);
  } else {
    //console is NOT defined is JSX context so we mirror the action to the JS side
    this.mirror('log',message);
  }
}

//RESULT in chrome console (JS context) :
> HELLO FROM js
> HELLO FROM jsx
  • it's also possible to easyly call methodes on both context using bridge names with 5 different scopes :
    • JS (only on JS context)
    • JSX (only on JSX context)
    • CURRENT (only in the CURRENT context (JS or JSX))
    • MIRROR (only in the MIRROR ("opposite") context (JS or JSX))
    • BOTH (in BOTH contexts (JS and JSX))
//on JS side
var a = new ClassA();
function ClassA () { 
    this.bridge = new JSXBridge(this,"BRIDGE_ID_X");
    this.doSomething = function() {
        //DOES SOMETHING
    }
}

//on JSX side
var b = new ClassB();
function ClassB () { 
    this.bridge = new JSXBridge(this,"BRIDGE_ID_X");
    this.doSomething = function() {
      //DOES SOMETHING ELSE
    }
}

//SOME WHERE IN JS OR JSX CONTEXT
var c = new ClassC();
function ClassC () { 
    this.bridge = new JSXBridge(this,"ANOTHER_BRIDGE_ID");
    this.bridgeCall("BRIDGE_ID_X","doSomething",{some_args_if_needed},callback_function_or_expression,"both");
}

//RESULT 
> c calls methode "doSomething" on "BRIDGE_ID_X" bridge (linked to a in JS conetxt and b in JSX context) with scope = "both".
> which means that both "doSomething" methodes from both context (a in JS and b in JSX) are called :
> a DOES SOMETHING in JS context
> b DOES SOMETHING ELSE in JSX context
  • the mirror methode takes a callback_or_expression argument depending on the context it's called on :
    • a callback function if it's called from JS context (that will be called with the mirror JSX function return value).
    • a callback expression if it's called from JSX context (that will be evaluated with the JS function return value). This expression contain key_words ({bridge} and {args}) which will dynamically be replaced before the expression is evaluated.
// imagine we want to synch a MIXED OBJECT (1 jsx file loaded in both contexts JS & JSX)
// we need to push the update to the other context and retrieve the new updated state to synch back with the first object
// 
this.synch = function(onComplete) {
    this.onSynchComplete = onComplete;
    var _self = this;
    if (this.checkContext("jsx")) {
        this.mirror(
            'update',
            this.data,
            '(function() {\
                {bridge}.update({args});\
                {bridge}.onSynchComplete({args});\
            })();'
        );
    } else {
        this.mirror(
            'update',
            this.data,
            function(json) {
                _self.update(json);
                _self.onSynchComplete(json);
            }
        );
    }  
}

this.update(data) {
    //update with data
    //return new state
}
  • easy communication between objects in both contexts with a custom Observer pattern that let you dispatch custom JSXBridgeEvents with 5 different scopes :
    • JS (only JSXBridge objects on JS context can receive the event)
    • JSX (only JSXBridge objects on JSX context can receive the event)
    • SAME (only JSXBridge objects in the SAME context (JS or JSX) can receive the event)
    • MIRROR (only JSXBridge objects in the MIRROR ("opposite") context (JS or JSX) can receive the event)
    • BOTH (JSXBridge objects in BOTH contexts (JS and JSX) can receive the event)
//IMPORTING THE MODULE
  // JS SIDE
  Configuration =  require(__EXTENTION_PATH__ + "/CORE/mixed/JSXBridge.jsx");
  // JSX SIDE
  $.evalFile(__EXTENTION_PATH__ + "/CORE/mixed/JSXBridge.jsx");
  
// IN AN OBJECT IN JS CONTEXT
var _bridge = new JSXBridge(this,"SOME_BRIDGE_ID");
this.listen("a_custom_event_type",function(event) {(...)});
this.dispatch("a_custom_event_type",some_data_object,"mirror");

// IN AN OBJECT IN JSX CONTEXT
var _bridge = new JSXBridge(this,"SAME_OR_OTHER_BRIDGE_ID");
this.listen("a_custom_event_type",function(event) {(...)});
this.dispatch("a_custom_event_type",some_data_object,"both")

/*
# RESULT ON JSX SIDE :
The JSX bridge will receive 2 events with "a_custom_event_type".
1 from its own dispatch because it was on "both" scope.
1 from JS context's dispatch because it was on "mirror" scope = the opposite context of JS = JSX.
In this case the mirror (opposite) of JS is of course JSX.

# RESULT ON JS SIDE :
The JS bridge will receive only 1 event with "a_custom_event_type".
0 from its own dispatch because it was on "mirror" scope = the opposite context of it's own = JSX.
1 from JSX context's dispatch because it was on "both" scope.
*/

Configuration

  • Mixed Configuration object synched and available in both contexts (JS ad JSX)
//IMPORTING THE MODULE
  // JS SIDE
  Configuration =  require(__EXTENTION_PATH__ + "/CORE/mixed/Configuration.jsx");

  // JSX SIDE
  $.evalFile(__EXTENTION_PATH__ + "/CORE/mixed/Configuration.jsx");
  
// ON BOTH SIDES
CONFIG = new Configuration("CONFIG");
CONFIG.update(json); // update with some json. existing keys are updated / non existing keys are created
CONFIG.set("some_key",some_value); // set a value to a key
CONFIG.get("some_key"); // get a value of a key
CONFIG.synch(); // synch the config with the other context

synch() is the most interresting part :

It synchronizes the config with the other context (JSX if you are in JS and JS if you're in JSX).

For now the synch is a "push prioritised". This means that the values are pushed to the the other side. Existing keys are updated / non existing keys are created. Then key/values are pulled to synch. Existing keys are updated (which should not happen) / non existing keys are created.

We might have the other option "pull prioritised" too in the future. This means the key/values are pulled from the other context. Existing keys are updated / non existing keys are created. Then key/values are pushed to synch. Existing keys are updated (which should not happen) / non existing keys are created.

Debugger

  • Mixed Multichanel Debugger available in both contexts (JS ad JSX)
// IMPORTING THE MODULE
  // JS SIDE
  Debugger = require(__EXTENTION_PATH__ + "/CORE/mixed/Debugger.jsx");
  // JSX SIDE
  $.evalFile(__EXTENTION_PATH__ + "/CORE/mixed/Debugger.jsx");
  
// USING THE MODULE (ON BOTH SIDE)
DEBUG = new Debugger();
DEBUG.log("Hello World");
  • create channels and sub channels :
DEBUG.channel("main_channel_branch_name").channel("sub_channel_branch_name").log("Hello World");
  • manage / costumise channels :
DEBUG.channel("main_channel_branch_name").mute(isCompletelyMuted);
DEBUG.channel("main_channel_branch_name").setVerbose(isWriteMuted,isAlertMutedn,isChannelIdPrefixDisplayed); 
DEBUG.channel("main_channel_branch_name").setSeparator("-._.-._.-._.-._.-._.-._.-._.-._.-._.-");
  • supporting multiple write & alert methodes :
    • write(message)
    DEBUG.channel("some_channel_name").write("Hello World");
    // JSX : JSX : mirrored to chrome.console.log instead of $.write / JS : chrome.console.log
    
    • writeln(message)
    DEBUG.channel("some_channel_name").writeln("Hello World");
    // JSX : mirrored to chrome.console.log instead of $.writeln / JS : chrome.console.log
    
    • log(message)
    DEBUG.channel("some_channel_name").log("Hello World");
    // JSX : mirrored to chrome.console.log instead of $.writeln / JS : chrome.console.log
    // the same than .writeln()
    
    • json(someObject)
    DEBUG.channel("some_channel_name").json(someObject);
    // .writeln() + JSON.stringify()
    
    • popup(message)
    DEBUG.channel("some_channel_name").popup(message);
    // application alert
    
View on GitHub
GitHub Stars8
CategoryDevelopment
Updated3mo ago
Forks0

Languages

JavaScript

Security Score

72/100

Audited on Dec 9, 2025

No findings