├── .gitignore ├── README.md ├── ae ├── .env.production ├── .github │ └── workflows │ │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── cep.config.ts ├── package.json ├── src │ ├── script │ │ ├── global.d.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── .gitattributes │ │ │ └── json2.js │ │ ├── src │ │ │ ├── aeft.ts │ │ │ └── getPropertyPath.ts │ │ ├── tsconfig.json │ │ └── utils │ │ │ ├── aeft-utils.ts │ │ │ └── utils.ts │ ├── shared │ │ ├── shared.ts │ │ └── universals.d.ts │ └── ui │ │ ├── assets │ │ ├── adobe.svg │ │ ├── bolt-cep-react.png │ │ ├── bolt-cep-vue.png │ │ ├── bolt-cep.svg │ │ ├── node-js.svg │ │ ├── react.svg │ │ ├── sass.svg │ │ ├── typescript.svg │ │ ├── vite.svg │ │ └── vue.svg │ │ ├── favicon.svg │ │ ├── index.scss │ │ ├── lib │ │ ├── cep │ │ │ ├── .gitattributes │ │ │ ├── cep-types.d.ts │ │ │ ├── cep_engine_extensions.js │ │ │ ├── csinterface.d.ts │ │ │ ├── csinterface.js │ │ │ ├── es-types │ │ │ │ └── index.ts │ │ │ ├── node.ts │ │ │ ├── vulcan.d.ts │ │ │ └── vulcan.js │ │ └── utils │ │ │ ├── aeft.ts │ │ │ ├── bolt.ts │ │ │ └── cep.ts │ │ ├── linting │ │ ├── eslintConfig.ts │ │ ├── eslintErrorsToMonacoMarkers.ts │ │ ├── lint.ts │ │ └── rules │ │ │ └── no-ending-with-function-declaration.ts │ │ ├── main │ │ ├── index.html │ │ ├── index.tsx │ │ ├── main.scss │ │ └── main.tsx │ │ ├── monaco │ │ ├── editorActions.tsx │ │ ├── monacoConfig.tsx │ │ ├── typeDefsLibrary.tsx │ │ ├── useMonaco.tsx │ │ └── userWorker.ts │ │ └── types │ │ ├── eslint4b-prebuilt.d.ts │ │ ├── global.d.ts │ │ └── vite-env.d.ts ├── tsconfig.json ├── vite.config.ts ├── vite.es.config.ts └── yarn.lock ├── common ├── defaultCode.ts └── onedarkpro-theme.json └── web ├── .gitignore ├── .nvmrc ├── index.html ├── package.json ├── src ├── App.jsx ├── index.css ├── main.tsx └── vite-env.d.ts ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Editor 2 | 3 | > A code editor for After Effects Expressions 4 | 5 | ## After Effects 6 | 7 | `/ae` contains the CEP extension, built with [bolt-cep](https://github.com/hyperbrew/bolt-cep). 8 | 9 | ## Web 10 | 11 | `/web` contains the web version, built with Vite. Available at [editor.motiondeveloper.com](https://editor.motiondeveloper.com). 12 | -------------------------------------------------------------------------------- /ae/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV=production -------------------------------------------------------------------------------- /ae/.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: ZXP Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*.*.*" 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | 12 | strategy: 13 | matrix: 14 | node-version: [15.x] 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Use Node.js ${{ matrix.node-version }} 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | - run: npm install yarn -g 22 | - run: yarn 23 | - run: yarn build 24 | - run: yarn zxp 25 | 26 | - name: GitHub Release 27 | uses: softprops/action-gh-release@v1 28 | if: startsWith(github.ref, 'refs/tags/') 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | SOURCE_NAME: ${{ steps.extract_names.outputs.SOURCE_NAME }} 32 | SOURCE_BRANCH: ${{ steps.extract_names.outputs.SOURCE_BRANCH }} 33 | SOURCE_TAG: ${{ steps.extract_names.outputs.SOURCE_TAG }} 34 | with: 35 | files: ./public/zxp/com.bolt.cep.zxp 36 | -------------------------------------------------------------------------------- /ae/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | dist 7 | yarn-error.log -------------------------------------------------------------------------------- /ae/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Hyper Brew LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ae/README.md: -------------------------------------------------------------------------------- 1 | # Editor After Effects extension 2 | 3 | An expressions editor After Effects plugin built on top of [Monaco](https://github.com/microsoft/monaco-editor), the editor that powers VS Code. 4 | 5 | It includes type definitions for the expressions API via [expression-globals-typescript](https://github.com/motiondeveloper/expression-globals-typescript), providing: 6 | 7 | - Autocomplete 8 | - Type-checking 9 | - JSDoc comments 10 | 11 | It's built using [Bolt CEP](https://github.com/hyperbrew/bolt-cep/) framework from HyperBrew. That repo contains more information on how to develop the extension. 12 | 13 | ## Development 14 | 15 | **Prerequisites:** git, node and yarn classic (`yarn set version classic`). 16 | 17 | ```sh 18 | # clone the repo 19 | git clone https://github.com/motiondeveloper/editor.git 20 | # enter the directory for the ae extension 21 | cd editor/ae 22 | # install the dependencies 23 | yarn 24 | # do an initial build (first time only) 25 | yarn build 26 | # add a symlink to the dev build in your extensions folder 27 | yarn symlink 28 | # run the extension in dev mode 29 | yarn dev 30 | ``` 31 | 32 | Then open After Effects and open "Editor" in the Extensions menu. 33 | 34 | ## Known issues 35 | 36 | Currently the editor is working well in dev mode. In production it's pretty broken, the text editor works but the rest of the buttons don't, and the hover UI is buggy. 37 | -------------------------------------------------------------------------------- /ae/cep.config.ts: -------------------------------------------------------------------------------- 1 | import { CEP_Config } from "vite-cep-plugin"; 2 | import { version } from "./package.json"; 3 | 4 | const config: CEP_Config = { 5 | version, 6 | id: "com.motiondeveloper.editor", 7 | displayName: "Editor", 8 | symlink: "local", 9 | port: 3001, 10 | servePort: 5001, 11 | startingDebugPort: 8861, 12 | extensionManifestVersion: 6.0, 13 | requiredRuntimeVersion: 9.0, 14 | hosts: [ 15 | { 16 | name: "AEFT", 17 | version: "[0.0,99.9]", 18 | }, 19 | ], 20 | 21 | type: "Panel", 22 | iconDarkNormal: "./src/assets/light-icon.png", 23 | iconNormal: "./src/assets/dark-icon.png", 24 | iconDarkNormalRollOver: "./src/assets/light-icon.png", 25 | iconNormalRollOver: "./src/assets/dark-icon.png", 26 | parameters: ["--enable-nodejs", "--mixed-context"], 27 | width: 500, 28 | height: 550, 29 | 30 | panels: [ 31 | { 32 | mainPath: "./main/index.html", 33 | name: "main", 34 | panelDisplayName: "Editor", 35 | autoVisible: true, 36 | width: 600, 37 | height: 650, 38 | }, 39 | ], 40 | 41 | build: { 42 | jsxBin: "off", 43 | sourceMap: true, 44 | }, 45 | zxp: { 46 | country: "US", 47 | province: "CA", 48 | org: "MyCompany", 49 | password: "mypassword", 50 | tsa: "http://timestamp.digicert.com/", 51 | sourceMap: false, 52 | jsxBin: "off", 53 | }, 54 | installModules: [], 55 | copyAssets: [], 56 | }; 57 | export default config; 58 | -------------------------------------------------------------------------------- /ae/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bolt-cep", 3 | "version": "0.0.9", 4 | "scripts": { 5 | "dev": "vite", 6 | "debug": "cross-env DEBUG_REACT=true vite build --watch true", 7 | "tools": "react-devtools", 8 | "watch": "tsc && vite build --watch true", 9 | "build": "rimraf dist/* && vite build --watch false", 10 | "zxp": "cross-env ZXP_PACKAGE=true vite build --watch false", 11 | "serve": "cross-env SERVE_PANEL=true vite preview", 12 | "symlink": "cross-env ACTION=symlink vite", 13 | "delsymlink": "cross-env ACTION=delsymlink vite" 14 | }, 15 | "dependencies": { 16 | "eslint4b-prebuilt": "^6.7.2", 17 | "expression-globals-typescript": "^3.3.0", 18 | "lz-string": "^1.4.4", 19 | "monaco-editor": "^0.33.0", 20 | "prettier": "^2.7.1", 21 | "react": "^18.2.0", 22 | "react-dom": "^18.2.0" 23 | }, 24 | "devDependencies": { 25 | "@babel/core": "^7.19.0", 26 | "@babel/plugin-proposal-class-properties": "^7.17.12", 27 | "@babel/plugin-proposal-object-rest-spread": "^7.18.0", 28 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 29 | "@babel/plugin-transform-runtime": "^7.18.5", 30 | "@babel/preset-env": "^7.19.0", 31 | "@babel/preset-react": "^7.17.12", 32 | "@babel/preset-typescript": "^7.17.12", 33 | "@babel/runtime": "^7.18.3", 34 | "@rollup/plugin-babel": "^5.3.1", 35 | "@rollup/plugin-commonjs": "^22.0.0", 36 | "@rollup/plugin-image": "^2.1.1", 37 | "@rollup/plugin-json": "^4.1.0", 38 | "@rollup/plugin-node-resolve": "^13.3.0", 39 | "@rollup/plugin-replace": "^4.0.0", 40 | "@types/eslint": "^8.4.3", 41 | "@types/fs-extra": "^9.0.13", 42 | "@types/lz-string": "^1.3.34", 43 | "@types/node": "^18.0.0", 44 | "@types/prettier": "^2.6.3", 45 | "@types/react": "^18.0.14", 46 | "@types/react-dom": "^18.0.5", 47 | "@types/trusted-types": "^2.0.2", 48 | "@types/ws": "^8.5.3", 49 | "@vitejs/plugin-react": "^1.3.2", 50 | "@vitejs/plugin-vue": "^2.3.3", 51 | "babel-plugin-react-require": "^3.1.3", 52 | "babel-plugin-transform-scss": "^1.1.0", 53 | "babel-preset-env": "^1.7.0", 54 | "core-js": "3.23.2", 55 | "cross-env": "^7.0.3", 56 | "fs-extra": "^10.1.0", 57 | "react-devtools": "^4.24.7", 58 | "rimraf": "^3.0.2", 59 | "rollup": "^2.75.7", 60 | "rollup-plugin-multi-input": "^1.3.1", 61 | "rollup-plugin-node-copy": "^1.0.4", 62 | "rollup-plugin-scss": "^3.0.0", 63 | "sass": "^1.53.0", 64 | "types-for-adobe": "^7.2.0", 65 | "types-for-adobe-extras": "^0.0.6", 66 | "typescript": "^4.6.4", 67 | "vite": "5.2.11", 68 | "vite-cep-plugin": "^1.1.12", 69 | "yarn": "^1.22.19" 70 | }, 71 | "resolutions": { 72 | "typescript": "4.6.4", 73 | "vite": "4.5.2" 74 | }, 75 | "main": "index.js", 76 | "license": "MIT" 77 | } 78 | -------------------------------------------------------------------------------- /ae/src/script/global.d.ts: -------------------------------------------------------------------------------- 1 | //@ts-ignore 2 | declare var JSON: { 3 | stringify(object: object): string; 4 | parse(string: string): object; 5 | }; 6 | -------------------------------------------------------------------------------- /ae/src/script/index.ts: -------------------------------------------------------------------------------- 1 | // @include './lib/json2.js' 2 | 3 | import { ns } from "../shared/shared"; 4 | import { 5 | getCurrentExpression, 6 | getPropertyPath, 7 | setCurrentExpression, 8 | } from "./src/aeft"; 9 | import { dispatchTS } from "../ui/lib/utils/bolt"; 10 | 11 | const scripts = { getCurrentExpression, getPropertyPath, setCurrentExpression }; 12 | 13 | //@ts-ignore 14 | const host = typeof $ !== "undefined" ? $ : window; 15 | host[ns] = scripts; 16 | 17 | export type Scripts = typeof scripts; 18 | -------------------------------------------------------------------------------- /ae/src/script/lib/.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-detectable=false -------------------------------------------------------------------------------- /ae/src/script/lib/json2.js: -------------------------------------------------------------------------------- 1 | "object"!=typeof JSON&&(JSON={}),function(){"use strict";var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta,rep;function f(t){return t<10?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;r prop instanceof Property && prop.canSetExpression 11 | )[0]; 12 | 13 | if (property instanceof Property) { 14 | return property.expression; 15 | } 16 | 17 | return undefined; 18 | } 19 | 20 | export function setCurrentExpression(expressionText: string) { 21 | const comp = getActiveComp(); 22 | const properties = filter( 23 | comp.selectedProperties, 24 | (prop) => prop instanceof Property && prop.canSetExpression 25 | ); 26 | 27 | if (properties.length < 1) return; 28 | 29 | app.beginUndoGroup("Set expression"); 30 | 31 | forEach(properties, (prop) => (prop.expression = expressionText)); 32 | 33 | app.endUndoGroup(); 34 | } 35 | -------------------------------------------------------------------------------- /ae/src/script/src/getPropertyPath.ts: -------------------------------------------------------------------------------- 1 | import { getActiveComp } from "../utils/aeft-utils"; 2 | 3 | const propCompactEnglishExpressions = { 4 | "ADBE Transform Group": () => "transform", 5 | // Handle camera/light vs. AV layers 6 | "ADBE Anchor Point": (prop: Property | PropertyGroup) => 7 | prop.propertyGroup(prop.propertyDepth).property("intensity") != null || 8 | prop.propertyGroup(prop.propertyDepth).property("zoom") != null 9 | ? ".pointOfInterest" 10 | : ".anchorPoint", 11 | "ADBE Position": () => ".position", 12 | "ADBE Scale": () => ".scale", 13 | "ADBE Orientation": () => ".orientation", 14 | "ADBE Rotate X": () => ".xRotation", 15 | "ADBE Rotate Y": () => ".yRotation", 16 | // Handle 3D vs. 2D layers 17 | "ADBE Rotate Z": (prop: Property | PropertyGroup) => 18 | prop.propertyGroup(prop.propertyDepth).property("threeDLayer") || 19 | prop.propertyGroup(prop.propertyDepth).property("intensity") != null || 20 | prop.propertyGroup(prop.propertyDepth).property("zoom") != null 21 | ? ".zRotation" 22 | : ".rotation", 23 | "ADBE Opacity": () => ".opacity", 24 | "ADBE Material Options Group": () => "materialOption", 25 | "ADBE Casts Shadows": () => ".castsShadows", 26 | "ADBE Light Transmission": () => ".lightTransmission", 27 | "ADBE Accepts Shadows": () => ".acceptsShadows", 28 | "ADBE Accepts Lights": () => ".acceptsLights", 29 | "ADBE Ambient Coefficient": () => ".ambient", 30 | "ADBE Diffuse Coefficient": () => ".diffuse", 31 | "ADBE Specular Coefficient": () => ".specular", 32 | "ADBE Shininess Coefficient": () => ".shininess", 33 | "ADBE Metal Coefficient": () => ".metal", 34 | 35 | "ADBE Light Options Group": () => "lightOption", 36 | "ADBE Light Intensity": () => ".intensity", 37 | "ADBE Light Color": () => ".color", 38 | "ADBE Light Cone Angle": () => ".coneAngle", 39 | "ADBE Light Cone Feather 2": () => ".coneFeather", 40 | //"ADBE Casts Shadows": () => ".castsShadows", // Already covered previously 41 | "ADBE Light Shadow Darkness": () => ".shadowDarkness", 42 | "ADBE Light Shadow Diffusion": () => ".shadowDiffusion", 43 | 44 | "ADBE Camera Options Group": () => "cameraOption", 45 | "ADBE Camera Zoom": () => ".zoom", 46 | "ADBE Camera Depth of Field": () => ".depthOfField", 47 | "ADBE Camera Focus Distance": () => ".focusDistance", 48 | "ADBE Camera Aperture": () => ".aperture", 49 | "ADBE Camera Blur Level": () => ".blurLevel", 50 | 51 | "ADBE Text Properties": () => "text", 52 | "ADBE Text Document": () => ".sourceText", 53 | "ADBE Text Path Options": () => ".pathOption", 54 | "ADBE Text Path": () => ".path", 55 | "ADBE Text Reverse Path": () => ".reversePath", 56 | "ADBE Text Perpendicular To Path": () => ".perpendicularToPath", 57 | "ADBE Text Force Align Path": () => ".forceAlignment", 58 | "ADBE Text First Margin": () => ".firstMargin", 59 | "ADBE Text Last Margin": () => ".lastMargin", 60 | "ADBE Text More Options": () => ".moreOption", 61 | "ADBE Text Anchor Point Option": () => ".anchorPointGrouping", 62 | "ADBE Text Anchor Point Align": () => ".groupingAlignment", 63 | "ADBE Text Render Order": () => ".fillANdStroke", 64 | "ADBE Text Character Blend Mode": () => ".interCharacterBlending", 65 | 66 | "ADBE Text Animators": () => ".animator", 67 | //"ADBE Text Animator": () => "", // No equivalent 68 | "ADBE Text Selectors": () => ".selector", 69 | //"ADBE Text Selector": () => "", // No equivalent 70 | "ADBE Text Percent Start": () => ".start", 71 | "ADBE Text Percent End": () => ".end", 72 | "ADBE Text Percent Offset": () => ".offset", 73 | "ADBE Text Index Start": () => ".start", 74 | "ADBE Text Index End": () => ".end", 75 | "ADBE Text Index Offset": () => ".offset", 76 | "ADBE Text Range Advanced": () => ".advanced", 77 | "ADBE Text Range Units": () => ".units", 78 | "ADBE Text Range Type2": () => ".basedOn", 79 | "ADBE Text Selector Mode": () => ".mode", 80 | "ADBE Text Selector Max Amount": () => ".amount", 81 | "ADBE Text Range Shape": () => ".shape", 82 | "ADBE Text Selector Smoothness": () => ".smoothness", 83 | "ADBE Text Levels Max Ease": () => ".easeHigh", 84 | "ADBE Text Levels Min Ease": () => ".easeLow", 85 | "ADBE Text Randomize Order": () => ".randomizeOrder", 86 | "ADBE Text Random Seed": () => ".randomSeed", 87 | //"ADBE Text Wiggly Selector": () => "", // No equivalent 88 | "ADBE Text Wiggly Max Amount": () => ".maxAmount", 89 | "ADBE Text Wiggly Min Amount": () => ".minAmount", 90 | "ADBE Text Temporal Freq": () => ".wigglesSecond", 91 | "ADBE Text Character Correlation": () => ".correlation", 92 | "ADBE Text Temporal Phase": () => ".temporalPhase", 93 | "ADBE Text Spatial Phase": () => ".spatialPhase", 94 | "ADBE Text Wiggly Lock Dim": () => ".lockDimensions", 95 | "ADBE Text Wiggly Random Seed": () => ".randomSeed", 96 | //"ADBE Text Expressible Selector": () => "", // No equivalent 97 | "ADBE Text Expressible Amount": () => ".amount", 98 | "ADBE Text Animator Properties": () => ".property", 99 | "ADBE Text Anchor Point 3D": () => ".anchorPoint", 100 | "ADBE Text Position 3D": () => ".position", 101 | "ADBE Text Scale 3D": () => ".scale", 102 | "ADBE Text Skew": () => ".skew", 103 | "ADBE Text Skew Axis": () => ".skewAxis", 104 | "ADBE Text Rotation X": () => ".xRotation", 105 | "ADBE Text Rotation Y": () => ".yRotation", 106 | "ADBE Text Rotation": () => ".zRotation", 107 | "ADBE Text Opacity": () => ".opacity", 108 | "ADBE Text Fill Opacity": () => ".fillOpacity", 109 | "ADBE Text Fill Color": () => ".fillColor", 110 | "ADBE Text Fill Hue": () => ".fillHue", 111 | "ADBE Text Fill Saturation": () => ".fillSaturation", 112 | "ADBE Text Fill Brightness": () => ".fillBrightness", 113 | "ADBE Text Stroke Opacity": () => ".strokeOpacity", 114 | "ADBE Text Stroke Color": () => ".strokeColor", 115 | "ADBE Text Stroke Hue": () => ".strokeHue", 116 | "ADBE Text Stroke Saturation": () => ".strokeSaturation", 117 | "ADBE Text Stroke Brightness": () => ".strokeBrightness", 118 | "ADBE Text Stroke Width": () => ".strokeWidth", 119 | "ADBE Text Line Anchor": () => ".lineAnchor", 120 | "ADBE Text Line Spacing": () => ".lineSpacing", 121 | "ADBE Text Track Type": () => ".trackingType", 122 | "ADBE Text Tracking Amount": () => ".trackingAmount", 123 | "ADBE Text Character Change Type": () => ".characterAlignment", 124 | "ADBE Text Character Range": () => ".characterRange", 125 | "ADBE Text Character Replace": () => ".characterValue", 126 | "ADBE Text Character Offset": () => ".characterOffset", 127 | "ADBE Text Blur": () => ".blur", 128 | 129 | "ADBE Mask Parade": () => "mask", 130 | "ADBE Mask Shape": () => ".maskPath", 131 | "ADBE Mask Feather": () => ".maskFeather", 132 | "ADBE Mask Opacity": () => ".maskOpacity", 133 | "ADBE Mask Offset": () => ".maskExpansion", 134 | 135 | "ADBE Effect Parade": () => "effect", 136 | 137 | //"ADBE Paint": () => "", 138 | //"ADBE Paint On Transparent": () => "", 139 | "ADBE Paint Group": () => ".stroke", 140 | //"ADBE Paint Atom": () => "", 141 | //"ADBE Paint Transfer Mode": () => "", 142 | //"ADBE Paint Duration": () => "", 143 | "ADBE Paint Shape": () => ".path", 144 | "ADBE Paint Properties": () => ".strokeOption", 145 | "ADBE Paint Begin": () => ".start", 146 | "ADBE Paint End": () => ".end", 147 | "ADBE Paint Color": () => ".color", 148 | "ADBE Paint Diameter": () => ".diameter", 149 | "ADBE Paint Angle": () => ".angle", 150 | "ADBE Paint Hardness": () => ".hardness", 151 | "ADBE Paint Roundness": () => ".roundness", 152 | "ADBE Paint Tip Spacing": () => ".spacing", 153 | "ADBE Paint Target Channels": () => ".channels", 154 | "ADBE Paint Opacity": () => ".opacity", 155 | "ADBE Paint Flow": () => ".flow", 156 | "ADBE Paint Clone Layer": () => ".cloneSource", 157 | "ADBE Paint Clone Position": () => ".clonePosition", 158 | "ADBE Paint Clone Time": () => ".cloneTime", 159 | "ADBE Paint Clone Time Shift": () => ".cloneTimeShift", 160 | //"ADBE Paint Clone Source Type": () => "", 161 | "ADBE Paint Transform": () => ".transform", 162 | "ADBE Paint Anchor Point": () => ".anchorPoint", 163 | "ADBE Paint Position": () => ".position", 164 | "ADBE Paint Scale": () => ".scale", 165 | "ADBE Paint Rotation": () => ".rotation", 166 | //"ADBE Paint Nibbler Group": () => "", 167 | 168 | "ADBE MTrackers": () => "motionTracker", 169 | "ADBE MTracker Pt Feature Center": () => ".featureCenter", 170 | "ADBE MTracker Pt Feature Size": () => ".featureSize", 171 | "ADBE MTracker Pt Search Ofst": () => ".searchOffset", 172 | "ADBE MTracker Pt Search Size": () => ".searchSize", 173 | "ADBE MTracker Pt Confidence": () => ".confidence", 174 | "ADBE MTracker Pt Attach Pt": () => ".attachPoint", 175 | "ADBE MTracker Pt Attach Pt Ofst": () => ".attachPointOffset", 176 | 177 | "ADBE Audio Group": () => "audio", 178 | "ADBE Audio Levels": () => ".audioLevels", 179 | 180 | "ADBE Time Remapping": () => "timeRemap", 181 | 182 | "ADBE Layer Styles": () => "layerStyle", 183 | "ADBE Blend Options Group": () => ".blendingOption", 184 | "ADBE Global Angle2": () => ".globalLightAngle", 185 | "ADBE Global Altitude2": () => ".globalLightAltitude", 186 | "ADBE Adv Blend Group": () => ".advancedBlending", 187 | "ADBE Layer Fill Opacity2": () => ".fillOpacity", 188 | "ADBE R Channel Blend": () => ".red", 189 | "ADBE G Channel Blend": () => ".green", 190 | "ADBE B Channel Blend": () => ".blue", 191 | "ADBE Blend Interior": () => ".blendInteriorStylesAsGroup", 192 | "ADBE Blend Ranges": () => ".useBlendRangesFromSource", 193 | 194 | "ADBE Vector Trim Offset": () => ".offset", 195 | "ADBE Vector Filter - Trim": (prop: PropertyGroup) => 196 | `content("${prop.name}")`, 197 | "ADBE Vectors Group": (prop: PropertyGroup) => `content("${prop.name}")`, 198 | "ADBE Vector Group": (prop: PropertyGroup) => `content("${prop.name}")`, 199 | 200 | "dropShadow/enabled": () => ".dropShadow", 201 | "dropShadow/mode2": () => ".blendMode", 202 | "dropShadow/color": () => ".color", 203 | "dropShadow/opacity": () => ".opacity", 204 | "dropShadow/useGlobalAngle": () => ".useGlobalLight", 205 | "dropShadow/localLightingAngle": () => ".angle", 206 | "dropShadow/distance": () => ".distance", 207 | "dropShadow/chokeMatte": () => ".spread", 208 | "dropShadow/blur": () => ".size", 209 | "dropShadow/noise": () => ".noise", 210 | "dropShadow/layerConceals": () => ".layerKnocksOutDropShadow", 211 | "innerShadow/enabled": () => ".innerShadow", 212 | "innerShadow/mode2": () => ".blendMode", 213 | "innerShadow/color": () => ".color", 214 | "innerShadow/opacity": () => ".opacity", 215 | "innerShadow/useGlobalAngle": () => ".useGlobalLight", 216 | "innerShadow/localLightingAngle": () => ".angle", 217 | "innerShadow/distance": () => ".distance", 218 | "innerShadow/chokeMatte": () => ".choke", 219 | "innerShadow/blur": () => ".size", 220 | "innerShadow/noise": () => ".noise", 221 | "outerGlow/enabled": () => ".outerGlow", 222 | "outerGlow/mode2": () => ".blendMode", 223 | "outerGlow/opacity": () => ".opacity", 224 | "outerGlow/noise": () => ".noise", 225 | "outerGlow/AEColorChoice": () => ".colorType", 226 | "outerGlow/color": () => ".color", 227 | //"outerGlow/gradient": () => ".", // No equivalent 228 | "outerGlow/gradientSmoothness": () => ".gradientSmoothness", 229 | "outerGlow/glowTechnique": () => ".technique", 230 | "outerGlow/chokeMatte": () => ".spread", 231 | "outerGlow/blur": () => ".size", 232 | "outerGlow/inputRange": () => ".range", 233 | "outerGlow/shadingNoise": () => ".jitter", 234 | "innerGlow/enabled": () => ".innerGlow", 235 | "innerGlow/mode2": () => ".blendMode", 236 | "innerGlow/opacity": () => ".opacity", 237 | "innerGlow/noise": () => ".noise", 238 | "innerGlow/AEColorChoice": () => ".colorType", 239 | "innerGlow/color": () => ".color", 240 | //"innerGlow/gradient": () => ".", // No equivalent 241 | "innerGlow/gradientSmoothness": () => ".gradientSmoothness", 242 | "innerGlow/glowTechnique": () => ".technique", 243 | "innerGlow/innerGlowSource": () => ".source", 244 | "innerGlow/chokeMatte": () => ".choke", 245 | "innerGlow/blur": () => ".size", 246 | "innerGlow/inputRange": () => ".range", 247 | "innerGlow/shadingNoise": () => ".jitter", 248 | "bevelEmboss/enabled": () => ".bevelAndEmboss", 249 | "bevelEmboss/bevelStyle": () => ".style", 250 | "bevelEmboss/bevelTechnique": () => ".technique", 251 | "bevelEmboss/strengthRatio": () => ".depth", 252 | "bevelEmboss/bevelDirection": () => ".direction", 253 | "bevelEmboss/blur": () => ".size", 254 | "bevelEmboss/softness": () => ".soften", 255 | "bevelEmboss/useGlobalAngle": () => ".useGlobalLight", 256 | "bevelEmboss/localLightingAngle": () => ".angle", 257 | "bevelEmboss/localLightingAltitude": () => ".altitude", 258 | "bevelEmboss/highlightMode": () => ".highlightMode", 259 | "bevelEmboss/highlightColor": () => ".highlightColor", 260 | "bevelEmboss/highlightOpacity": () => ".highlightOpacity", 261 | "bevelEmboss/shadowMode": () => ".shadowMode", 262 | "bevelEmboss/shadowColor": () => ".shadowColor", 263 | "bevelEmboss/shadowOpacity": () => ".shadowOpacity", 264 | "chromeFX/enabled": () => ".satin", 265 | "chromeFX/mode2": () => ".blendMode", 266 | "chromeFX/color": () => ".color", 267 | "chromeFX/opacity": () => ".opacity", 268 | "chromeFX/localLightingAngle": () => ".angle", 269 | "chromeFX/distance": () => ".distance", 270 | "chromeFX/blur": () => ".size", 271 | "chromeFX/invert": () => ".invert", 272 | "solidFill/enabled": () => ".colorOverlay", 273 | "solidFill/mode2": () => ".blendMode", 274 | "solidFill/color": () => ".color", 275 | "solidFill/opacity": () => ".opacity", 276 | "gradientFill/enabled": () => ".gradientOverlay", 277 | "gradientFill/mode2": () => ".blendMode", 278 | "gradientFill/opacity": () => ".opacity", 279 | //"gradientFill/gradient": () => ".", // No equivalent 280 | "gradientFill/gradientSmoothness": () => ".gradientSmoothness", 281 | "gradientFill/angle": () => ".angle", 282 | "gradientFill/type": () => ".style", 283 | "gradientFill/reverse": () => ".reverse", 284 | "gradientFill/align": () => ".alignWithLayer", 285 | "gradientFill/scale": () => ".scale", 286 | "gradientFill/offset": () => ".offset", 287 | "patternFill/enabled": () => ".patternOverlay", 288 | "patternFill/mode2": () => ".blendMode", 289 | "patternFill/opacity": () => ".opacity", 290 | "patternFill/align": () => ".linkWithLayer", 291 | "patternFill/scale": () => ".scale", 292 | "patternFill/phase": () => ".offset", 293 | "frameFX/enabled": () => ".stroke", 294 | "frameFX/mode2": () => ".blendMode", 295 | "frameFX/color": () => ".color", 296 | "frameFX/size": () => ".size", 297 | "frameFX/opacity": () => ".opacity", 298 | "frameFX/style": () => ".position", 299 | } as const; 300 | 301 | const hasProp = ( 302 | obj: O, 303 | propKey: K 304 | ): obj is O & { [key in K]: unknown } => propKey in obj; 305 | 306 | function getCompactEnglishExpression( 307 | prop: Property | PropertyGroup, 308 | matchName: string 309 | ) { 310 | if (!hasProp(propCompactEnglishExpressions, matchName)) { 311 | throw Error( 312 | `Couldn't get compact expression for property ${prop.name}\nMatch name: ${matchName}` 313 | ); 314 | } 315 | 316 | const getTranslatedName = propCompactEnglishExpressions[matchName]; 317 | 318 | return getTranslatedName(prop); 319 | } 320 | 321 | function getDeepestSelectedProp() { 322 | const comp = getActiveComp(); 323 | let deepestProp, 324 | numDeepestProps = 0, 325 | deepestPropDepth = 0; 326 | let prop; 327 | 328 | for (var i = 0; i < comp.selectedProperties.length; i++) { 329 | prop = comp.selectedProperties[i]; 330 | 331 | if (prop.propertyDepth >= deepestPropDepth) { 332 | if (prop.propertyDepth > deepestPropDepth) numDeepestProps = 0; 333 | deepestProp = prop; 334 | numDeepestProps++; 335 | deepestPropDepth = prop.propertyDepth; 336 | } else continue; 337 | } 338 | 339 | return numDeepestProps > 1 ? undefined : deepestProp; 340 | } 341 | 342 | function getLayerForProperty(property: Property | PropertyGroup) { 343 | return property.propertyGroup(property.propertyDepth); 344 | } 345 | 346 | export function getPropertyPath() { 347 | let currProp: Property | PropertyGroup | undefined = getDeepestSelectedProp(); 348 | if (!currProp) return; 349 | 350 | const layer = getLayerForProperty(currProp); 351 | 352 | let exprCode = ""; 353 | let compactName = ""; 354 | 355 | while (currProp.parentProperty !== null) { 356 | compactName = getCompactEnglishExpression(currProp, currProp.matchName); 357 | exprCode = compactName + exprCode; 358 | 359 | // Traverse up the property tree 360 | currProp = currProp.parentProperty; 361 | } 362 | 363 | exprCode = `thisComp.layer("${layer.name}").${exprCode}`; 364 | return exprCode; 365 | } 366 | -------------------------------------------------------------------------------- /ae/src/script/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es3", 4 | "noLib": true, 5 | "strict": true, 6 | "types": [ 7 | "./global", 8 | "../../node_modules/types-for-adobe/shared/global", 9 | "../../node_modules/types-for-adobe/shared/PlugPlugExternalObject", 10 | "../../node_modules/types-for-adobe/AfterEffects/18.0" 11 | ] 12 | }, 13 | "include": ["./**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /ae/src/script/utils/aeft-utils.ts: -------------------------------------------------------------------------------- 1 | export const forEachLayer = ( 2 | comp: CompItem, 3 | callback: (item: Layer, index: number) => void 4 | ) => { 5 | const len = comp.numLayers; 6 | for (let i = 1; i < len + 1; i++) { 7 | callback(comp.layers[i], i); 8 | } 9 | }; 10 | 11 | export const compFromFootage = (item: FootageItem): CompItem => { 12 | return app.project.items.addComp( 13 | item.name, 14 | item.width, 15 | item.height, 16 | item.pixelAspect, 17 | item.duration, 18 | item.frameRate 19 | ); 20 | }; 21 | 22 | export const getProjectDir = () => { 23 | app.project.file; 24 | if (app.project.file !== null) { 25 | //@ts-ignore 26 | return app.project.file.parent; 27 | } else { 28 | return ""; 29 | } 30 | }; 31 | 32 | export const getActiveComp = () => { 33 | if (app.project.activeItem instanceof CompItem === false) { 34 | app.activeViewer?.setActive(); 35 | } 36 | return app.project.activeItem as CompItem; 37 | }; 38 | -------------------------------------------------------------------------------- /ae/src/script/utils/utils.ts: -------------------------------------------------------------------------------- 1 | export const forEach = ( 2 | arr: any[], 3 | callback: (item: any, i: number) => void 4 | ): void => { 5 | for (let i = 0; i < arr.length; i++) { 6 | callback(arr[i], i); 7 | } 8 | }; 9 | 10 | export const map = ( 11 | arr: any[], 12 | callback: (item: any, i: number) => any 13 | ): any[] => { 14 | let res = []; 15 | for (let i = 0; i < arr.length; i++) { 16 | res.push(callback(arr[i], i)); 17 | } 18 | return res; 19 | }; 20 | 21 | export const filter = ( 22 | arr: any[], 23 | func: (item: any, i: number) => boolean 24 | ): any[] => { 25 | let res = []; 26 | for (let i = 0; i < arr.length; i++) { 27 | if (func(arr[i], i)) { 28 | res.push(arr[i]); 29 | } 30 | } 31 | return res; 32 | }; 33 | 34 | export const includes = ( 35 | arr: Array, 36 | value: string | number 37 | ) => { 38 | for (let i = 0; i < arr.length; i++) { 39 | const element = arr[i]; 40 | if (element === value) { 41 | return true; 42 | } 43 | } 44 | return false; 45 | }; 46 | 47 | export const indexOf = ( 48 | arr: Array, 49 | value: string | number 50 | ) => { 51 | for (let i = 0; i < arr.length; i++) { 52 | const element = arr[i]; 53 | if (element === value) { 54 | return i; 55 | } 56 | } 57 | return -1; 58 | }; 59 | 60 | // Joins paths 61 | export const join = (...args: string[]) => { 62 | const sep = $.os === "Windows" ? "\\" : "/"; 63 | const len = args.length; 64 | let res = args[0]; 65 | for (let i = 1; i < len; i++) { 66 | res = res + sep + args[i]; 67 | } 68 | return res; 69 | }; 70 | -------------------------------------------------------------------------------- /ae/src/shared/shared.ts: -------------------------------------------------------------------------------- 1 | import config from "../../cep.config"; 2 | export const ns = config.id; 3 | -------------------------------------------------------------------------------- /ae/src/shared/universals.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description Declare event types for listening with listenTS() and dispatching with dispatchTS() 3 | */ 4 | export type EventTS = { 5 | myCustomEvent: { 6 | oneValue: string; 7 | anotherValue: number; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /ae/src/ui/assets/adobe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ae/src/ui/assets/bolt-cep-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondeveloper/editor/b49ea6e1afbc18c5face59ab97629a5228197333/ae/src/ui/assets/bolt-cep-react.png -------------------------------------------------------------------------------- /ae/src/ui/assets/bolt-cep-vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motiondeveloper/editor/b49ea6e1afbc18c5face59ab97629a5228197333/ae/src/ui/assets/bolt-cep-vue.png -------------------------------------------------------------------------------- /ae/src/ui/assets/bolt-cep.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 11 | 12 | 13 | 14 | 19 | 27 | 28 | 29 | 36 | 37 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /ae/src/ui/assets/node-js.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /ae/src/ui/assets/react.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ae/src/ui/assets/sass.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ae/src/ui/assets/typescript.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | TypeScript logo 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ae/src/ui/assets/vite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ae/src/ui/assets/vue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /ae/src/ui/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ae/src/ui/index.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-detectable=false -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/cep-types.d.ts: -------------------------------------------------------------------------------- 1 | export declare interface cep_node { 2 | global: any; 3 | process: any; 4 | buffer: any; 5 | require: any; 6 | } 7 | export declare interface cep { 8 | encoding: { 9 | Base64: "Base64" | string; 10 | UTF8: "UTF-8" | string; 11 | convertion: { 12 | utf8_to_b64: (...params: any) => {}; 13 | b64_to_utf8: (...params: any) => {}; 14 | binary_to_b64: (...params: any) => {}; 15 | b64_to_binary: (...params: any) => {}; 16 | ascii_to_b64: (...params: any) => {}; 17 | }; 18 | }; 19 | fs: { 20 | ERR_CANT_READ: number; 21 | ERR_CANT_WRITE: number; 22 | ERR_FILE_EXISTS: number; 23 | ERR_INVALID_PARAMS: number; 24 | ERR_NOT_DIRECTORY: number; 25 | ERR_NOT_FILE: number; 26 | ERR_NOT_FOUND: number; 27 | ERR_OUT_OF_SPACE: number; 28 | ERR_UNKNOWN: number; 29 | ERR_UNSUPPORTED_ENCODING: number; 30 | NO_ERROR: number; 31 | chmod: (...params: any) => {}; 32 | deleteFile: (...params: any) => {}; 33 | makedir: (...params: any) => {}; 34 | readFile: (...params: any) => {}; 35 | readdir: (...params: any) => {}; 36 | rename: (...params: any) => {}; 37 | showOpenDialog: (...params: any) => {}; 38 | showOpenDialogEx: (...params: any) => {}; 39 | showSaveDialogEx: (...params: any) => {}; 40 | stat: (...params: any) => {}; 41 | writeFile: (...params: any) => {}; 42 | }; 43 | process: { 44 | ERR_EXCEED_MAX_NUM_PROCESS: number; 45 | createProcess: (...params: any) => {}; 46 | getWorkingDirectory: (...params: any) => {}; 47 | isRunning: (...params: any) => {}; 48 | onquit: (...params: any) => {}; 49 | stderr: (...params: any) => {}; 50 | stdin: (...params: any) => {}; 51 | stdout: (...params: any) => {}; 52 | terminate: (...params: any) => {}; 53 | waitfor: (...params: any) => {}; 54 | }; 55 | util: { 56 | DEPRECATED_API: number; 57 | ERR_INVALID_URL: number; 58 | openURLInDefaultBrowser: (...params: any) => {}; 59 | registerExtensionUnloadCallback: (...params: any) => {}; 60 | storeProxyCredentials: (...params: any) => {}; 61 | }; 62 | } 63 | 64 | export interface __adobe_cep__ { 65 | addEventListener: (...params: any) => {}; 66 | analyticsLogging: (...params: any) => {}; 67 | autoThemeColorChange: (...params: any) => {}; 68 | closeExtension: (...params: any) => {}; 69 | dispatchEvent: (...params: any) => {}; 70 | dumpInstallationInfo: (...params: any) => {}; 71 | evalScript: (...params: any) => {}; 72 | getCurrentApiVersion: (...params: any) => {}; 73 | getCurrentImsUserId: (...params: any) => {}; 74 | getExtensionId: (...params: any) => {}; 75 | getExtensions: (...params: any) => {}; 76 | getHostCapabilities: (...params: any) => {}; 77 | getHostEnvironment: (...params: any) => {}; 78 | getMonitorScaleFactor: (...params: any) => {}; 79 | getNetworkPreferences: (...params: any) => {}; 80 | getScaleFactor: (...params: any) => {}; 81 | getSystemPath: (...params: any) => {}; 82 | imsConnect: (...params: any) => {}; 83 | imsDisconnect: (...params: any) => {}; 84 | imsFetchAccessToken: (...params: any) => {}; 85 | imsFetchAccounts: (...params: any) => {}; 86 | imsSetProxyCredentials: (...params: any) => {}; 87 | initResourceBundle: (...params: any) => {}; 88 | invokeAsync: (...params: any) => {}; 89 | invokeSync: (...params: any) => {}; 90 | nglImsFetchAccessToken: (...params: any) => {}; 91 | nglImsFetchProfile: (...params: any) => {}; 92 | registerInvalidCertificateCallback: (...params: any) => {}; 93 | registerKeyEventsInterest: (...params: any) => {}; 94 | removeEventListener: (...params: any) => {}; 95 | requestOpenExtension: (...params: any) => {}; 96 | resizeContent: (...params: any) => {}; 97 | setScaleFactorChangedHandler: (...params: any) => {}; 98 | showAAM: (...params: any) => {}; 99 | } 100 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/cep_engine_extensions.js: -------------------------------------------------------------------------------- 1 | // FOR REFERENCE ONLY -- THIS FILE IS NOT BUNDLED 2 | 3 | /************************************************************************************************** 4 | * 5 | * ADOBE SYSTEMS INCORPORATED 6 | * Copyright 2020 Adobe Systems Incorporated 7 | * All Rights Reserved. 8 | * 9 | * NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the 10 | * terms of the Adobe license agreement accompanying it. If you have received this file from a 11 | * source other than Adobe, then your use, modification, or distribution of it requires the prior 12 | * written permission of Adobe. 13 | * 14 | **************************************************************************************************/ 15 | 16 | // This is the JavaScript code for bridging to native functionality 17 | // See CEPEngine_extensions.cpp for implementation of native methods. 18 | // 19 | // Note: So far all native file i/o functions are synchronous, and aynchronous file i/o is TBD. 20 | 21 | /** Version v11.0.0 */ 22 | 23 | /*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */ 24 | /*global define, native */ 25 | 26 | var cep; 27 | if (!cep) { 28 | cep = {}; 29 | } 30 | if (!cep.fs) { 31 | cep.fs = {}; 32 | } 33 | if (!cep.process) { 34 | cep.process = {}; 35 | } 36 | if (!cep.encoding) { 37 | cep.encoding = {}; 38 | } 39 | if (!cep.util) { 40 | cep.util = {}; 41 | } 42 | (function () { 43 | // Internal function to get the last error code. 44 | native function GetLastError(); 45 | function getLastError() { 46 | return GetLastError(); 47 | } 48 | 49 | function getErrorResult(){ 50 | var result = {err: getLastError()}; 51 | return result; 52 | } 53 | 54 | // Error values. These MUST be in sync with the error values 55 | // at the top of CEPEngine_extensions.cpp 56 | 57 | /** 58 | * @constant No error. 59 | */ 60 | cep.fs.NO_ERROR = 0; 61 | 62 | /** 63 | * @constant Unknown error occurred. 64 | */ 65 | cep.fs.ERR_UNKNOWN = 1; 66 | 67 | /** 68 | * @constant Invalid parameters passed to function. 69 | */ 70 | cep.fs.ERR_INVALID_PARAMS = 2; 71 | 72 | /** 73 | * @constant File or directory was not found. 74 | */ 75 | cep.fs.ERR_NOT_FOUND = 3; 76 | 77 | /** 78 | * @constant File or directory could not be read. 79 | */ 80 | cep.fs.ERR_CANT_READ = 4; 81 | 82 | /** 83 | * @constant An unsupported encoding value was specified. 84 | */ 85 | cep.fs.ERR_UNSUPPORTED_ENCODING = 5; 86 | 87 | /** 88 | * @constant File could not be written. 89 | */ 90 | cep.fs.ERR_CANT_WRITE = 6; 91 | 92 | /** 93 | * @constant Target directory is out of space. File could not be written. 94 | */ 95 | cep.fs.ERR_OUT_OF_SPACE = 7; 96 | 97 | /** 98 | * @constant Specified path does not point to a file. 99 | */ 100 | cep.fs.ERR_NOT_FILE = 8; 101 | 102 | /** 103 | * @constant Specified path does not point to a directory. 104 | */ 105 | cep.fs.ERR_NOT_DIRECTORY = 9; 106 | 107 | /** 108 | * @constant Specified file already exists. 109 | */ 110 | cep.fs.ERR_FILE_EXISTS = 10; 111 | 112 | /** 113 | * @constant The maximum number of processes has been exceeded. 114 | */ 115 | cep.process.ERR_EXCEED_MAX_NUM_PROCESS = 101; 116 | 117 | /** 118 | * @constant Invalid URL. 119 | */ 120 | cep.util.ERR_INVALID_URL = 201; 121 | 122 | /** 123 | * @constant deprecated API. 124 | */ 125 | cep.util.DEPRECATED_API = 202; 126 | 127 | /** 128 | * @constant UTF8 encoding type. 129 | */ 130 | cep.encoding.UTF8 = "UTF-8"; 131 | 132 | /** 133 | * @constant Base64 encoding type. 134 | */ 135 | cep.encoding.Base64 = "Base64"; 136 | 137 | /** 138 | * Displays the OS File Open dialog, allowing the user to select files or directories. 139 | * 140 | * @param allowMultipleSelection {boolean} When true, multiple files/folders can be selected. 141 | * @param chooseDirectory {boolean} When true, only folders can be selected. When false, only 142 | * files can be selected. 143 | * @param title {string} Title of the open dialog. 144 | * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to 145 | * display the last path chosen. 146 | * @param fileTypes {Array.} The file extensions (without the dot) for the types 147 | * of files that can be selected. Ignored when chooseDirectory=true. 148 | * 149 | * @return An object with these properties: 150 | *
  • "data": An array of the full names of the selected files.
  • 151 | *
  • "err": The status of the operation, one of 152 | *
    NO_ERROR 153 | *
    ERR_INVALID_PARAMS
  • 154 | *
155 | **/ 156 | native function ShowOpenDialog(); 157 | cep.fs.showOpenDialog = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes) { 158 | var resultString = ShowOpenDialog(allowMultipleSelection, chooseDirectory, 159 | title || 'Open', initialPath || '', 160 | fileTypes ? fileTypes.join(' ') : ''); 161 | 162 | var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; 163 | return result; 164 | }; 165 | 166 | /** 167 | * Displays the OS File Open dialog, allowing the user to select files or directories. 168 | * 169 | * @param allowMultipleSelection {boolean} When true, multiple files/folders can be selected. 170 | * @param chooseDirectory {boolean} When true, only folders can be selected. When false, only 171 | * files can be selected. 172 | * @param title {string} Title of the open dialog. 173 | * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to 174 | * display the last path chosen. 175 | * @param fileTypes {Array.} The file extensions (without the dot) for the types 176 | * of files that can be selected. Ignored when chooseDirectory=true. 177 | * @param friendlyFilePrefix {string} String to put in front of the extensions 178 | * of files that can be selected. Ignored when chooseDirectory=true. (win only) 179 | * For example: 180 | * fileTypes = ["gif", "jpg", "jpeg", "png", "bmp", "webp", "svg"]; 181 | * friendlyFilePrefix = "Images (*.gif;*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.svg)"; 182 | * @param prompt {string} String for OK button (mac only, default is "Open" on mac, "Open" or "Select Folder" on win). 183 | * 184 | * @return An object with these properties: 185 | *
  • "data": An array of the full names of the selected files.
  • 186 | *
  • "err": The status of the operation, one of 187 | *
    NO_ERROR 188 | *
    ERR_INVALID_PARAMS
  • 189 | *
190 | **/ 191 | native function ShowOpenDialogEx(); 192 | cep.fs.showOpenDialogEx = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes, 193 | friendlyFilePrefix, prompt) { 194 | var resultString = ShowOpenDialogEx(allowMultipleSelection, chooseDirectory, 195 | title || 'Open', initialPath || '', 196 | fileTypes ? fileTypes.join(' ') : '', friendlyFilePrefix || '', 197 | prompt || ''); 198 | 199 | var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; 200 | return result; 201 | }; 202 | 203 | /** 204 | * Displays the OS File Save dialog, allowing the user to type in a file name. 205 | * 206 | * @param title {string} Title of the save dialog. 207 | * @param initialPath {string} Initial path to display in the dialog. Pass NULL or "" to 208 | * display the last path chosen. 209 | * @param fileTypes {Array.} The file extensions (without the dot) for the types 210 | * of files that can be selected. 211 | * @param defaultName {string} String to start with for the file name. 212 | * @param friendlyFilePrefix {string} String to put in front of the extensions of files that can be selected. (win only) 213 | * For example: 214 | * fileTypes = ["gif", "jpg", "jpeg", "png", "bmp", "webp", "svg"]; 215 | * friendlyFilePrefix = "Images (*.gif;*.jpg;*.jpeg;*.png;*.bmp;*.webp;*.svg)"; 216 | * @param prompt {string} String for Save button (mac only, default is "Save" on mac and win). 217 | * @param nameFieldLabel {string} String displayed in front of the file name text field (mac only, "File name:" on win). 218 | * 219 | * @return An object with these properties: 220 | *
  • "data": The file path selected to save at or "" if canceled
  • 221 | *
  • "err": The status of the operation, one of 222 | *
    NO_ERROR 223 | *
    ERR_INVALID_PARAMS
  • 224 | *
225 | **/ 226 | native function ShowSaveDialogEx(); 227 | cep.fs.showSaveDialogEx = function (title, initialPath, fileTypes, defaultName, friendlyFilePrefix, prompt, nameFieldLabel) { 228 | var resultString = ShowSaveDialogEx(title || '', initialPath || '', 229 | fileTypes ? fileTypes.join(' ') : '', defaultName || '', 230 | friendlyFilePrefix || '', prompt || '', nameFieldLabel || ''); 231 | 232 | var result = {data: resultString || '', err: getLastError() }; 233 | return result; 234 | }; 235 | 236 | /** 237 | * Reads the contents of a folder. 238 | * 239 | * @param path {string} The path of the folder to read. 240 | * 241 | * @return An object with these properties: 242 | *
  • "data": An array of the names of the contained files (excluding '.' and '..'.
  • 243 | *
  • "err": The status of the operation, one of: 244 | *
    NO_ERROR 245 | *
    ERR_UNKNOWN 246 | *
    ERR_INVALID_PARAMS 247 | *
    ERR_NOT_FOUND 248 | *
    ERR_CANT_READ
249 | **/ 250 | native function ReadDir(); 251 | cep.fs.readdir = function (path) { 252 | var resultString = ReadDir(path); 253 | var result = {data: JSON.parse(resultString || '[]'), err: getLastError() }; 254 | return result; 255 | }; 256 | 257 | /** 258 | * Creates a new folder. 259 | * 260 | * @param path {string} The path of the folder to create. 261 | * 262 | * @return An object with this property: 263 | *
  • "err": The status of the operation, one of: 264 | *
    NO_ERROR 265 | *
    ERR_UNKNOWN 266 | *
    ERR_INVALID_PARAMS
267 | **/ 268 | native function MakeDir(); 269 | cep.fs.makedir = function (path) { 270 | MakeDir(path); 271 | return getErrorResult(); 272 | }; 273 | 274 | /** 275 | * Renames a file or folder. 276 | * 277 | * @param oldPath {string} The old name of the file or folder. 278 | * @param newPath {string} The new name of the file or folder. 279 | * 280 | * @return An object with this property: 281 | *
  • "err": The status of the operation, one of: 282 | *
    NO_ERROR 283 | *
    ERR_UNKNOWN 284 | *
    ERR_INVALID_PARAMS 285 | *
    ERR_NOT_FOUND 286 | *
    ERR_FILE_EXISTS
287 | **/ 288 | native function Rename(); 289 | cep.fs.rename = function(oldPath, newPath) { 290 | Rename(oldPath, newPath); 291 | return getErrorResult(); 292 | }; 293 | 294 | /** 295 | * Reports whether an item is a file or folder. 296 | * 297 | * @param path {string} The path of the file or folder. 298 | * 299 | * @return An object with these properties: 300 | *
  • "data": An object with properties 301 | *
    isFile (boolean) 302 | *
    isDirectory (boolean) 303 | *
    mtime (modification DateTime)
  • 304 | *
  • "err": The status of the operation, one of 305 | *
    NO_ERROR 306 | *
    ERR_UNKNOWN 307 | *
    ERR_INVALID_PARAMS 308 | *
    ERR_NOT_FOUND
  • 309 | *
310 | **/ 311 | native function IsDirectory(); 312 | native function GetFileModificationTime(); 313 | cep.fs.stat = function (path) { 314 | var isDir = IsDirectory(path); 315 | var modtime = GetFileModificationTime(path); 316 | var result = { 317 | data: { 318 | isFile: function () { 319 | return !isDir; 320 | }, 321 | isDirectory: function () { 322 | return isDir; 323 | }, 324 | mtime: modtime 325 | }, 326 | err: getLastError() 327 | }; 328 | 329 | return result; 330 | }; 331 | 332 | /** 333 | * Reads the entire contents of a file. 334 | * 335 | * @param path {string} The path of the file to read. 336 | * @param encoding {string} The encoding of the contents of file, one of 337 | * UTF8 (the default) or Base64. 338 | * 339 | * @return An object with these properties: 340 | *
  • "data": The file contents.
  • 341 | *
  • "err": The status of the operation, one of 342 | *
    NO_ERROR 343 | *
    ERR_UNKNOWN 344 | *
    ERR_INVALID_PARAMS 345 | *
    ERR_NOT_FOUND 346 | *
    ERR_CANT_READ 347 | *
    ERR_UNSUPPORTED_ENCODING
  • 348 | *
349 | **/ 350 | native function ReadFile(); 351 | cep.fs.readFile = function (path, encoding) { 352 | encoding = encoding ? encoding : cep.encoding.UTF8; 353 | var contents = ReadFile(path, encoding); 354 | var result = {data: contents, err: getLastError() }; 355 | return result; 356 | }; 357 | 358 | /** 359 | * Writes data to a file, replacing the file if it already exists. 360 | * 361 | * @param path {string} The path of the file to write. 362 | * @param data {string} The data to write to the file. 363 | * @param encoding {string} The encoding of the contents of file, one of 364 | * UTF8 (the default) or Base64. 365 | * 366 | * @return An object with this property: 367 | *
  • "err": The status of the operation, one of: 368 | *
    NO_ERROR 369 | *
    ERR_UNKNOWN 370 | *
    ERR_INVALID_PARAMS 371 | *
    ERR_UNSUPPORTED_ENCODING 372 | *
    ERR_CANT_WRITE 373 | *
    ERR_OUT_OF_SPACE
374 | **/ 375 | native function WriteFile(); 376 | cep.fs.writeFile = function (path, data, encoding) { 377 | encoding = encoding ? encoding : cep.encoding.UTF8; 378 | WriteFile(path, data, encoding); 379 | return getErrorResult(); 380 | }; 381 | 382 | /** 383 | * Sets permissions for a file or folder. 384 | * 385 | * @param path {string} The path of the file or folder. 386 | * @param mode {number} The permissions in numeric format (for example, 0777). 387 | * 388 | * @return An object with this property: 389 | *
  • "err": The status of the operation, one of: 390 | *
    NO_ERROR 391 | *
    ERR_UNKNOWN 392 | *
    ERR_INVALID_PARAMS 393 | *
    ERR_CANT_WRITE
394 | **/ 395 | native function SetPosixPermissions(); 396 | cep.fs.chmod = function (path, mode) { 397 | SetPosixPermissions(path, mode); 398 | return getErrorResult(); 399 | }; 400 | 401 | /** 402 | * Deletes a file. 403 | * 404 | * @param path {string} The path of the file to delete. 405 | * 406 | * @return An object with this property: 407 | *
  • "err": The status of the operation, one of: 408 | *
    NO_ERROR 409 | *
    ERR_UNKNOWN 410 | *
    ERR_INVALID_PARAMS 411 | *
    ERR_NOT_FOUND 412 | *
    ERR_NOT_FILE
413 | **/ 414 | native function DeleteFileOrDirectory(); 415 | native function IsDirectory(); 416 | cep.fs.deleteFile = function (path) { 417 | if (IsDirectory(path)) { 418 | var result = {err: cep.fs.ERR_NOT_FILE}; 419 | return result; 420 | } 421 | DeleteFileOrDirectory(path); 422 | return getErrorResult(); 423 | }; 424 | 425 | /** 426 | * Creates a process. 427 | * 428 | * @param arguments {list} The arguments to create process. The first one is the full path of the executable, 429 | * followed by the arguments of the executable. 430 | * 431 | * @return An object with these properties: 432 | *
  • "data": The pid of the process, or -1 on error.
  • 433 | *
  • "err": The status of the operation, one of 434 | *
    NO_ERROR 435 | *
    ERR_UNKNOWN 436 | *
    ERR_INVALID_PARAMS 437 | *
    ERR_EXCEED_MAX_NUM_PROCESS 438 | *
    ERR_NOT_FOUND 439 | *
    ERR_NOT_FILE
  • 440 | *
441 | **/ 442 | native function CreateProcess(); 443 | cep.process.createProcess = function () { 444 | var args = Array.prototype.slice.call(arguments); 445 | var pid = CreateProcess(args); 446 | var result = {data: pid, err: getLastError()}; 447 | return result; 448 | }; 449 | 450 | /** 451 | * Registers a standard-output handler for a process. 452 | * 453 | * @param pid {int} The pid of the process. 454 | * @param callback {function} The handler function for the standard output callback. 455 | * 456 | * @return An object with this property: 457 | *
  • "err": The status of the operation, one of: 458 | *
    NO_ERROR 459 | *
    ERR_UNKNOWN 460 | *
    ERR_INVALID_PARAMS 461 | *
    ERR_INVALID_PROCESS_ID
462 | **/ 463 | native function SetupStdOutHandler(); 464 | cep.process.stdout = function (pid, callback) { 465 | SetupStdOutHandler(pid, callback); 466 | return getErrorResult(); 467 | }; 468 | 469 | /** 470 | * Registers up a standard-error handler for a process. 471 | * 472 | * @param pid {int} The pid of the process. 473 | * @param callback {function} The handler function for the standard error callback. 474 | * 475 | * @return An object with this property: 476 | *
  • "err": The status of the operation, one of: 477 | *
    NO_ERROR 478 | *
    ERR_UNKNOWN 479 | *
    ERR_INVALID_PARAMS 480 | *
    ERR_INVALID_PROCESS_ID
481 | **/ 482 | native function SetupStdErrHandler(); 483 | cep.process.stderr = function (pid, callback) { 484 | SetupStdErrHandler(pid, callback); 485 | return getErrorResult(); 486 | }; 487 | 488 | /** 489 | * Writes data to the standard input of a process. 490 | * 491 | * @param pid {int} The pid of the process 492 | * @param data {string} The data to write. 493 | * 494 | * @return An object with this property: 495 | *
  • "err": The status of the operation, one of: 496 | *
    NO_ERROR 497 | *
    ERR_UNKNOWN 498 | *
    ERR_INVALID_PARAMS 499 | *
    ERR_INVALID_PROCESS_ID
500 | **/ 501 | native function WriteStdIn(); 502 | cep.process.stdin = function (pid, data) { 503 | WriteStdIn(pid, data); 504 | return getErrorResult(); 505 | }; 506 | 507 | /** 508 | * Retrieves the working directory of a process. 509 | * 510 | * @param pid {int} The pid of the process. 511 | * 512 | * @return An object with these properties: 513 | *
  • "data": The path of the working directory.
  • 514 | *
  • "err": The status of the operation, one of 515 | *
    NO_ERROR 516 | *
    ERR_UNKNOWN 517 | *
    ERR_INVALID_PARAMS 518 | *
    ERR_INVALID_PROCESS_ID
519 | **/ 520 | native function GetWorkingDirectory(); 521 | cep.process.getWorkingDirectory = function (pid) { 522 | var wd = GetWorkingDirectory(pid); 523 | var result = {data: wd, err: getLastError()}; 524 | return result; 525 | }; 526 | 527 | /** 528 | * Waits for a process to quit. 529 | * 530 | * @param pid {int} The pid of the process. 531 | * 532 | * @return An object with this property: 533 | *
  • "err": The status of the operation, one of: 534 | *
    NO_ERROR 535 | *
    ERR_UNKNOWN 536 | *
    ERR_INVALID_PARAMS 537 | *
    ERR_INVALID_PROCESS_ID
538 | **/ 539 | native function WaitFor(); 540 | cep.process.waitfor = function (pid) { 541 | WaitFor(pid); 542 | return getErrorResult(); 543 | }; 544 | 545 | /** 546 | * Registers a handler for the onquit callback of a process. 547 | * 548 | * @param pid {int} The pid of the process. 549 | * @param callback {function} The handler function. 550 | * 551 | * @return An object with this property: 552 | *
  • "err": The status of the operation, one of: 553 | *
    NO_ERROR 554 | *
    ERR_UNKNOWN 555 | *
    ERR_INVALID_PARAMS 556 | *
    ERR_INVALID_PROCESS_ID
557 | **/ 558 | native function OnQuit(); 559 | cep.process.onquit = function (pid, callback) { 560 | OnQuit(pid, callback); 561 | return getErrorResult(); 562 | }; 563 | 564 | /** 565 | * Reports whether a process is currently running. 566 | * 567 | * @param pid {int} The pid of the process. 568 | * 569 | * @return An object with these properties: 570 | *
  • "data": True if the process is running, false otherwise.
  • 571 | *
  • "err": The status of the operation, one of 572 | *
    NO_ERROR 573 | *
    ERR_UNKNOWN 574 | *
    ERR_INVALID_PARAMS 575 | *
    ERR_INVALID_PROCESS_ID
576 | **/ 577 | native function IsRunning(); 578 | cep.process.isRunning = function (pid) { 579 | var isRunning = IsRunning(pid); 580 | var result = {data: isRunning, err: getLastError()}; 581 | return result; 582 | }; 583 | 584 | /** 585 | * Terminates a process. 586 | * 587 | * @param pid {int} The pid of the process 588 | * 589 | * @return An object with this property: 590 | *
  • "err": The status of the operation, one of: 591 | *
    NO_ERROR 592 | *
    ERR_UNKNOWN 593 | *
    ERR_INVALID_PARAMS 594 | *
    ERR_INVALID_PROCESS_ID
595 | **/ 596 | native function Terminate(); 597 | cep.process.terminate = function (pid) { 598 | Terminate(pid); 599 | return getErrorResult(); 600 | }; 601 | 602 | /** 603 | * Encoding conversions. 604 | * 605 | */ 606 | cep.encoding.convertion = 607 | { 608 | utf8_to_b64: function(str) { 609 | return window.btoa(unescape(encodeURIComponent(str))); 610 | }, 611 | 612 | b64_to_utf8: function(base64str) { 613 | // If a base64 string contains any whitespace character, DOM Exception 5 occurs during window.atob, please see 614 | // http://stackoverflow.com/questions/14695988/dom-exception-5-invalid-character-error-on-valid-base64-image-string-in-javascri 615 | base64str = base64str.replace(/\s/g, ''); 616 | return decodeURIComponent(escape(window.atob(base64str))); 617 | }, 618 | 619 | binary_to_b64: function(binary) { 620 | return window.btoa(binary); 621 | }, 622 | 623 | b64_to_binary: function(base64str) { 624 | return window.atob(base64str); 625 | }, 626 | 627 | ascii_to_b64: function(ascii) { 628 | return window.btoa(binary); 629 | }, 630 | 631 | b64_to_ascii: function(base64str) { 632 | return window.atob(base64str); 633 | } 634 | }; 635 | 636 | /** 637 | * Opens a page in the default system browser. 638 | * 639 | * @param url {string} The URL of the page/file to open, or the email address. 640 | * Must use HTTP/HTTPS/file/mailto. For example: 641 | * "http://www.adobe.com" 642 | * "https://github.com" 643 | * "file:///C:/log.txt" 644 | * "mailto:test@adobe.com" 645 | * 646 | * @return An object with this property: 647 | *
  • "err": The status of the operation, one of: 648 | *
    NO_ERROR 649 | *
    ERR_UNKNOWN 650 | *
    ERR_INVALID_PARAMS
651 | **/ 652 | native function OpenURLInDefaultBrowser(); 653 | cep.util.openURLInDefaultBrowser = function (url) { 654 | if (url && (url.indexOf("http://") === 0 || 655 | url.indexOf("https://") === 0 || 656 | url.indexOf("file://") === 0 || 657 | url.indexOf("mailto:") === 0)) { 658 | OpenURLInDefaultBrowser(url); 659 | return getErrorResult(); 660 | } else { 661 | return { err : cep.util.ERR_INVALID_URL }; 662 | } 663 | }; 664 | 665 | /** 666 | * Registers a callback function for extension unload. If called more than once, 667 | * the last callback that is successfully registered is used. 668 | * 669 | * @deprecated since version 6.0.0 670 | * 671 | * @param callback {function} The handler function. 672 | * 673 | * @return An object with this property: 674 | *
  • "err": The status of the operation, one of: 675 | *
    NO_ERROR 676 | *
    ERR_INVALID_PARAMS
677 | **/ 678 | native function RegisterExtensionUnloadCallback(); 679 | cep.util.registerExtensionUnloadCallback = function (callback) { 680 | return { err : cep.util.DEPRECATED_API }; 681 | }; 682 | 683 | /** 684 | * Stores the user's proxy credentials 685 | * 686 | * @param username {string} proxy username 687 | * @param password {string} proxy password 688 | * 689 | * @return An object with this property: 690 | *
  • "err": The status of the operation, one of 691 | *
    NO_ERROR 692 | *
    ERR_INVALID_PARAMS
  • 693 | *
694 | **/ 695 | native function StoreProxyCredentials(); 696 | cep.util.storeProxyCredentials = function (username, password) { 697 | StoreProxyCredentials(username, password); 698 | return getErrorResult(); 699 | }; 700 | 701 | })(); 702 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/csinterface.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Stores constants for the window types supported by the CSXS infrastructure. 3 | */ 4 | declare function CSXSWindowType(): void; 5 | 6 | /** 7 | * EvalScript error message 8 | */ 9 | declare var EvalScript_ErrMessage: any; 10 | 11 | /** 12 | * Version 13 | Defines a version number with major, minor, micro, and special 14 | components. The major, minor and micro values are numeric; the special 15 | value can be any string. 16 | * @param major - The major version component, a positive integer up to nine digits long. 17 | * @param minor - The minor version component, a positive integer up to nine digits long. 18 | * @param micro - The micro version component, a positive integer up to nine digits long. 19 | * @param special - The special version component, an arbitrary string. 20 | */ 21 | declare class Version { 22 | constructor(major: any, minor: any, micro: any, special: any); 23 | /** 24 | * The maximum value allowed for a numeric version component. 25 | This reflects the maximum value allowed in PlugPlug and the manifest schema. 26 | */ 27 | static MAX_NUM: any; 28 | } 29 | 30 | /** 31 | * VersionBound 32 | Defines a boundary for a version range, which associates a \c Version object 33 | with a flag for whether it is an inclusive or exclusive boundary. 34 | * @param version - The \c #Version object. 35 | * @param inclusive - True if this boundary is inclusive, false if it is exclusive. 36 | */ 37 | declare class VersionBound { 38 | constructor(version: any, inclusive: any); 39 | } 40 | 41 | /** 42 | * VersionRange 43 | Defines a range of versions using a lower boundary and optional upper boundary. 44 | * @param lowerBound - The \c #VersionBound object. 45 | * @param upperBound - The \c #VersionBound object, or null for a range with no upper boundary. 46 | */ 47 | declare class VersionRange { 48 | constructor(lowerBound: any, upperBound: any); 49 | } 50 | 51 | /** 52 | * Runtime 53 | Represents a runtime related to the CEP infrastructure. 54 | Extensions can declare dependencies on particular 55 | CEP runtime versions in the extension manifest. 56 | * @param name - The runtime name. 57 | * @param version - A \c #VersionRange object that defines a range of valid versions. 58 | */ 59 | declare class Runtime { 60 | constructor(name: any, version: any); 61 | } 62 | 63 | /** 64 | * Extension 65 | Encapsulates a CEP-based extension to an Adobe application. 66 | * @param id - The unique identifier of this extension. 67 | * @param name - The localizable display name of this extension. 68 | * @param mainPath - The path of the "index.html" file. 69 | * @param basePath - The base path of this extension. 70 | * @param windowType - The window type of the main window of this extension. 71 | * Valid values are defined by \c #CSXSWindowType. 72 | * @param width - The default width in pixels of the main window of this extension. 73 | * @param height - The default height in pixels of the main window of this extension. 74 | * @param minWidth - The minimum width in pixels of the main window of this extension. 75 | * @param minHeight - The minimum height in pixels of the main window of this extension. 76 | * @param maxWidth - The maximum width in pixels of the main window of this extension. 77 | * @param maxHeight - The maximum height in pixels of the main window of this extension. 78 | * @param defaultExtensionDataXml - The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. 79 | * @param specialExtensionDataXml - The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. 80 | * @param requiredRuntimeList - An array of \c Runtime objects for runtimes required by this extension. 81 | * @param isAutoVisible - True if this extension is visible on loading. 82 | * @param isPluginExtension - True if this extension has been deployed in the Plugins folder of the host application. 83 | */ 84 | declare class Extension { 85 | constructor( 86 | id: any, 87 | name: any, 88 | mainPath: any, 89 | basePath: any, 90 | windowType: any, 91 | width: any, 92 | height: any, 93 | minWidth: any, 94 | minHeight: any, 95 | maxWidth: any, 96 | maxHeight: any, 97 | defaultExtensionDataXml: any, 98 | specialExtensionDataXml: any, 99 | requiredRuntimeList: any, 100 | isAutoVisible: any, 101 | isPluginExtension: any 102 | ); 103 | } 104 | 105 | /** 106 | * CSEvent 107 | A standard JavaScript event, the base class for CEP events. 108 | * @param type - The name of the event type. 109 | * @param scope - The scope of event, can be "GLOBAL" or "APPLICATION". 110 | * @param appId - The unique identifier of the application that generated the event. 111 | * @param extensionId - The unique identifier of the extension that generated the event. 112 | */ 113 | declare class CSEvent { 114 | constructor(type: any, scope: any, appId: any, extensionId: any); 115 | /** 116 | * Event-specific data. 117 | */ 118 | data: any; 119 | } 120 | 121 | /** 122 | * SystemPath 123 | Stores operating-system-specific location constants for use in the 124 | \c #CSInterface.getSystemPath() method. 125 | */ 126 | declare class SystemPath { 127 | constructor(); 128 | /** 129 | * The path to user data. 130 | */ 131 | static USER_DATA: any; 132 | /** 133 | * The path to common files for Adobe applications. 134 | */ 135 | static COMMON_FILES: any; 136 | /** 137 | * The path to the user's default document folder. 138 | */ 139 | static MY_DOCUMENTS: any; 140 | static APPLICATION: any; 141 | /** 142 | * The path to current extension. 143 | */ 144 | static EXTENSION: any; 145 | /** 146 | * The path to hosting application's executable. 147 | */ 148 | static HOST_APPLICATION: any; 149 | } 150 | 151 | /** 152 | * ColorType 153 | Stores color-type constants. 154 | */ 155 | declare class ColorType { 156 | constructor(); 157 | /** 158 | * RGB color type. 159 | */ 160 | static RGB: any; 161 | /** 162 | * Gradient color type. 163 | */ 164 | static GRADIENT: any; 165 | /** 166 | * Null color type. 167 | */ 168 | static NONE: any; 169 | } 170 | 171 | /** 172 | * RGBColor 173 | Stores an RGB color with red, green, blue, and alpha values. 174 | All values are in the range [0.0 to 255.0]. Invalid numeric values are 175 | converted to numbers within this range. 176 | * @param red - The red value, in the range [0.0 to 255.0]. 177 | * @param green - The green value, in the range [0.0 to 255.0]. 178 | * @param blue - The blue value, in the range [0.0 to 255.0]. 179 | * @param alpha - The alpha (transparency) value, in the range [0.0 to 255.0]. 180 | The default, 255.0, means that the color is fully opaque. 181 | */ 182 | declare class RGBColor { 183 | constructor(red: any, green: any, blue: any, alpha: any); 184 | } 185 | 186 | /** 187 | * Direction 188 | A point value in which the y component is 0 and the x component 189 | is positive or negative for a right or left direction, 190 | or the x component is 0 and the y component is positive or negative for 191 | an up or down direction. 192 | * @param x - The horizontal component of the point. 193 | * @param y - The vertical component of the point. 194 | */ 195 | declare class Direction { 196 | constructor(x: any, y: any); 197 | } 198 | 199 | /** 200 | * GradientStop 201 | Stores gradient stop information. 202 | * @param offset - The offset of the gradient stop, in the range [0.0 to 1.0]. 203 | * @param rgbColor - The color of the gradient at this point, an \c #RGBColor object. 204 | */ 205 | declare class GradientStop { 206 | constructor(offset: any, rgbColor: any); 207 | } 208 | 209 | /** 210 | * GradientColor 211 | Stores gradient color information. 212 | * @param type - The gradient type, must be "linear". 213 | * @param direction - A \c #Direction object for the direction of the gradient 214 | * (up, down, right, or left). 215 | * @param numStops - The number of stops in the gradient. 216 | * @param gradientStopList - An array of \c #GradientStop objects. 217 | */ 218 | declare class GradientColor { 219 | constructor(type: any, direction: any, numStops: any, gradientStopList: any); 220 | } 221 | 222 | /** 223 | * UIColor 224 | Stores color information, including the type, anti-alias level, and specific color 225 | values in a color object of an appropriate type. 226 | * @param type - The color type, 1 for "rgb" and 2 for "gradient". 227 | * The supplied color object must correspond to this type. 228 | * @param antialiasLevel - The anti-alias level constant. 229 | * @param color - A \c #RGBColor or \c #GradientColor object containing specific color information. 230 | */ 231 | declare class UIColor { 232 | constructor(type: any, antialiasLevel: any, color: any); 233 | } 234 | 235 | /** 236 | * AppSkinInfo 237 | Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects except that systemHighlightColor is \c #RGBColor object. 238 | * @param baseFontFamily - The base font family of the application. 239 | * @param baseFontSize - The base font size of the application. 240 | * @param appBarBackgroundColor - The application bar background color. 241 | * @param panelBackgroundColor - The background color of the extension panel. 242 | * @param appBarBackgroundColorSRGB - The application bar background color, as sRGB. 243 | * @param panelBackgroundColorSRGB - The background color of the extension panel, as sRGB. 244 | * @param systemHighlightColor - The highlight color of the extension panel, if provided by the host application. Otherwise, the operating-system highlight color. 245 | */ 246 | declare class AppSkinInfo { 247 | constructor( 248 | baseFontFamily: any, 249 | baseFontSize: any, 250 | appBarBackgroundColor: any, 251 | panelBackgroundColor: any, 252 | appBarBackgroundColorSRGB: any, 253 | panelBackgroundColorSRGB: any, 254 | systemHighlightColor: any 255 | ); 256 | } 257 | 258 | /** 259 | * HostEnvironment 260 | Stores information about the environment in which the extension is loaded. 261 | * @param appName - The application's name. 262 | * @param appVersion - The application's version. 263 | * @param appLocale - The application's current license locale. 264 | * @param appUILocale - The application's current UI locale. 265 | * @param appId - The application's unique identifier. 266 | * @param isAppOnline - True if the application is currently online. 267 | * @param appSkinInfo - An \c #AppSkinInfo object containing the application's default color and font styles. 268 | */ 269 | declare class HostEnvironment { 270 | constructor( 271 | appName: any, 272 | appVersion: any, 273 | appLocale: any, 274 | appUILocale: any, 275 | appId: any, 276 | isAppOnline: any, 277 | appSkinInfo: any 278 | ); 279 | } 280 | 281 | /** 282 | * HostCapabilities 283 | Stores information about the host capabilities. 284 | * @param EXTENDED_PANEL_MENU - True if the application supports panel menu. 285 | * @param EXTENDED_PANEL_ICONS - True if the application supports panel icon. 286 | * @param DELEGATE_APE_ENGINE - True if the application supports delegated APE engine. 287 | * @param SUPPORT_HTML_EXTENSIONS - True if the application supports HTML extensions. 288 | * @param DISABLE_FLASH_EXTENSIONS - True if the application disables FLASH extensions. 289 | */ 290 | declare class HostCapabilities { 291 | constructor( 292 | EXTENDED_PANEL_MENU: any, 293 | EXTENDED_PANEL_ICONS: any, 294 | DELEGATE_APE_ENGINE: any, 295 | SUPPORT_HTML_EXTENSIONS: any, 296 | DISABLE_FLASH_EXTENSIONS: any 297 | ); 298 | } 299 | 300 | /** 301 | * ApiVersion 302 | Stores current api version. 303 | 304 | Since 4.2.0 305 | * @param major - The major version 306 | * @param minor - The minor version. 307 | * @param micro - The micro version. 308 | */ 309 | declare class ApiVersion { 310 | constructor(major: any, minor: any, micro: any); 311 | } 312 | 313 | /** 314 | * MenuItemStatus 315 | Stores flyout menu item status 316 | 317 | Since 5.2.0 318 | * @param menuItemLabel - The menu item label. 319 | * @param enabled - True if user wants to enable the menu item. 320 | * @param checked - True if user wants to check the menu item. 321 | */ 322 | declare class MenuItemStatus { 323 | constructor(menuItemLabel: any, enabled: any, checked: any); 324 | } 325 | 326 | /** 327 | * ContextMenuItemStatus 328 | Stores the status of the context menu item. 329 | 330 | Since 5.2.0 331 | * @param menuItemID - The menu item id. 332 | * @param enabled - True if user wants to enable the menu item. 333 | * @param checked - True if user wants to check the menu item. 334 | */ 335 | declare class ContextMenuItemStatus { 336 | constructor(menuItemID: any, enabled: any, checked: any); 337 | } 338 | 339 | /** 340 | * CSInterface 341 | This is the entry point to the CEP extensibility infrastructure. 342 | Instantiate this object and use it to: 343 |
    344 |
  • Access information about the host application in which an extension is running
  • 345 |
  • Launch an extension
  • 346 |
  • Register interest in event notifications, and dispatch events
  • 347 |
348 | */ 349 | 350 | type RBGAColor = { 351 | alpha: number; 352 | green: number; 353 | blue: number; 354 | red: number; 355 | }; 356 | 357 | export default class CSInterface { 358 | constructor(); 359 | /** 360 | * User can add this event listener to handle native application theme color changes. 361 | Callback function gives extensions ability to fine-tune their theme color after the 362 | global theme color has been changed. 363 | The callback function should be like below: 364 | * @example 365 | * // event is a CSEvent object, but user can ignore it. 366 | function OnAppThemeColorChanged(event) 367 | { 368 | // Should get a latest HostEnvironment object from application. 369 | var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; 370 | // Gets the style information such as color info from the skinInfo, 371 | // and redraw all UI controls of your extension according to the style info. 372 | } 373 | */ 374 | static THEME_COLOR_CHANGED_EVENT: any; 375 | /** 376 | * The host environment data object. 377 | */ 378 | hostEnvironment: { 379 | appName: string; 380 | appVersion: string; 381 | appLocale: string; 382 | appUILocale: string; 383 | appId: string; 384 | isAppOnline: boolean; 385 | appSkinInfo: { 386 | baseFontFamily: string; 387 | baseFontSize: number; 388 | appBarBackgroundColor: { 389 | antialiasLevel: number; 390 | type: number; 391 | color: RBGAColor; 392 | }; 393 | panelBackgroundColor: { 394 | antialiasLevel: number; 395 | type: number; 396 | color: RBGAColor; 397 | }; 398 | appBarBackgroundColorSRGB: { 399 | antialiasLevel: number; 400 | type: number; 401 | color: RBGAColor; 402 | }; 403 | panelBackgroundColorSRGB: { 404 | antialiasLevel: number; 405 | type: number; 406 | color: RBGAColor; 407 | }; 408 | systemHighlightColor: RBGAColor; 409 | }; 410 | }; 411 | /** 412 | * Retrieves information about the host environment in which the 413 | extension is currently running. 414 | * @returns A \c #HostEnvironment object. 415 | */ 416 | getHostEnvironment(): any; 417 | /** 418 | * Loads binary file created which is located at url asynchronously 419 | * @example 420 | * To create JS binary use command ./cep_compiler test.js test.bin 421 | To load JS binary asyncronously 422 | var CSLib = new CSInterface(); 423 | CSLib.loadBinAsync(url, function () { }); 424 | * @param urlName - url at which binary file is located. Local files should start with 'file://' 425 | * @param callback - Optional. A callback function that returns after binary is loaded 426 | */ 427 | loadBinAsync(urlName: any, callback: any): void; 428 | /** 429 | * Loads binary file created synchronously 430 | * @example 431 | * To create JS binary use command ./cep_compiler test.js test.bin 432 | To load JS binary syncronously 433 | var CSLib = new CSInterface(); 434 | CSLib.loadBinSync(path); 435 | * @param pathName - the local path at which binary file is located 436 | */ 437 | loadBinSync(pathName: any): void; 438 | /** 439 | * Closes this extension. 440 | */ 441 | closeExtension(): void; 442 | /** 443 | * Retrieves a path for which a constant is defined in the system. 444 | * @param pathType - The path-type constant defined in \c #SystemPath , 445 | * @returns The platform-specific system path string. 446 | */ 447 | getSystemPath(pathType: any): any; 448 | /** 449 | * Evaluates a JavaScript script, which can use the JavaScript DOM 450 | of the host application. 451 | * @param script - The JavaScript script. 452 | * @param callback - Optional. A callback function that receives the result of execution. 453 | If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. 454 | */ 455 | evalScript(script: any, callback: any): void; 456 | /** 457 | * Retrieves the unique identifier of the application. 458 | in which the extension is currently running. 459 | * @returns The unique ID string. 460 | */ 461 | getApplicationID(): any; 462 | /** 463 | * Retrieves host capability information for the application 464 | in which the extension is currently running. 465 | * @returns A \c #HostCapabilities object. 466 | */ 467 | getHostCapabilities(): any; 468 | /** 469 | * Triggers a CEP event programmatically. Yoy can use it to dispatch 470 | an event of a predefined type, or of a type you have defined. 471 | * @param event - A \c CSEvent object. 472 | */ 473 | dispatchEvent(event: any): void; 474 | /** 475 | * Registers an interest in a CEP event of a particular type, and 476 | assigns an event handler. 477 | The event infrastructure notifies your extension when events of this type occur, 478 | passing the event object to the registered handler function. 479 | * @param type - The name of the event type of interest. 480 | * @param listener - The JavaScript handler function or method. 481 | * @param obj - Optional, the object containing the handler method, if any. 482 | Default is null. 483 | */ 484 | addEventListener(type: any, listener: Function, obj?: any): void; 485 | /** 486 | * Removes a registered event listener. 487 | * @param type - The name of the event type of interest. 488 | * @param listener - The JavaScript handler function or method that was registered. 489 | * @param obj - Optional, the object containing the handler method, if any. 490 | Default is null. 491 | */ 492 | removeEventListener(type: any, listener: any, obj: any): void; 493 | /** 494 | * Loads and launches another extension, or activates the extension if it is already loaded. 495 | * @example 496 | * To launch the extension "help" with ID "HLP" from this extension, call: 497 | requestOpenExtension("HLP", ""); 498 | * @param extensionId - The extension's unique identifier. 499 | * @param startupParams - Not currently used, pass "". 500 | */ 501 | requestOpenExtension(extensionId: any, startupParams: any): void; 502 | /** 503 | * Retrieves the list of extensions currently loaded in the current host application. 504 | The extension list is initialized once, and remains the same during the lifetime 505 | of the CEP session. 506 | * @param extensionIds - Optional, an array of unique identifiers for extensions of interest. 507 | If omitted, retrieves data for all extensions. 508 | * @returns Zero or more \c #Extension objects. 509 | */ 510 | getExtensions(extensionIds: any): any; 511 | /** 512 | * Retrieves network-related preferences. 513 | * @returns A JavaScript object containing network preferences. 514 | */ 515 | getNetworkPreferences(): any; 516 | /** 517 | * Initializes the resource bundle for this extension with property values 518 | for the current application and locale. 519 | To support multiple locales, you must define a property file for each locale, 520 | containing keyed display-string values for that locale. 521 | See localization documentation for Extension Builder and related products. 522 | 523 | Keys can be in the 524 | form key.value="localized string", for use in HTML text elements. 525 | For example, in this input element, the localized \c key.value string is displayed 526 | instead of the empty \c value string: 527 | 528 | 529 | * @returns An object containing the resource bundle information. 530 | */ 531 | initResourceBundle(): any; 532 | /** 533 | * Writes installation information to a file. 534 | * @returns The file path. 535 | */ 536 | dumpInstallationInfo(): any; 537 | /** 538 | * Retrieves version information for the current Operating System, 539 | See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. 540 | * @returns A string containing the OS version, or "unknown Operation System". 541 | If user customizes the User Agent by setting CEF command parameter "--user-agent", only 542 | "Mac OS X" or "Windows" will be returned. 543 | */ 544 | getOSInformation(): any; 545 | /** 546 | * Opens a page in the default system browser. 547 | 548 | Since 4.2.0 549 | * @param url - The URL of the page/file to open, or the email address. 550 | Must use HTTP/HTTPS/file/mailto protocol. For example: 551 | "http://www.adobe.com" 552 | "https://github.com" 553 | "file:///C:/log.txt" 554 | "mailto:test@adobe.com" 555 | * @returns One of these error codes:\n 556 |
    \n 557 |
  • NO_ERROR - 0
  • \n 558 |
  • ERR_UNKNOWN - 1
  • \n 559 |
  • ERR_INVALID_PARAMS - 2
  • \n 560 |
  • ERR_INVALID_URL - 201
  • \n 561 |
\n 562 | */ 563 | openURLInDefaultBrowser(url: any): any; 564 | /** 565 | * Retrieves extension ID. 566 | 567 | Since 4.2.0 568 | * @returns extension ID. 569 | */ 570 | getExtensionID(): any; 571 | /** 572 | * Retrieves the scale factor of screen. 573 | On Windows platform, the value of scale factor might be different from operating system's scale factor, 574 | since host application may use its self-defined scale factor. 575 | 576 | Since 4.2.0 577 | * @returns One of the following float number. 578 |
    \n 579 |
  • -1.0 when error occurs
  • \n 580 |
  • 1.0 means normal screen
  • \n 581 |
  • >1.0 means HiDPI screen
  • \n 582 |
\n 583 | */ 584 | getScaleFactor(): any; 585 | /** 586 | * Set a handler to detect any changes of scale factor. This only works on Mac. 587 | 588 | Since 4.2.0 589 | * @param handler - The function to be called when scale factor is changed. 590 | */ 591 | setScaleFactorChangedHandler(handler: any): void; 592 | /** 593 | * Retrieves current API version. 594 | 595 | Since 4.2.0 596 | * @returns ApiVersion object. 597 | */ 598 | getCurrentApiVersion(): { 599 | minor: string; 600 | micro: string; 601 | major: string; 602 | }; 603 | /** 604 | * Set panel flyout menu by an XML. 605 | 606 | Since 5.2.0 607 | 608 | Register a callback function for "com.adobe.csxs.events.flyoutMenuClicked" to get notified when a 609 | menu item is clicked. 610 | The "data" attribute of event is an object which contains "menuId" and "menuName" attributes. 611 | 612 | Register callback functions for "com.adobe.csxs.events.flyoutMenuOpened" and "com.adobe.csxs.events.flyoutMenuClosed" 613 | respectively to get notified when flyout menu is opened or closed. 614 | * @param menu - A XML string which describes menu structure. 615 | An example menu XML: 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | */ 628 | setPanelFlyoutMenu(menu: any): void; 629 | /** 630 | * Updates a menu item in the extension window's flyout menu, by setting the enabled 631 | and selection status. 632 | 633 | Since 5.2.0 634 | * @param menuItemLabel - The menu item label. 635 | * @param enabled - True to enable the item, false to disable it (gray it out). 636 | * @param checked - True to select the item, false to deselect it. 637 | * @returns false when the host application does not support this functionality (HostCapabilities.EXTENDED_PANEL_MENU is false). 638 | Fails silently if menu label is invalid. 639 | */ 640 | updatePanelMenuItem(menuItemLabel: any, enabled: any, checked: any): any; 641 | /** 642 | * An example menu XML: 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | * @param menu - A XML string which describes menu structure. 655 | * @param callback - The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. 656 | */ 657 | setContextMenu(menu: any, callback: any): void; 658 | /** 659 | * An example menu JSON: 660 | 661 | { 662 | "menu": [ 663 | { 664 | "id": "menuItemId1", 665 | "label": "testExample1", 666 | "enabled": true, 667 | "checkable": true, 668 | "checked": false, 669 | "icon": "./image/small_16X16.png" 670 | }, 671 | { 672 | "id": "menuItemId2", 673 | "label": "testExample2", 674 | "menu": [ 675 | { 676 | "id": "menuItemId2-1", 677 | "label": "testExample2-1", 678 | "menu": [ 679 | { 680 | "id": "menuItemId2-1-1", 681 | "label": "testExample2-1-1", 682 | "enabled": false, 683 | "checkable": true, 684 | "checked": true 685 | } 686 | ] 687 | }, 688 | { 689 | "id": "menuItemId2-2", 690 | "label": "testExample2-2", 691 | "enabled": true, 692 | "checkable": true, 693 | "checked": true 694 | } 695 | ] 696 | }, 697 | { 698 | "label": "---" 699 | }, 700 | { 701 | "id": "menuItemId3", 702 | "label": "testExample3", 703 | "enabled": false, 704 | "checkable": true, 705 | "checked": false 706 | } 707 | ] 708 | } 709 | * @param menu - A JSON string which describes menu structure. 710 | * @param callback - The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. 711 | */ 712 | setContextMenuByJSON(menu: any, callback: any): void; 713 | /** 714 | * Updates a context menu item by setting the enabled and selection status. 715 | 716 | Since 5.2.0 717 | * @param menuItemID - The menu item ID. 718 | * @param enabled - True to enable the item, false to disable it (gray it out). 719 | * @param checked - True to select the item, false to deselect it. 720 | */ 721 | updateContextMenuItem(menuItemID: any, enabled: any, checked: any): void; 722 | /** 723 | * Get the visibility status of an extension window. 724 | 725 | Since 6.0.0 726 | * @returns true if the extension window is visible; false if the extension window is hidden. 727 | */ 728 | isWindowVisible(): any; 729 | /** 730 | * Resize extension's content to the specified dimensions. 731 | 1. Works with modal and modeless extensions in all Adobe products. 732 | 2. Extension's manifest min/max size constraints apply and take precedence. 733 | 3. For panel extensions 734 | 3.1 This works in all Adobe products except: 735 | * Premiere Pro 736 | * Prelude 737 | * After Effects 738 | 3.2 When the panel is in certain states (especially when being docked), 739 | it will not change to the desired dimensions even when the 740 | specified size satisfies min/max constraints. 741 | 742 | Since 6.0.0 743 | * @param width - The new width 744 | * @param height - The new height 745 | */ 746 | resizeContent(width: any, height: any): void; 747 | /** 748 | * Register the invalid certificate callback for an extension. 749 | This callback will be triggered when the extension tries to access the web site that contains the invalid certificate on the main frame. 750 | But if the extension does not call this function and tries to access the web site containing the invalid certificate, a default error page will be shown. 751 | 752 | Since 6.1.0 753 | * @param callback - the callback function 754 | */ 755 | registerInvalidCertificateCallback(callback: any): void; 756 | /** 757 | * Register an interest in some key events to prevent them from being sent to the host application. 758 | 759 | This function works with modeless extensions and panel extensions. 760 | Generally all the key events will be sent to the host application for these two extensions if the current focused element 761 | is not text input or dropdown, 762 | If you want to intercept some key events and want them to be handled in the extension, please call this function 763 | in advance to prevent them being sent to the host application. 764 | 765 | Since 6.1.0 766 | */ 767 | registerKeyEventsInterest(keyEventsInterest: any): void; 768 | /** 769 | * Set the title of the extension window. 770 | This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. 771 | 772 | Since 6.1.0 773 | * @param title - The window title. 774 | */ 775 | setWindowTitle(title: any): void; 776 | /** 777 | * Get the title of the extension window. 778 | This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. 779 | 780 | Since 6.1.0 781 | * @returns The window title. 782 | */ 783 | getWindowTitle(): any; 784 | } 785 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/es-types/index.ts: -------------------------------------------------------------------------------- 1 | export type Scripts = { 2 | [key: string]: (...ags: any) => any; 3 | }; 4 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/node.ts: -------------------------------------------------------------------------------- 1 | // Abstracted built-in Node.js Modules 2 | 3 | //@ts-ignore 4 | export const crypto = ( 5 | typeof window.cep !== "undefined" ? require("crypto") : {} 6 | ) as typeof import("crypto"); 7 | export const assert = ( 8 | typeof window.cep !== "undefined" ? require("assert") : {} 9 | ) as typeof import("assert"); 10 | export const buffer = ( 11 | typeof window.cep !== "undefined" ? require("buffer") : {} 12 | ) as typeof import("buffer"); 13 | export const child_process = ( 14 | typeof window.cep !== "undefined" ? require("child_process") : {} 15 | ) as typeof import("child_process"); 16 | export const cluster = ( 17 | typeof window.cep !== "undefined" ? require("cluster") : {} 18 | ) as typeof import("cluster"); 19 | export const dgram = ( 20 | typeof window.cep !== "undefined" ? require("dgram") : {} 21 | ) as typeof import("dgram"); 22 | export const dns = ( 23 | typeof window.cep !== "undefined" ? require("dns") : {} 24 | ) as typeof import("dns"); 25 | export const domain = ( 26 | typeof window.cep !== "undefined" ? require("domain") : {} 27 | ) as typeof import("domain"); 28 | export const events = ( 29 | typeof window.cep !== "undefined" ? require("events") : {} 30 | ) as typeof import("events"); 31 | export const fs = ( 32 | typeof window.cep !== "undefined" ? require("fs") : {} 33 | ) as typeof import("fs"); 34 | export const http = ( 35 | typeof window.cep !== "undefined" ? require("http") : {} 36 | ) as typeof import("http"); 37 | export const https = ( 38 | typeof window.cep !== "undefined" ? require("https") : {} 39 | ) as typeof import("https"); 40 | export const net = ( 41 | typeof window.cep !== "undefined" ? require("net") : {} 42 | ) as typeof import("net"); 43 | export const os = ( 44 | typeof window.cep !== "undefined" ? require("os") : {} 45 | ) as typeof import("os"); 46 | export const path = ( 47 | typeof window.cep !== "undefined" ? require("path") : {} 48 | ) as typeof import("path"); 49 | export const punycode = ( 50 | typeof window.cep !== "undefined" ? require("punycode") : {} 51 | ) as typeof import("punycode"); 52 | export const querystring = ( 53 | typeof window.cep !== "undefined" ? require("querystring") : {} 54 | ) as typeof import("querystring"); 55 | export const readline = ( 56 | typeof window.cep !== "undefined" ? require("readline") : {} 57 | ) as typeof import("readline"); 58 | export const stream = ( 59 | typeof window.cep !== "undefined" ? require("stream") : {} 60 | ) as typeof import("stream"); 61 | export const string_decoder = ( 62 | typeof window.cep !== "undefined" ? require("string_decoder") : {} 63 | ) as typeof import("string_decoder"); 64 | export const timers = ( 65 | typeof window.cep !== "undefined" ? require("timers") : {} 66 | ) as typeof import("timers"); 67 | export const tls = ( 68 | typeof window.cep !== "undefined" ? require("tls") : {} 69 | ) as typeof import("tls"); 70 | export const tty = ( 71 | typeof window.cep !== "undefined" ? require("tty") : {} 72 | ) as typeof import("tty"); 73 | export const url = ( 74 | typeof window.cep !== "undefined" ? require("url") : {} 75 | ) as typeof import("url"); 76 | export const util = ( 77 | typeof window.cep !== "undefined" ? require("util") : {} 78 | ) as typeof import("util"); 79 | export const v8 = ( 80 | typeof window.cep !== "undefined" ? require("v8") : {} 81 | ) as typeof import("v8"); 82 | export const vm = ( 83 | typeof window.cep !== "undefined" ? require("vm") : {} 84 | ) as typeof import("vm"); 85 | export const zlib = ( 86 | typeof window.cep !== "undefined" ? require("zlib") : {} 87 | ) as typeof import("zlib"); 88 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/vulcan.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Vulcan 3 | 4 | The singleton instance, VulcanInterface, provides an interface 5 | to the Vulcan. Allows you to launch CC applications 6 | and discover information about them. 7 | */ 8 | export default class Vulcan { 9 | constructor(); 10 | 11 | /** 12 | * Gets all available application SAPCode-Specifiers on the local machine. 13 | * 14 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 15 | * Changes : New getTargetSpecifiersEx returns productSAPCodeSpecifiers 16 | * 17 | * @return The array of all available application SAPCode-Specifiers. 18 | */ 19 | getTargetSpecifiersEx(): any; 20 | 21 | /** 22 | * Launches a CC application on the local machine, if it is not already running. 23 | * 24 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 25 | * Changes : New launchAppEx uses productSAPCodeSpecifiers 26 | * 27 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 28 | * @param focus True to launch in foreground, or false to launch in the background. 29 | * @param cmdLine Optional, command-line parameters to supply to the launch command. 30 | * @return True if the app can be launched, false otherwise. 31 | */ 32 | launchAppEx( 33 | productSAPCodeSpecifier: string, 34 | focus: boolean, 35 | cmdLine?: string 36 | ): boolean; 37 | 38 | /** 39 | * Checks whether a CC application is running on the local machine. 40 | * 41 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 42 | * Changes : New isAppRunningEx uses productSAPCodeSpecifiers 43 | * 44 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 45 | * @return True if the app is running, false otherwise. 46 | */ 47 | isAppRunningEx(productSAPCodeSpecifier: string): boolean; 48 | 49 | /** 50 | * Checks whether a CC application is installed on the local machine. 51 | * 52 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 53 | * Changes : New isAppInstalledEx uses productSAPCodeSpecifiers 54 | * 55 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 56 | * @return True if the app is installed, false otherwise. 57 | */ 58 | isAppInstalledEx(productSAPCodeSpecifier: string): any; 59 | 60 | /**s 61 | * Retrieves the local install path of a CC application. 62 | * 63 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 64 | * Changes : New getAppPathEx uses productSAPCodeSpecifiers 65 | * 66 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 67 | * @return The path string if the application is found, "" otherwise. 68 | */ 69 | getAppPathEx(): any; 70 | 71 | // OLD FUNCTIONS 72 | // OLD FUNCTIONS 73 | // OLD FUNCTIONS 74 | // OLD FUNCTIONS 75 | 76 | /** 77 | * Gets all available application specifiers on the local machine. 78 | * @returns The array of all available application specifiers. 79 | */ 80 | getTargetSpecifiers(): any; 81 | /** 82 | * Launches a CC application on the local machine, if it is not already running. 83 | * @param targetSpecifier - The application specifier; for example "indesign". 84 | 85 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 86 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 87 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 88 | receive wrong result. 89 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 90 | 91 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 92 | * @param focus - True to launch in foreground, or false to launch in the background. 93 | * @param cmdLine - Optional, command-line parameters to supply to the launch command. 94 | * @returns True if the app can be launched, false otherwise. 95 | */ 96 | launchApp(targetSpecifier: any, focus: any, cmdLine: any): any; 97 | /** 98 | * Checks whether a CC application is running on the local machine. 99 | * @param targetSpecifier - The application specifier; for example "indesign". 100 | 101 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 102 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 103 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 104 | receive wrong result. 105 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 106 | 107 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 108 | * @returns True if the app is running, false otherwise. 109 | */ 110 | isAppRunning(targetSpecifier: any): any; 111 | /** 112 | * Checks whether a CC application is installed on the local machine. 113 | * @param targetSpecifier - The application specifier; for example "indesign". 114 | 115 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 116 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 117 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 118 | receive wrong result. 119 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 120 | 121 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 122 | * @returns True if the app is installed, false otherwise. 123 | */ 124 | isAppInstalled(targetSpecifier: any): any; 125 | /** 126 | * Retrieves the local install path of a CC application. 127 | * @param targetSpecifier - The application specifier; for example "indesign". 128 | 129 | Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 130 | and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 131 | installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 132 | receive wrong result. 133 | The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 134 | 135 | In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 136 | * @returns The path string if the application is found, "" otherwise. 137 | */ 138 | getAppPath(targetSpecifier: any): any; 139 | /** 140 | * Registers a message listener callback function for a Vulcan message. 141 | * @param type - The message type. 142 | * @param callback - The callback function that handles the message. 143 | Takes one argument, the message object. 144 | * @param obj - Optional, the object containing the callback method, if any. 145 | Default is null. 146 | */ 147 | addMessageListener(type: any, callback: any, obj: any): void; 148 | /** 149 | * Removes a registered message listener callback function for a Vulcan message. 150 | * @param type - The message type. 151 | * @param callback - The callback function that was registered. 152 | Takes one argument, the message object. 153 | * @param obj - Optional, the object containing the callback method, if any. 154 | Default is null. 155 | */ 156 | removeMessageListener(type: any, callback: any, obj: any): void; 157 | /** 158 | * Dispatches a Vulcan message. 159 | * @param vulcanMessage - The message object. 160 | */ 161 | dispatchMessage(vulcanMessage: any): void; 162 | /** 163 | * Retrieves the message payload of a Vulcan message for the registered message listener callback function. 164 | * @param vulcanMessage - The message object. 165 | * @returns A string containing the message payload. 166 | */ 167 | getPayload(vulcanMessage: any): any; 168 | /** 169 | * Gets all available endpoints of the running Vulcan-enabled applications. 170 | 171 | Since 7.0.0 172 | * @returns The array of all available endpoints. 173 | An example endpoint string: 174 | 175 | PHXS 176 | 16.1.0 177 | 178 | */ 179 | getEndPoints(): any; 180 | /** 181 | * Gets the endpoint for itself. 182 | 183 | Since 7.0.0 184 | * @returns The endpoint string for itself. 185 | */ 186 | getSelfEndPoint(): any; 187 | } 188 | 189 | /** 190 | * Singleton instance of Vulcan 191 | */ 192 | declare var VulcanInterface: any; 193 | 194 | /** 195 | * VulcanMessage 196 | Message type for sending messages between host applications. 197 | A message of this type can be sent to the designated destination 198 | when appId and appVersion are provided and valid. Otherwise, 199 | the message is broadcast to all running Vulcan-enabled applications. 200 | 201 | To send a message between extensions running within one 202 | application, use the CSEvent type in CSInterface.js. 203 | * @param type - The message type. 204 | * @param appId - The peer appId. 205 | * @param appVersion - The peer appVersion. 206 | */ 207 | export declare class VulcanMessage { 208 | static TYPE_PREFIX: string; 209 | static SCOPE_SUITE: string; 210 | static DEFAULT_APP_ID: string; 211 | static DEFAULT_APP_VERSION: string; 212 | static DEFAULT_DATA: string; 213 | static dataTemplate: string; 214 | static payloadTemplate: string; 215 | constructor(type: any, appId: any, appVersion: any); 216 | /** 217 | * Initializes this message instance. 218 | * @param message - A \c message instance to use for initialization. 219 | */ 220 | initialize(message: any): void; 221 | /** 222 | * Retrieves the message data. 223 | * @returns A data string in XML format. 224 | */ 225 | xmlData(): any; 226 | /** 227 | * Sets the message payload of this message. 228 | * @param payload - A string containing the message payload. 229 | */ 230 | setPayload(payload: any): void; 231 | /** 232 | * Retrieves the message payload of this message. 233 | * @returns A string containing the message payload. 234 | */ 235 | getPayload(): any; 236 | /** 237 | * Converts the properties of this instance to a string. 238 | * @returns The string version of this instance. 239 | */ 240 | toString(): any; 241 | } 242 | 243 | /** 244 | * Retrieves the content of an XML element. 245 | * @param xmlStr - The XML string. 246 | * @param key - The name of the tag. 247 | * @returns The content of the tag, or the empty string 248 | if such tag is not found or the tag has no content. 249 | */ 250 | declare function GetValueByKey(xmlStr: any, key: any): any; 251 | 252 | /** 253 | * Reports whether required parameters are valid. 254 | * @returns True if all required parameters are valid, 255 | false if any of the required parameters are invalid. 256 | */ 257 | declare function requiredParamsValid(): any; 258 | 259 | /** 260 | * Reports whether a string has a given prefix. 261 | * @param str - The target string. 262 | * @param prefix - The specific prefix string. 263 | * @returns True if the string has the prefix, false if not. 264 | */ 265 | declare function strStartsWith(str: any, prefix: any): any; 266 | -------------------------------------------------------------------------------- /ae/src/ui/lib/cep/vulcan.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * 3 | * ADOBE SYSTEMS INCORPORATED 4 | * Copyright 2020 Adobe Systems Incorporated 5 | * All Rights Reserved. 6 | * 7 | * NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the 8 | * terms of the Adobe license agreement accompanying it. If you have received this file from a 9 | * source other than Adobe, then your use, modification, or distribution of it requires the prior 10 | * written permission of Adobe. 11 | * 12 | **************************************************************************************************/ 13 | 14 | /** Vulcan - v11.2.0 */ 15 | 16 | /** 17 | * @class Vulcan 18 | * 19 | * The singleton instance, VulcanInterface, provides an interface 20 | * to the Vulcan. Allows you to launch CC applications 21 | * and discover information about them. 22 | */ 23 | function Vulcan() {} 24 | 25 | /** 26 | * Gets all available application SAPCode-Specifiers on the local machine. 27 | * 28 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 29 | * Changes : New getTargetSpecifiersEx returns productSAPCodeSpecifiers 30 | * 31 | * @return The array of all available application SAPCode-Specifiers. 32 | */ 33 | Vulcan.prototype.getTargetSpecifiersEx = function () { 34 | var params = {}; 35 | return JSON.parse( 36 | window.__adobe_cep__.invokeSync( 37 | "vulcanGetTargetSpecifiersEx", 38 | JSON.stringify(params) 39 | ) 40 | ); 41 | }; 42 | 43 | /** 44 | * Launches a CC application on the local machine, if it is not already running. 45 | * 46 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 47 | * Changes : New launchAppEx uses productSAPCodeSpecifiers 48 | * 49 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 50 | * @param focus True to launch in foreground, or false to launch in the background. 51 | * @param cmdLine Optional, command-line parameters to supply to the launch command. 52 | * @return True if the app can be launched, false otherwise. 53 | */ 54 | Vulcan.prototype.launchAppEx = function ( 55 | productSAPCodeSpecifier, 56 | focus, 57 | cmdLine 58 | ) { 59 | if (!requiredParamsValid(productSAPCodeSpecifier)) { 60 | return false; 61 | } 62 | 63 | var params = {}; 64 | params.productSAPCodeSpecifier = productSAPCodeSpecifier; 65 | params.focus = focus ? "true" : "false"; 66 | params.cmdLine = requiredParamsValid(cmdLine) ? cmdLine : ""; 67 | 68 | return JSON.parse( 69 | window.__adobe_cep__.invokeSync("vulcanLaunchAppEx", JSON.stringify(params)) 70 | ).result; 71 | }; 72 | 73 | /** 74 | * Checks whether a CC application is running on the local machine. 75 | * 76 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 77 | * Changes : New isAppRunningEx uses productSAPCodeSpecifiers 78 | * 79 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 80 | * @return True if the app is running, false otherwise. 81 | */ 82 | Vulcan.prototype.isAppRunningEx = function (productSAPCodeSpecifier) { 83 | if (!requiredParamsValid(productSAPCodeSpecifier)) { 84 | return false; 85 | } 86 | 87 | var params = {}; 88 | params.productSAPCodeSpecifier = productSAPCodeSpecifier; 89 | 90 | return JSON.parse( 91 | window.__adobe_cep__.invokeSync( 92 | "vulcanIsAppRunningEx", 93 | JSON.stringify(params) 94 | ) 95 | ).result; 96 | }; 97 | 98 | /** 99 | * Checks whether a CC application is installed on the local machine. 100 | * 101 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 102 | * Changes : New isAppInstalledEx uses productSAPCodeSpecifiers 103 | * 104 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 105 | * @return True if the app is installed, false otherwise. 106 | */ 107 | Vulcan.prototype.isAppInstalledEx = function (productSAPCodeSpecifier) { 108 | if (!requiredParamsValid(productSAPCodeSpecifier)) { 109 | return false; 110 | } 111 | 112 | var params = {}; 113 | params.productSAPCodeSpecifier = productSAPCodeSpecifier; 114 | 115 | return JSON.parse( 116 | window.__adobe_cep__.invokeSync( 117 | "vulcanIsAppInstalledEx", 118 | JSON.stringify(params) 119 | ) 120 | ).result; 121 | }; 122 | 123 | /**s 124 | * Retrieves the local install path of a CC application. 125 | * 126 | * Vulcan Control New 6.x APIs, and Deprecating older Vulcan Control APIs. 127 | * Changes : New getAppPathEx uses productSAPCodeSpecifiers 128 | * 129 | * @param productSAPCodeSpecifier The application specifier; for example "ILST-25.2.3", "ILST-25", "ILST-25.2.3-en_US" and "ILST. Refer to `Documentation/CEP 11.1 HTML Extension Cookbook.md#applications-integrated-with-cep` for product SAPCode. 130 | * @return The path string if the application is found, "" otherwise. 131 | */ 132 | Vulcan.prototype.getAppPathEx = function (productSAPCodeSpecifier) { 133 | if (!requiredParamsValid(productSAPCodeSpecifier)) { 134 | return ""; 135 | } 136 | 137 | var params = {}; 138 | params.productSAPCodeSpecifier = productSAPCodeSpecifier; 139 | 140 | return JSON.parse( 141 | window.__adobe_cep__.invokeSync( 142 | "vulcanGetAppPathEx", 143 | JSON.stringify(params) 144 | ) 145 | ).result; 146 | }; 147 | 148 | /** 149 | * DEPRECATED API:: use getTargetSpecifiersEx 150 | * Gets all available application specifiers on the local machine. 151 | * 152 | * @return The array of all available application specifiers. 153 | */ 154 | Vulcan.prototype.getTargetSpecifiers = function () { 155 | console.warn( 156 | "WARNING! Function 'getTargetSpecifiers' has been deprecated, please use the new 'getTargetSpecifiersEx' function instead!" 157 | ); 158 | var params = {}; 159 | return JSON.parse( 160 | window.__adobe_cep__.invokeSync( 161 | "vulcanGetTargetSpecifiers", 162 | JSON.stringify(params) 163 | ) 164 | ); 165 | }; 166 | 167 | /** 168 | * DEPRECATED API:: use launchAppEx 169 | * Launches a CC application on the local machine, if it is not already running. 170 | * 171 | * @param targetSpecifier The application specifier; for example "indesign". 172 | * 173 | * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 174 | * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 175 | * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 176 | * receive wrong result. 177 | * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 178 | * 179 | * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 180 | * @param focus True to launch in foreground, or false to launch in the background. 181 | * @param cmdLine Optional, command-line parameters to supply to the launch command. 182 | * @return True if the app can be launched, false otherwise. 183 | */ 184 | Vulcan.prototype.launchApp = function (targetSpecifier, focus, cmdLine) { 185 | console.warn( 186 | "WARNING! Function 'launchApp' has been deprecated, please use the new 'launchAppEx' function instead!" 187 | ); 188 | if (!requiredParamsValid(targetSpecifier)) { 189 | return false; 190 | } 191 | 192 | var params = {}; 193 | params.targetSpecifier = targetSpecifier; 194 | params.focus = focus ? "true" : "false"; 195 | params.cmdLine = requiredParamsValid(cmdLine) ? cmdLine : ""; 196 | 197 | return JSON.parse( 198 | window.__adobe_cep__.invokeSync("vulcanLaunchApp", JSON.stringify(params)) 199 | ).result; 200 | }; 201 | 202 | /** 203 | * DEPRECATED API:: use isAppRunningEx 204 | * Checks whether a CC application is running on the local machine. 205 | * 206 | * @param targetSpecifier The application specifier; for example "indesign". 207 | * 208 | * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 209 | * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 210 | * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 211 | * receive wrong result. 212 | * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 213 | * 214 | * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 215 | * @return True if the app is running, false otherwise. 216 | */ 217 | Vulcan.prototype.isAppRunning = function (targetSpecifier) { 218 | console.warn( 219 | "WARNING! Function 'isAppRunning' has been deprecated, please use the new 'isAppRunningEx' function instead!" 220 | ); 221 | if (!requiredParamsValid(targetSpecifier)) { 222 | return false; 223 | } 224 | 225 | var params = {}; 226 | params.targetSpecifier = targetSpecifier; 227 | 228 | return JSON.parse( 229 | window.__adobe_cep__.invokeSync( 230 | "vulcanIsAppRunning", 231 | JSON.stringify(params) 232 | ) 233 | ).result; 234 | }; 235 | 236 | /** 237 | * DEPRECATED API:: use isAppInstalledEx 238 | * Checks whether a CC application is installed on the local machine. 239 | * 240 | * @param targetSpecifier The application specifier; for example "indesign". 241 | * 242 | * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 243 | * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 244 | * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 245 | * receive wrong result. 246 | * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 247 | * 248 | * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 249 | * @return True if the app is installed, false otherwise. 250 | */ 251 | Vulcan.prototype.isAppInstalled = function (targetSpecifier) { 252 | console.warn( 253 | "WARNING! Function 'isAppInstalled' has been deprecated, please use the new 'isAppInstalledEx' function instead!" 254 | ); 255 | if (!requiredParamsValid(targetSpecifier)) { 256 | return false; 257 | } 258 | 259 | var params = {}; 260 | params.targetSpecifier = targetSpecifier; 261 | 262 | return JSON.parse( 263 | window.__adobe_cep__.invokeSync( 264 | "vulcanIsAppInstalled", 265 | JSON.stringify(params) 266 | ) 267 | ).result; 268 | }; 269 | 270 | /** 271 | * DEPRECATED API:: use getAppPathEx 272 | * Retrieves the local install path of a CC application. 273 | * 274 | * @param targetSpecifier The application specifier; for example "indesign". 275 | * 276 | * Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version 277 | * and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you 278 | * installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may 279 | * receive wrong result. 280 | * The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator". 281 | * 282 | * In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier. 283 | * @return The path string if the application is found, "" otherwise. 284 | */ 285 | Vulcan.prototype.getAppPath = function (targetSpecifier) { 286 | console.warn( 287 | "WARNING! Function 'getAppPath' has been deprecated, please use the new 'getAppPathEx' function instead!" 288 | ); 289 | if (!requiredParamsValid(targetSpecifier)) { 290 | return ""; 291 | } 292 | 293 | var params = {}; 294 | params.targetSpecifier = targetSpecifier; 295 | 296 | return JSON.parse( 297 | window.__adobe_cep__.invokeSync("vulcanGetAppPath", JSON.stringify(params)) 298 | ).result; 299 | }; 300 | 301 | /** 302 | * Registers a message listener callback function for a Vulcan message. 303 | * 304 | * @param type The message type. 305 | * @param callback The callback function that handles the message. 306 | * Takes one argument, the message object. 307 | * @param obj Optional, the object containing the callback method, if any. 308 | * Default is null. 309 | */ 310 | Vulcan.prototype.addMessageListener = function (type, callback, obj) { 311 | if ( 312 | !requiredParamsValid(type, callback) || 313 | !strStartsWith(type, VulcanMessage.TYPE_PREFIX) 314 | ) { 315 | return; 316 | } 317 | 318 | var params = {}; 319 | params.type = type; 320 | 321 | window.__adobe_cep__.invokeAsync( 322 | "vulcanAddMessageListener", 323 | JSON.stringify(params), 324 | callback, 325 | obj 326 | ); 327 | }; 328 | 329 | /** 330 | * Removes a registered message listener callback function for a Vulcan message. 331 | * 332 | * @param type The message type. 333 | * @param callback The callback function that was registered. 334 | * Takes one argument, the message object. 335 | * @param obj Optional, the object containing the callback method, if any. 336 | * Default is null. 337 | */ 338 | Vulcan.prototype.removeMessageListener = function (type, callback, obj) { 339 | if ( 340 | !requiredParamsValid(type, callback) || 341 | !strStartsWith(type, VulcanMessage.TYPE_PREFIX) 342 | ) { 343 | return; 344 | } 345 | 346 | var params = {}; 347 | params.type = type; 348 | 349 | window.__adobe_cep__.invokeAsync( 350 | "vulcanRemoveMessageListener", 351 | JSON.stringify(params), 352 | callback, 353 | obj 354 | ); 355 | }; 356 | 357 | /** 358 | * Dispatches a Vulcan message. 359 | * 360 | * @param vulcanMessage The message object. 361 | */ 362 | Vulcan.prototype.dispatchMessage = function (vulcanMessage) { 363 | if ( 364 | !requiredParamsValid(vulcanMessage) || 365 | !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX) 366 | ) { 367 | return; 368 | } 369 | 370 | var params = {}; 371 | var message = new VulcanMessage(vulcanMessage.type); 372 | message.initialize(vulcanMessage); 373 | params.vulcanMessage = message; 374 | 375 | window.__adobe_cep__.invokeSync( 376 | "vulcanDispatchMessage", 377 | JSON.stringify(params) 378 | ); 379 | }; 380 | 381 | /** 382 | * Retrieves the message payload of a Vulcan message for the registered message listener callback function. 383 | * 384 | * @param vulcanMessage The message object. 385 | * @return A string containing the message payload. 386 | */ 387 | Vulcan.prototype.getPayload = function (vulcanMessage) { 388 | if ( 389 | !requiredParamsValid(vulcanMessage) || 390 | !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX) 391 | ) { 392 | return null; 393 | } 394 | 395 | var message = new VulcanMessage(vulcanMessage.type); 396 | message.initialize(vulcanMessage); 397 | return message.getPayload(); 398 | }; 399 | 400 | /** 401 | * Gets all available endpoints of the running Vulcan-enabled applications. 402 | * 403 | * Since 7.0.0 404 | * 405 | * @return The array of all available endpoints. 406 | * An example endpoint string: 407 | * 408 | * PHXS 409 | * 16.1.0 410 | * 411 | */ 412 | Vulcan.prototype.getEndPoints = function () { 413 | var params = {}; 414 | return JSON.parse( 415 | window.__adobe_cep__.invokeSync( 416 | "vulcanGetEndPoints", 417 | JSON.stringify(params) 418 | ) 419 | ); 420 | }; 421 | 422 | /** 423 | * Gets the endpoint for itself. 424 | * 425 | * Since 7.0.0 426 | * 427 | * @return The endpoint string for itself. 428 | */ 429 | Vulcan.prototype.getSelfEndPoint = function () { 430 | var params = {}; 431 | return window.__adobe_cep__.invokeSync( 432 | "vulcanGetSelfEndPoint", 433 | JSON.stringify(params) 434 | ); 435 | }; 436 | 437 | /** Singleton instance of Vulcan **/ 438 | var VulcanInterface = new Vulcan(); 439 | 440 | //--------------------------------- Vulcan Message ------------------------------ 441 | 442 | /** 443 | * @class VulcanMessage 444 | * Message type for sending messages between host applications. 445 | * A message of this type can be sent to the designated destination 446 | * when appId and appVersion are provided and valid. Otherwise, 447 | * the message is broadcast to all running Vulcan-enabled applications. 448 | * 449 | * To send a message between extensions running within one 450 | * application, use the CSEvent type in CSInterface.js. 451 | * 452 | * @param type The message type. 453 | * @param appId The peer appId. 454 | * @param appVersion The peer appVersion. 455 | * 456 | */ 457 | function VulcanMessage(type, appId, appVersion) { 458 | this.type = type; 459 | this.scope = VulcanMessage.SCOPE_SUITE; 460 | this.appId = requiredParamsValid(appId) 461 | ? appId 462 | : VulcanMessage.DEFAULT_APP_ID; 463 | this.appVersion = requiredParamsValid(appVersion) 464 | ? appVersion 465 | : VulcanMessage.DEFAULT_APP_VERSION; 466 | this.data = VulcanMessage.DEFAULT_DATA; 467 | } 468 | 469 | VulcanMessage.TYPE_PREFIX = "vulcan.SuiteMessage."; 470 | VulcanMessage.SCOPE_SUITE = "GLOBAL"; 471 | VulcanMessage.DEFAULT_APP_ID = "UNKNOWN"; 472 | VulcanMessage.DEFAULT_APP_VERSION = "UNKNOWN"; 473 | VulcanMessage.DEFAULT_DATA = ""; 474 | VulcanMessage.dataTemplate = "{0}"; 475 | VulcanMessage.payloadTemplate = "{0}"; 476 | 477 | /** 478 | * Initializes this message instance. 479 | * 480 | * @param message A \c message instance to use for initialization. 481 | */ 482 | VulcanMessage.prototype.initialize = function (message) { 483 | this.type = message.type; 484 | this.scope = message.scope; 485 | this.appId = message.appId; 486 | this.appVersion = message.appVersion; 487 | this.data = message.data; 488 | }; 489 | 490 | /** 491 | * Retrieves the message data. 492 | * 493 | * @return A data string in XML format. 494 | */ 495 | VulcanMessage.prototype.xmlData = function () { 496 | if (this.data === undefined) { 497 | var str = ""; 498 | str = String.format(VulcanMessage.payloadTemplate, str); 499 | this.data = String.format(VulcanMessage.dataTemplate, str); 500 | } 501 | return this.data; 502 | }; 503 | 504 | /** 505 | * Sets the message payload of this message. 506 | * 507 | * @param payload A string containing the message payload. 508 | */ 509 | VulcanMessage.prototype.setPayload = function (payload) { 510 | var str = cep.encoding.convertion.utf8_to_b64(payload); 511 | str = String.format(VulcanMessage.payloadTemplate, str); 512 | this.data = String.format(VulcanMessage.dataTemplate, str); 513 | }; 514 | 515 | /** 516 | * Retrieves the message payload of this message. 517 | * 518 | * @return A string containing the message payload. 519 | */ 520 | VulcanMessage.prototype.getPayload = function () { 521 | var str = GetValueByKey(this.data, "payload"); 522 | if (str !== null) { 523 | return cep.encoding.convertion.b64_to_utf8(str); 524 | } 525 | return null; 526 | }; 527 | 528 | /** 529 | * Converts the properties of this instance to a string. 530 | * 531 | * @return The string version of this instance. 532 | */ 533 | VulcanMessage.prototype.toString = function () { 534 | var str = "type=" + this.type; 535 | str += ", scope=" + this.scope; 536 | str += ", appId=" + this.appId; 537 | str += ", appVersion=" + this.appVersion; 538 | str += ", data=" + this.xmlData(); 539 | return str; 540 | }; 541 | 542 | //--------------------------------------- Util -------------------------------- 543 | 544 | /** 545 | * Formats a string based on a template. 546 | * 547 | * @param src The format template. 548 | * 549 | * @return The formatted string 550 | */ 551 | String.format = function (src) { 552 | if (arguments.length === 0) { 553 | return null; 554 | } 555 | 556 | var args = Array.prototype.slice.call(arguments, 1); 557 | return src.replace(/\{(\d+)\}/g, function (m, i) { 558 | return args[i]; 559 | }); 560 | }; 561 | 562 | /** 563 | * Retrieves the content of an XML element. 564 | * 565 | * @param xmlStr The XML string. 566 | * @param key The name of the tag. 567 | * 568 | * @return The content of the tag, or the empty string 569 | * if such tag is not found or the tag has no content. 570 | */ 571 | function GetValueByKey(xmlStr, key) { 572 | if (window.DOMParser) { 573 | var parser = new window.DOMParser(); 574 | try { 575 | var xmlDoc = parser.parseFromString(xmlStr, "text/xml"); 576 | var node = xmlDoc.getElementsByTagName(key)[0]; 577 | if (node && node.childNodes[0]) { 578 | return node.childNodes[0].nodeValue; 579 | } 580 | } catch (e) { 581 | //log the error 582 | } 583 | } 584 | return ""; 585 | } 586 | 587 | /** 588 | * Reports whether required parameters are valid. 589 | * 590 | * @return True if all required parameters are valid, 591 | * false if any of the required parameters are invalid. 592 | */ 593 | function requiredParamsValid() { 594 | for (var i = 0; i < arguments.length; i++) { 595 | var argument = arguments[i]; 596 | if (argument === undefined || argument === null) { 597 | return false; 598 | } 599 | } 600 | return true; 601 | } 602 | 603 | /** 604 | * Reports whether a string has a given prefix. 605 | * 606 | * @param str The target string. 607 | * @param prefix The specific prefix string. 608 | * 609 | * @return True if the string has the prefix, false if not. 610 | */ 611 | function strStartsWith(str, prefix) { 612 | if (typeof str != "string") { 613 | return false; 614 | } 615 | return str.indexOf(prefix) === 0; 616 | } 617 | 618 | // Boilerplate Added Export 619 | export { VulcanMessage }; 620 | export default Vulcan; 621 | -------------------------------------------------------------------------------- /ae/src/ui/lib/utils/aeft.ts: -------------------------------------------------------------------------------- 1 | import { fs, path } from "../cep/node"; 2 | import { csi } from "./bolt"; 3 | 4 | const getLatestFile = (dir: string, suffix: string): string | null => { 5 | const getModified = (filePath: string) => 6 | fs.statSync(filePath).mtime.valueOf(); 7 | let latestFile: string | null = null; 8 | fs.readdirSync(dir) 9 | .filter((file) => file.includes(suffix)) 10 | .map((file) => { 11 | if ( 12 | latestFile === null || 13 | getModified(path.join(dir, file)) > 14 | getModified(path.join(dir, latestFile)) 15 | ) { 16 | latestFile = file; 17 | } 18 | }); 19 | return latestFile; 20 | }; 21 | 22 | export const getPrefsDir = (): string => { 23 | const appVersion = csi.getHostEnvironment().appVersion; 24 | const { platform, env } = window.cep_node.process; 25 | const mainDir = 26 | platform == "darwin" 27 | ? `${env.HOME}/Library/Preferences` 28 | : env.APPDATA || ""; 29 | const prefsDir = path.join( 30 | mainDir, 31 | "Adobe", 32 | "After Effects", 33 | parseFloat(appVersion).toFixed(1).toString() 34 | ); 35 | return prefsDir; 36 | }; 37 | 38 | export const getOutputModules = (): string[] => { 39 | const prefsDir = getPrefsDir(); 40 | const prefsSuffix = "indep-output.txt"; 41 | const outputPref = getLatestFile(prefsDir, prefsSuffix); 42 | if (outputPref) { 43 | const txt = fs.readFileSync(path.join(prefsDir, outputPref), { 44 | encoding: "utf-8", 45 | }); 46 | const matches = txt.match( 47 | /\"Output Module Spec Strings Name .* = \".*.\"/g 48 | ); 49 | if (matches) { 50 | let outputModules: string[] = []; 51 | matches.map((line) => { 52 | const str = line.split("=").pop()?.trim().replace(/"/g, ""); 53 | if (str && !str.includes("_HIDDEN X-Factor")) { 54 | outputModules.push(str); 55 | } 56 | }); 57 | return outputModules; 58 | } 59 | } 60 | return []; 61 | }; 62 | 63 | export const getRenderSettingsList = (): string[] => { 64 | const prefsDir = getPrefsDir(); 65 | const prefsSuffix = "indep-render.txt"; 66 | const renderPref = getLatestFile(prefsDir, prefsSuffix); 67 | if (renderPref) { 68 | const txt = fs.readFileSync(path.join(prefsDir, renderPref), { 69 | encoding: "utf-8", 70 | }); 71 | const lines = txt.match(/[^\r\n]+/g); 72 | if (lines) { 73 | const firstLine = lines.findIndex((line) => 74 | line.includes("Render Settings List") 75 | ); 76 | const lastLine = lines.findIndex((line) => 77 | line.includes("Still Frame RS Index") 78 | ); 79 | const settingBlock = lines 80 | .slice(firstLine, lastLine) 81 | .join("") 82 | .trim() 83 | .replace(/^.*\=/g, "") 84 | .replace(/\t/g, "") 85 | .replace(/\\/g, "") 86 | .replace(/\"\"/g, ""); 87 | let renderSettings: string[] = []; 88 | settingBlock.match(/\".*?\"/g)?.map((str) => { 89 | if (str && !str.includes("_HIDDEN X-Factor")) { 90 | renderSettings.push(str.replace(/\"/g, "")); 91 | } 92 | }); 93 | return renderSettings; 94 | } 95 | } 96 | return []; 97 | }; 98 | -------------------------------------------------------------------------------- /ae/src/ui/lib/utils/bolt.ts: -------------------------------------------------------------------------------- 1 | import CSInterface, { CSEvent } from "../cep/csinterface"; 2 | import Vulcan, { VulcanMessage } from "../cep/vulcan"; 3 | import { ns } from "../../../shared/shared"; 4 | import { fs } from "../cep/node"; 5 | 6 | export const csi = new CSInterface(); 7 | export const vulcan = new Vulcan(); 8 | 9 | // jsx utils 10 | 11 | /** 12 | * @function EvalES 13 | * Evaluates a string in ExtendScript scoped to the project's namespace 14 | * Optionally, pass true to the isGlobal param to avoid scoping 15 | * 16 | * @param script The script as a string to be evaluated 17 | * @param isGlobal Optional. Defaults to false, 18 | * 19 | * @return String Result. 20 | */ 21 | 22 | export const evalES = (script: string, isGlobal = false): Promise => { 23 | return new Promise(function (resolve, reject) { 24 | const pre = isGlobal 25 | ? "" 26 | : `var host = typeof $ !== 'undefined' ? $ : window; host["${ns}"].`; 27 | const fullString = pre + script; 28 | csi.evalScript( 29 | "try{" + fullString + "}catch(e){alert(e);}", 30 | (res: string) => { 31 | resolve(res); 32 | } 33 | ); 34 | }); 35 | }; 36 | 37 | import type { Scripts } from "@esTypes/index"; 38 | import type { EventTS } from "../../../shared/universals"; 39 | 40 | type ArgTypes = F extends (...args: infer A) => any 41 | ? A 42 | : never; 43 | type ReturnType = F extends (...args: infer A) => infer B 44 | ? B 45 | : never; 46 | 47 | /** 48 | * @description End-to-end type-safe ExtendScript evaluation with error handling 49 | * Call ExtendScript functions from CEP with type-safe parameters and return types. 50 | * Any ExtendScript errors are captured and logged to the CEP console for tracing 51 | * 52 | * @param functionName The name of the function to be evaluated. 53 | * @param args the list of arguments taken by the function. 54 | * 55 | * @return Promise resolving to function native return type. 56 | * 57 | * @example 58 | * // CEP 59 | * evalTS("myFunc", 60, 'test').then((res) => { 60 | * console.log(res.word); 61 | * }); 62 | * 63 | * // ExtendScript 64 | * export const myFunc = (num: number, word: string) => { 65 | * return { num, word }; 66 | * } 67 | * 68 | */ 69 | 70 | export const evalTS = < 71 | Key extends string & keyof Scripts, 72 | Func extends Function & Scripts[Key] 73 | >( 74 | functionName: Key, 75 | ...args: ArgTypes 76 | ): Promise> => { 77 | return new Promise(function (resolve, reject) { 78 | const formattedArgs = args 79 | .map((arg) => { 80 | console.log(JSON.stringify(arg)); 81 | return `${JSON.stringify(arg)}`; 82 | }) 83 | .join(","); 84 | csi.evalScript( 85 | `try{ 86 | var host = typeof $ !== 'undefined' ? $ : window; 87 | var res = host["${ns}"].${functionName}(${formattedArgs}); 88 | JSON.stringify(res); 89 | }catch(e){ 90 | e.fileName = new File(e.fileName).fsName; 91 | JSON.stringify(e); 92 | }`, 93 | (res: string) => { 94 | try { 95 | //@ts-ignore 96 | if (res === "undefined") return resolve(); 97 | const parsed = JSON.parse(res); 98 | if (parsed.name === "ReferenceError") { 99 | console.error("REFERENCE ERROR"); 100 | reject(parsed); 101 | } else { 102 | resolve(parsed); 103 | } 104 | } catch (error) { 105 | reject(res); 106 | } 107 | } 108 | ); 109 | }); 110 | }; 111 | 112 | export const evalFile = (file: string) => { 113 | return evalES( 114 | "typeof $ !== 'undefined' ? $.evalFile(\"" + 115 | file + 116 | '") : fl.runScript(FLfile.platformPathToURI("' + 117 | file + 118 | '"));', 119 | true 120 | ); 121 | }; 122 | 123 | /** 124 | * @function listenTS End-to-end Type-Safe ExtendScript to JavaScript Events 125 | * Uses the PlugPlug ExternalObject to trigger events in CEP panels 126 | * Function comes scoped to the panel's namespace to avoid conflicts 127 | * Simply declare your event name and value in the shared/universals.ts file 128 | * Listen for events with listenTS() in your CEP panel 129 | * Trigger those events with dispatchTS() ExtendScript 130 | * @param event The event name to listen for (defined in EventTS in shared/universals.ts) 131 | * @param callback The callback function to be executed when the event is triggered 132 | * @param isLocal Whether to scope the event to the panel's namespace. Defaults to true 133 | * 134 | * @example 135 | * 136 | * // 1. Declare Type in EventTS in shared/universals.ts 137 | * export type EventTS = { 138 | * 'myCustomEvent': { 139 | * name: string; 140 | * value: number; 141 | * } 142 | * // [... other events] 143 | * }; 144 | * 145 | * // 2. Listen in CEP 146 | * listenTS("myCustomEvent", (data) => { 147 | * console.log("name is", data.name); 148 | * console.log("value is", data.value); 149 | * }); 150 | * 151 | * // 3. Dispatch in ExtendScript 152 | * dispatchTS("myCustomEvent", { name: "name", value: 20 }); 153 | * 154 | */ 155 | export const listenTS = ( 156 | event: Key, 157 | callback: (data: EventTS[Key]) => void, 158 | isLocal = true 159 | ) => { 160 | const fullEvent = isLocal ? `${ns}.${event}` : event; 161 | const csi = new CSInterface(); 162 | // console.log(`listening to ${fullEvent}`); 163 | const thisCallback = (e: { data: EventTS[Key] }) => { 164 | callback(e.data); 165 | }; 166 | 167 | // remove any existing listeners 168 | csi.removeEventListener(fullEvent, thisCallback, null); 169 | // add the event listener 170 | csi.addEventListener(fullEvent, thisCallback); 171 | }; 172 | 173 | /** 174 | * @function dispatchTS Displatches an event within or between CEP panels with Type-Safety 175 | * See listenTS() in the CEP panel for more info 176 | * @param event The event name to listen for (defined in EventTS in shared/universals.ts) 177 | * @param callback The callback function to be executed when the event is triggered 178 | * @param scope The scope of the event. Defaults to "APPLICATION" 179 | * @param appId The application ID. Defaults to the current application 180 | * @param id The extension ID. Defaults to the current extension 181 | * @param isLocal Whether to scope the event to the panel's namespace. Defaults to true 182 | */ 183 | export const dispatchTS = ( 184 | event: Key, 185 | data: EventTS[Key], 186 | scope = "APPLICATION", 187 | appId = csi.getApplicationID() as string, 188 | id = csi.getExtensionID() as string, 189 | isLocal = true 190 | ) => { 191 | const fullEvent = isLocal ? `${ns}.${event}` : event; 192 | // console.log(`dispatching ${fullEvent}`); 193 | const csEvent = new CSEvent(fullEvent, scope, appId, id); 194 | csEvent.data = data; 195 | csi.dispatchEvent(csEvent); 196 | }; 197 | 198 | // js utils 199 | 200 | export const initBolt = (log = true) => { 201 | if (window.cep) { 202 | const extRoot = csi.getSystemPath("extension"); 203 | const jsxSrc = `${extRoot}/jsx/index.js`; 204 | const jsxBinSrc = `${extRoot}/jsx/index.jsxbin`; 205 | if (fs.existsSync(jsxSrc)) { 206 | if (log) console.log(jsxSrc); 207 | evalFile(jsxSrc); 208 | } else if (fs.existsSync(jsxBinSrc)) { 209 | if (log) console.log(jsxBinSrc); 210 | evalFile(jsxBinSrc); 211 | } 212 | } 213 | }; 214 | 215 | export const posix = (str: string) => str.replace(/\\/g, "/"); 216 | 217 | export const openLinkInBrowser = (url: string) => { 218 | if (window.cep) { 219 | csi.openURLInDefaultBrowser(url); 220 | } else { 221 | location.href = url; 222 | } 223 | }; 224 | 225 | export const getAppBackgroundColor = () => { 226 | const { green, blue, red } = JSON.parse( 227 | window.__adobe_cep__.getHostEnvironment() as string 228 | ).appSkinInfo.panelBackgroundColor.color; 229 | return { 230 | rgb: { 231 | r: red, 232 | g: green, 233 | b: blue, 234 | }, 235 | hex: `#${red.toString(16)}${green.toString(16)}${blue.toString(16)}`, 236 | }; 237 | }; 238 | 239 | export const subscribeBackgroundColor = (callback: (color: string) => void) => { 240 | const getColor = () => { 241 | const newColor = getAppBackgroundColor(); 242 | console.log("BG Color Updated: ", { rgb: newColor.rgb }); 243 | const { r, g, b } = newColor.rgb; 244 | return `rgb(${r}, ${g}, ${b})`; 245 | }; 246 | // get current color 247 | callback(getColor()); 248 | // listen for changes 249 | csi.addEventListener( 250 | "com.adobe.csxs.events.ThemeColorChanged", 251 | () => callback(getColor()), 252 | {} 253 | ); 254 | }; 255 | 256 | // vulcan 257 | 258 | declare type IVulcanMessageObject = { 259 | event: string; 260 | callbackID?: string; 261 | data?: string | null; 262 | payload?: object; 263 | }; 264 | 265 | export const vulcanSend = (id: string, msgObj: IVulcanMessageObject) => { 266 | const msg = new VulcanMessage(VulcanMessage.TYPE_PREFIX + id, null, null); 267 | const msgStr = JSON.stringify(msgObj); 268 | msg.setPayload(msgStr); 269 | vulcan.dispatchMessage(msg); 270 | }; 271 | 272 | export const vulcanListen = (id: string, callback: Function) => { 273 | vulcan.addMessageListener( 274 | VulcanMessage.TYPE_PREFIX + id, 275 | (res: any) => { 276 | var msgStr = vulcan.getPayload(res); 277 | const msgObj = JSON.parse(msgStr); 278 | callback(msgObj); 279 | }, 280 | null 281 | ); 282 | }; 283 | 284 | export const isAppRunning = (targetSpecifier: string) => { 285 | const { major, minor, micro } = csi.getCurrentApiVersion(); 286 | const version = parseFloat(`${major}.${minor}`); 287 | if (version >= 11.2) { 288 | return vulcan.isAppRunningEx(targetSpecifier.toUpperCase()); 289 | } else { 290 | return vulcan.isAppRunning(targetSpecifier); 291 | } 292 | }; 293 | 294 | interface IOpenDialogResult { 295 | data: string[]; 296 | } 297 | export const selectFolder = ( 298 | dir: string, 299 | msg: string, 300 | callback: (res: string) => void 301 | ) => { 302 | const result = ( 303 | window.cep.fs.showOpenDialogEx || window.cep.fs.showOpenDialog 304 | )(false, true, msg, dir) as IOpenDialogResult; 305 | if (result.data?.length > 0) { 306 | const folder = decodeURIComponent(result.data[0].replace("file://", "")); 307 | callback(folder); 308 | } 309 | }; 310 | 311 | export const selectFile = ( 312 | dir: string, 313 | msg: string, 314 | callback: (res: string) => void 315 | ) => { 316 | const result = ( 317 | window.cep.fs.showOpenDialogEx || window.cep.fs.showOpenDialog 318 | )(false, false, msg, dir) as IOpenDialogResult; 319 | if (result.data?.length > 0) { 320 | const folder = decodeURIComponent(result.data[0].replace("file://", "")); 321 | callback(folder); 322 | } 323 | }; 324 | 325 | /** 326 | * @function enableSpectrum fixes an issue with React Spectrum and PointerEvents on MacOS 327 | * Run once at the start of your app to fix this issue 328 | */ 329 | 330 | export const enableSpectrum = () => { 331 | if (window.PointerEvent) { 332 | //@ts-ignore 333 | delete window.PointerEvent; 334 | } 335 | }; 336 | -------------------------------------------------------------------------------- /ae/src/ui/lib/utils/cep.ts: -------------------------------------------------------------------------------- 1 | import { csi } from "./bolt"; 2 | 3 | /** 4 | * Register all possible keyboard shortcuts on Mac and Windows for you CEP Panel 5 | * Warning: Note that certain keys will not work per OS regardless of registration 6 | */ 7 | 8 | export const keyRegisterOverride = () => { 9 | //@ts-ignore 10 | const platform = navigator.platform.substring(0, 3); 11 | let maxKey = 0; 12 | if (platform === "Mac") maxKey = 126; // Mac Max Key Code 13 | else if (platform === "Win") maxKey = 222; // HTML Max Key Code 14 | let allKeys: { 15 | keyCode: number; 16 | ctrlKey: boolean; 17 | altKey: boolean; 18 | shiftKey: boolean; 19 | metaKey: boolean; 20 | }[] = []; 21 | for (let k = 0; k <= maxKey; k++) { 22 | for (let j = 0; j <= 15; j++) { 23 | const guide = (j >>> 0).toString(2).padStart(4, "0"); 24 | allKeys.push({ 25 | keyCode: k, 26 | ctrlKey: guide[0] === "1", 27 | altKey: guide[1] === "1", 28 | shiftKey: guide[2] === "1", 29 | metaKey: guide[3] === "1", 30 | }); 31 | } 32 | } 33 | const keyRes = csi.registerKeyEventsInterest(JSON.stringify(allKeys)); 34 | console.log("Key Events Registered Completed: " + keyRes); 35 | }; 36 | -------------------------------------------------------------------------------- /ae/src/ui/linting/eslintConfig.ts: -------------------------------------------------------------------------------- 1 | import Linter from "eslint4b-prebuilt"; 2 | import test from "./rules/no-ending-with-function-declaration"; 3 | 4 | export const SEVERITY = { 5 | OFF: 0, 6 | WARN: 1, 7 | ERROR: 2, 8 | } as const; 9 | 10 | export const eslintConfig: Linter.Config = { 11 | env: { es6: true }, 12 | rules: { 13 | // Custom rules 14 | "no-ending-with-function-declaration": SEVERITY.ERROR, 15 | // Builtin rules 16 | "array-callback-return": SEVERITY.WARN, 17 | "getter-return": SEVERITY.WARN, 18 | "new-parens": SEVERITY.WARN, 19 | indent: [SEVERITY.WARN, 4], 20 | quotes: SEVERITY.WARN, 21 | "no-array-constructor": SEVERITY.WARN, 22 | "no-caller": SEVERITY.ERROR, 23 | "no-cond-assign": [SEVERITY.WARN, "except-parens"], 24 | "no-const-assign": SEVERITY.ERROR, 25 | "no-control-regex": SEVERITY.WARN, 26 | "no-dupe-args": SEVERITY.WARN, 27 | "no-dupe-class-members": SEVERITY.WARN, 28 | "no-dupe-keys": SEVERITY.WARN, 29 | "no-duplicate-case": SEVERITY.WARN, 30 | "no-empty-character-class": SEVERITY.WARN, 31 | "no-empty-pattern": SEVERITY.WARN, 32 | "no-duplicate-imports": SEVERITY.WARN, 33 | "no-empty": [SEVERITY.WARN, { allowEmptyCatch: true }], 34 | "no-eval": SEVERITY.ERROR, 35 | "no-ex-assign": SEVERITY.WARN, 36 | "no-extend-native": SEVERITY.WARN, 37 | "no-extra-bind": SEVERITY.WARN, 38 | "no-extra-label": SEVERITY.WARN, 39 | "no-extra-boolean-cast": SEVERITY.WARN, 40 | "no-func-assign": SEVERITY.ERROR, 41 | "no-global-assign": SEVERITY.ERROR, 42 | "no-implied-eval": SEVERITY.WARN, 43 | "no-invalid-regexp": SEVERITY.WARN, 44 | "no-label-var": SEVERITY.WARN, 45 | "no-labels": [SEVERITY.WARN, { allowLoop: true, allowSwitch: false }], 46 | "no-lone-blocks": SEVERITY.WARN, 47 | "no-loop-func": SEVERITY.WARN, 48 | "no-mixed-operators": [ 49 | SEVERITY.WARN, 50 | { 51 | groups: [ 52 | ["&", "|", "^", "~", "<<", ">>", ">>>"], 53 | ["==", "!=", "===", "!==", ">", ">=", "<", "<="], 54 | ["&&", "||"], 55 | ["in", "instanceof"], 56 | ], 57 | allowSamePrecedence: false, 58 | }, 59 | ], 60 | "no-unsafe-negation": SEVERITY.WARN, 61 | "no-new-func": SEVERITY.WARN, 62 | "no-new-object": SEVERITY.WARN, 63 | "no-octal": SEVERITY.WARN, 64 | "no-redeclare": SEVERITY.ERROR, 65 | "no-script-url": SEVERITY.WARN, 66 | "no-self-assign": SEVERITY.WARN, 67 | "no-self-compare": SEVERITY.WARN, 68 | "no-sequences": SEVERITY.WARN, 69 | "no-shadow-restricted-names": SEVERITY.WARN, 70 | "no-sparse-arrays": SEVERITY.WARN, 71 | "no-template-curly-in-string": SEVERITY.WARN, 72 | "no-this-before-super": SEVERITY.WARN, 73 | "no-unreachable": SEVERITY.WARN, 74 | "no-unused-labels": SEVERITY.WARN, 75 | "no-unused-vars": [ 76 | SEVERITY.WARN, 77 | { 78 | args: "none", 79 | ignoreRestSiblings: true, 80 | }, 81 | ], 82 | "no-use-before-define": [ 83 | SEVERITY.WARN, 84 | { classes: false, functions: false, variables: false }, 85 | ], 86 | "no-useless-computed-key": SEVERITY.WARN, 87 | "no-useless-concat": SEVERITY.WARN, 88 | "no-useless-constructor": SEVERITY.WARN, 89 | "no-useless-escape": SEVERITY.WARN, 90 | "no-useless-rename": [ 91 | SEVERITY.WARN, 92 | { 93 | ignoreDestructuring: false, 94 | ignoreImport: false, 95 | ignoreExport: false, 96 | }, 97 | ], 98 | "require-yield": SEVERITY.WARN, 99 | "use-isnan": SEVERITY.WARN, 100 | "valid-typeof": SEVERITY.WARN, 101 | "arrow-body-style": SEVERITY.WARN, 102 | curly: SEVERITY.WARN, 103 | "dot-notation": SEVERITY.WARN, 104 | "no-confusing-arrow": SEVERITY.WARN, 105 | "no-extra-semi": SEVERITY.WARN, 106 | "prefer-const": SEVERITY.WARN, 107 | "spaced-comment": SEVERITY.WARN, 108 | }, 109 | }; 110 | -------------------------------------------------------------------------------- /ae/src/ui/linting/eslintErrorsToMonacoMarkers.ts: -------------------------------------------------------------------------------- 1 | import * as Monaco from "monaco-editor"; 2 | import Linter from "eslint4b-prebuilt"; 3 | import { SEVERITY } from "./eslintConfig"; 4 | 5 | export function eslintErrorsToMonacoMarkers( 6 | errors: Linter.LintMessage[], 7 | linter: Linter 8 | ): Monaco.editor.IMarkerData[] { 9 | const ruleDefines = linter.getRules(); 10 | const severityMap = { 11 | [SEVERITY.ERROR]: 8, 12 | [SEVERITY.WARN]: 4, 13 | [SEVERITY.OFF]: 0, 14 | } as const; 15 | 16 | const markers = errors.map((err) => { 17 | if (err.fatal) { 18 | return { 19 | startLineNumber: err.line, 20 | startColumn: err.column, 21 | message: err.message, 22 | severity: severityMap[err.severity], 23 | source: "eslint", 24 | }; 25 | } 26 | 27 | return { 28 | code: { 29 | value: err.ruleId ?? "", 30 | target: err.ruleId && ruleDefines.get(err.ruleId)?.meta?.docs?.url, 31 | }, 32 | startLineNumber: err.line, 33 | endLineNumber: err.endLine, 34 | startColumn: err.column, 35 | endColumn: err.endColumn, 36 | message: err.message, 37 | severity: severityMap[err.severity], 38 | source: "eslint", 39 | }; 40 | }); 41 | 42 | return markers; 43 | } 44 | -------------------------------------------------------------------------------- /ae/src/ui/linting/lint.ts: -------------------------------------------------------------------------------- 1 | import type * as Monaco from "monaco-editor"; 2 | import Linter from "eslint4b-prebuilt"; 3 | import { eslintConfig } from "./eslintConfig"; 4 | import { eslintErrorsToMonacoMarkers } from "./eslintErrorsToMonacoMarkers"; 5 | import noEndingWithFunctionDeclaration from "./rules/no-ending-with-function-declaration"; 6 | 7 | export function lintEditor( 8 | monaco: typeof Monaco, 9 | monacoInstance: Monaco.editor.IStandaloneCodeEditor 10 | ) { 11 | const model = monacoInstance.getModel(); 12 | if (!model) return; 13 | 14 | const value = monacoInstance.getValue(); 15 | const markers = getLintModelMarkers(value); 16 | if (!markers) return; 17 | monaco.editor.setModelMarkers(model, "eslint", markers); 18 | } 19 | 20 | function getLintModelMarkers(code: string) { 21 | const linter = new Linter(); 22 | linter.defineRule( 23 | "no-ending-with-function-declaration", 24 | noEndingWithFunctionDeclaration 25 | ); 26 | 27 | const errs = linter.verify(code, eslintConfig); 28 | const markers = eslintErrorsToMonacoMarkers(errs, linter); 29 | 30 | return markers; 31 | } 32 | -------------------------------------------------------------------------------- /ae/src/ui/linting/rules/no-ending-with-function-declaration.ts: -------------------------------------------------------------------------------- 1 | import type { Rule } from "eslint"; 2 | import { FunctionDeclaration, VariableDeclaration } from "estree"; 3 | 4 | type NodeType = (FunctionDeclaration | VariableDeclaration) & 5 | Rule.NodeParentExtension; 6 | const isLastNode = (node: NodeType) => 7 | node.parent.type === "Program" && 8 | node.parent.body[node.parent.body.length - 1].range === node.range; 9 | 10 | // https://eslint.org/docs/developer-guide/working-with-rules - working with custom rules 11 | const rule: Rule.RuleModule = { 12 | meta: { 13 | type: "problem", 14 | docs: { 15 | description: "Expressions can't end with a function declaration.", 16 | category: "Possible Errors", 17 | url: "", 18 | }, 19 | }, 20 | 21 | create(context) { 22 | return { 23 | FunctionDeclaration(node) { 24 | if (isLastNode(node)) { 25 | context.report({ 26 | message: "Expressions cannot end in a function declaration.", 27 | node, 28 | suggest: null, 29 | }); 30 | } 31 | }, 32 | }; 33 | }, 34 | }; 35 | 36 | export default rule; 37 | -------------------------------------------------------------------------------- /ae/src/ui/main/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Bolt CEP React 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ae/src/ui/main/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "../index.scss"; 4 | import Main from "./main"; 5 | import "../monaco/userWorker"; 6 | 7 | ReactDOM.render( 8 | 9 |
10 | , 11 | document.getElementById("root") 12 | ); 13 | -------------------------------------------------------------------------------- /ae/src/ui/main/main.scss: -------------------------------------------------------------------------------- 1 | html { 2 | --background: #1c2022; 3 | --border: #2d2d2d; 4 | 5 | --button-background: var(--background); 6 | --button-background-hover: #374140; 7 | } 8 | 9 | #monaco { 10 | width: 100%; 11 | height: calc(100vh - 30px); 12 | } 13 | 14 | /** 15 | Fix the text color for the variable 16 | renaming input 17 | */ 18 | 19 | .monaco-editor .rename-box .rename-input { 20 | color: white; 21 | outline: none; 22 | } 23 | 24 | .controls { 25 | border-top: 1px solid var(--border); 26 | background-color: var(--background); 27 | padding: 4px; 28 | font-size: 12px; 29 | color: white; 30 | display: flex; 31 | justify-content: space-between; 32 | } 33 | 34 | button { 35 | background: var(--button-background); 36 | border: 1px solid var(--border); 37 | border-radius: 2px; 38 | color: white; 39 | } 40 | 41 | button:hover { 42 | background: var(--button-background-hover); 43 | } 44 | -------------------------------------------------------------------------------- /ae/src/ui/main/main.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import "./main.scss"; 3 | import { useMonaco } from "../monaco/useMonaco"; 4 | import * as pkg from "../../../package.json"; 5 | import { evalTS, initBolt, openLinkInBrowser } from "../lib/utils/bolt"; 6 | 7 | const Main = () => { 8 | initBolt(); 9 | const editorRef = useRef(null); 10 | 11 | const { setValue, getValue, insertValue, disableErrors } = 12 | useMonaco(editorRef); 13 | 14 | const issueUrl = new URL( 15 | "https://github.com/motiondeveloper/editor/issues/new" 16 | ); 17 | 18 | issueUrl.searchParams.set("title", `[${pkg.version}] Issue Name`); 19 | issueUrl.searchParams.set("labels", "ae"); 20 | 21 | return ( 22 |
23 |
24 |
25 |
26 | 31 | 39 | 47 | 50 |
51 |
52 | 59 |
60 |
61 |
62 | ); 63 | }; 64 | 65 | export default Main; 66 | -------------------------------------------------------------------------------- /ae/src/ui/monaco/editorActions.tsx: -------------------------------------------------------------------------------- 1 | import * as monaco from "monaco-editor"; 2 | import { compressToEncodedURIComponent } from "lz-string"; 3 | import { evalTS } from "../lib/utils/bolt"; 4 | import Linter from "eslint4b-prebuilt"; 5 | import { eslintConfig } from "../linting/eslintConfig"; 6 | 7 | const saveToURL = { 8 | // An unique identifier of the contributed action. 9 | id: "save-to-url", 10 | 11 | // A label of the action that will be presented to the user. 12 | label: "Save to URL", 13 | 14 | // An optional array of keybindings for the action. 15 | keybindings: [ 16 | // chord 17 | monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd, monaco.KeyCode.KeyS), 18 | ], 19 | 20 | // A precondition for this action. 21 | precondition: undefined, 22 | 23 | // A rule to evaluate on top of the precondition in order to dispatch the keybindings. 24 | keybindingContext: undefined, 25 | 26 | contextMenuGroupId: "9_cutcopypaste", 27 | 28 | contextMenuOrder: 1.5, 29 | 30 | // Method that will be executed when the action is triggered. 31 | // @param editor The editor instance is passed in as a convinience 32 | run: async function (editor: monaco.editor.IStandaloneCodeEditor) { 33 | // Encode to URI friendly string 34 | const encoded = compressToEncodedURIComponent(editor.getValue()); 35 | 36 | // Copy the URL to the clipboard 37 | // TODO: this only works on https, won't work in CEP 38 | await navigator.clipboard.writeText( 39 | `editor.motiondeveloper.com/?state=${encoded}` 40 | ); 41 | }, 42 | }; 43 | 44 | const applyToProperty = { 45 | // An unique identifier of the contributed action. 46 | id: "apply-to-property", 47 | 48 | // A label of the action that will be presented to the user. 49 | label: "Apply Expression", 50 | 51 | // An optional array of keybindings for the action. 52 | keybindings: [ 53 | // TODO: find keys that work 54 | monaco.KeyMod.chord(monaco.KeyMod.Alt, monaco.KeyCode.KeyA), 55 | ], 56 | 57 | // A precondition for this action. 58 | precondition: undefined, 59 | 60 | // A rule to evaluate on top of the precondition in order to dispatch the keybindings. 61 | keybindingContext: undefined, 62 | 63 | contextMenuGroupId: "expression", 64 | 65 | contextMenuOrder: 1.5, 66 | 67 | // Method that will be executed when the action is triggered. 68 | // @param editor The editor instance is passed in as a convinience 69 | run: async function (editor: monaco.editor.IStandaloneCodeEditor) { 70 | evalTS(`setCurrentExpression`, editor.getValue()); 71 | }, 72 | }; 73 | 74 | const getValueFromProperty = { 75 | // An unique identifier of the contributed action. 76 | id: "get-value-from-property", 77 | 78 | // A label of the action that will be presented to the user. 79 | label: "Get Expression", 80 | 81 | // An optional array of keybindings for the action. 82 | keybindings: [ 83 | // TODO: find keys that work 84 | monaco.KeyMod.chord(monaco.KeyMod.Alt, monaco.KeyCode.KeyG), 85 | ], 86 | 87 | // A precondition for this action. 88 | precondition: undefined, 89 | 90 | // A rule to evaluate on top of the precondition in order to dispatch the keybindings. 91 | keybindingContext: undefined, 92 | 93 | contextMenuGroupId: "expression", 94 | 95 | contextMenuOrder: 1.5, 96 | 97 | // Method that will be executed when the action is triggered. 98 | // @param editor The editor instance is passed in as a convinience 99 | run: async function (editor: monaco.editor.IStandaloneCodeEditor) { 100 | editor.setValue(await evalTS("getCurrentExpression")); 101 | }, 102 | }; 103 | 104 | const fixLintErrors = { 105 | // An unique identifier of the contributed action. 106 | id: "fix-eslint-errors", 107 | 108 | // A label of the action that will be presented to the user. 109 | label: "Fix Lint Errors", 110 | 111 | // A precondition for this action. 112 | precondition: undefined, 113 | 114 | // A rule to evaluate on top of the precondition in order to dispatch the keybindings. 115 | keybindingContext: undefined, 116 | 117 | contextMenuGroupId: "1_modification", 118 | 119 | contextMenuOrder: 1.5, 120 | 121 | // Method that will be executed when the action is triggered. 122 | // @param editor The editor instance is passed in as a convinience 123 | run: async function (editor: monaco.editor.IStandaloneCodeEditor) { 124 | const linter = new Linter(); 125 | const errs = linter.verifyAndFix(editor.getValue(), eslintConfig); 126 | const model = editor.getModel(); 127 | if (!model) return; 128 | 129 | const lines = model.getLineCount(); 130 | 131 | editor.executeEdits("fix eslint errors", [ 132 | { 133 | text: errs.output, 134 | range: { 135 | startColumn: 1, 136 | startLineNumber: 1, 137 | endColumn: model.getLineMaxColumn(lines), 138 | endLineNumber: lines, 139 | }, 140 | forceMoveMarkers: false, 141 | }, 142 | ]); 143 | }, 144 | }; 145 | 146 | export const editorActions = [ 147 | saveToURL, 148 | applyToProperty, 149 | getValueFromProperty, 150 | fixLintErrors, 151 | ]; 152 | -------------------------------------------------------------------------------- /ae/src/ui/monaco/monacoConfig.tsx: -------------------------------------------------------------------------------- 1 | import * as monaco from "monaco-editor"; 2 | import defaultCode from "../../../../common/defaultCode"; 3 | 4 | export const monacoConfig: monaco.editor.IStandaloneEditorConstructionOptions = 5 | { 6 | value: defaultCode, 7 | language: "typescript", 8 | minimap: { enabled: false }, 9 | automaticLayout: true, 10 | scrollBeyondLastLine: false, 11 | formatOnPaste: true, 12 | insertSpaces: false, 13 | tabSize: 4, 14 | theme: "one-dark", 15 | lineNumbersMinChars: 3, 16 | }; 17 | -------------------------------------------------------------------------------- /ae/src/ui/monaco/typeDefsLibrary.tsx: -------------------------------------------------------------------------------- 1 | import expressionTypes from "expression-globals-typescript/dist/index.d.ts?raw"; 2 | import { 3 | Layer, 4 | NumericValue, 5 | Property, 6 | Vector, 7 | } from "expression-globals-typescript"; 8 | 9 | const thisLayer = new Layer(); 10 | const thisProperty = new Property([0, 0]); 11 | 12 | const layerProperties = [ 13 | ...Object.getOwnPropertyNames(thisLayer), 14 | ...Object.getOwnPropertyNames(Object.getPrototypeOf(thisLayer)), 15 | ]; 16 | 17 | const propertyProperties = [ 18 | ...Object.getOwnPropertyNames(thisProperty), 19 | ...Object.getOwnPropertyNames(Object.getPrototypeOf(thisProperty)), 20 | ]; 21 | 22 | const preprocessLayers = layerProperties 23 | .map((name) => `const ${name} = thisLayer['${name}']`) 24 | .join("\n"); 25 | 26 | const preprocessProperties = propertyProperties 27 | .map((name) => `const ${name} = thisProperty['${name}']`) 28 | .join("\n"); 29 | 30 | const libCode = expressionTypes.replace(/export /g, ""); 31 | 32 | export const typeDefsLib = (preprocess = true) => `${libCode} 33 | const thisComp = new Comp(); 34 | const thisProperty = new Property([0, 0]); 35 | const thisLayer = new Layer(); 36 | 37 | ${preprocess && preprocessLayers} 38 | ${preprocess && preprocessProperties}`; 39 | -------------------------------------------------------------------------------- /ae/src/ui/monaco/useMonaco.tsx: -------------------------------------------------------------------------------- 1 | import * as monaco from "monaco-editor"; 2 | import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"; 3 | import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker"; 4 | 5 | import { useEffect, useState } from "react"; 6 | 7 | import { lintEditor } from "../linting/lint"; 8 | import { editorActions } from "./editorActions"; 9 | import { monacoConfig } from "./monacoConfig"; 10 | 11 | function setupMonacoInstance(editorElement: HTMLDivElement) { 12 | const monacoInstance = monaco.editor.create(editorElement, monacoConfig); 13 | 14 | for (const action of editorActions) { 15 | monacoInstance.addAction(action); 16 | } 17 | 18 | lintEditor(monaco, monacoInstance); 19 | 20 | let timer: NodeJS.Timeout | null = null; 21 | monacoInstance?.getModel()?.onDidChangeContent(() => { 22 | if (timer) clearTimeout(timer); 23 | timer = setTimeout(() => { 24 | lintEditor(monaco, monacoInstance); 25 | }, 500); 26 | }); 27 | 28 | return monacoInstance; 29 | } 30 | 31 | export function useMonaco(editorRef: React.RefObject) { 32 | const [monacoInstance, setMonacoInstance] = 33 | useState(); 34 | 35 | useEffect(() => { 36 | if (!editorRef.current) return; 37 | // @ts-expect-error 38 | self.MonacoEnvironment = { 39 | getWorker(_: undefined, label: string) { 40 | if (label === "typescript" || label === "javascript") { 41 | return new tsWorker(); 42 | } 43 | 44 | return new editorWorker(); 45 | }, 46 | }; 47 | 48 | const monacoInstance = setupMonacoInstance(editorRef.current); 49 | 50 | setMonacoInstance(monacoInstance); 51 | return () => monacoInstance.dispose(); 52 | }, [editorRef]); 53 | 54 | return { 55 | setValue(value: string) { 56 | monacoInstance?.setValue(value); 57 | }, 58 | getValue() { 59 | return monacoInstance?.getValue(); 60 | }, 61 | insertValue(content: string) { 62 | if (!monacoInstance) return; 63 | const selection = monacoInstance.getSelection(); 64 | monacoInstance.executeEdits("pickwhip", [ 65 | { 66 | text: content, 67 | range: selection || { 68 | endColumn: 1, 69 | endLineNumber: 1, 70 | startColumn: 1, 71 | startLineNumber: 1, 72 | }, 73 | forceMoveMarkers: true, 74 | }, 75 | ]); 76 | }, 77 | disableErrors(shouldDisable: boolean) { 78 | const model = monacoInstance?.getModel(); 79 | if (!model) return; 80 | 81 | monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ 82 | noSemanticValidation: shouldDisable, 83 | noSyntaxValidation: shouldDisable, 84 | }); 85 | }, 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /ae/src/ui/monaco/userWorker.ts: -------------------------------------------------------------------------------- 1 | import * as monaco from "monaco-editor"; 2 | import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"; 3 | import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker"; 4 | import prettierBabel from "prettier/parser-babel"; 5 | import prettier from "prettier/standalone"; 6 | import theme from "../../../../common/onedarkpro-theme.json"; 7 | import { typeDefsLib } from "./typeDefsLibrary"; 8 | 9 | // @ts-ignore 10 | self.MonacoEnvironment = { 11 | getWorker(_: any, label: string) { 12 | if (label === "typescript" || label === "javascript") { 13 | return new tsWorker(); 14 | } 15 | return new editorWorker(); 16 | }, 17 | }; 18 | 19 | const ignoredCodes = [2365 /** Operator types */]; 20 | 21 | monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true); 22 | monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ 23 | diagnosticCodesToIgnore: ignoredCodes, 24 | }); 25 | 26 | monaco.editor.defineTheme( 27 | "one-dark", 28 | theme as monaco.editor.IStandaloneThemeData 29 | ); 30 | monaco.languages.registerDocumentFormattingEditProvider("typescript", { 31 | async provideDocumentFormattingEdits(model, options, token) { 32 | const plugins = [prettierBabel]; 33 | const text = prettier.format(model.getValue(), { 34 | parser: "babel", 35 | plugins, 36 | useTabs: true, 37 | printWidth: 80, 38 | }); 39 | 40 | return [ 41 | { 42 | range: model.getFullModelRange(), 43 | text, 44 | }, 45 | ]; 46 | }, 47 | }); 48 | 49 | monaco.languages.typescript.typescriptDefaults.setExtraLibs([ 50 | { content: typeDefsLib() }, 51 | { 52 | content: '', 53 | filePath: "lib.es5.d.ts", 54 | }, 55 | ]); 56 | -------------------------------------------------------------------------------- /ae/src/ui/types/eslint4b-prebuilt.d.ts: -------------------------------------------------------------------------------- 1 | declare module "eslint4b-prebuilt" { 2 | import eslint from "eslint"; 3 | export default eslint.Linter; 4 | } 5 | -------------------------------------------------------------------------------- /ae/src/ui/types/global.d.ts: -------------------------------------------------------------------------------- 1 | import { cep_node, cep, __adobe_cep__ } from "../lib/cep-types"; 2 | 3 | declare module "*.png"; 4 | declare module "*.gif"; 5 | declare module "*.jpg"; 6 | declare module "*.svg"; 7 | 8 | declare global { 9 | interface Window { 10 | cep_node: cep_node; 11 | cep: cep; 12 | __adobe_cep__: __adobe_cep__; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ae/src/ui/types/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ae/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "paths": { 19 | "@esTypes/*": ["./src/script"] 20 | } 21 | }, 22 | "include": ["./src"], 23 | "exclude": ["./src/script", "node_modules/@types/react/index.d.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /ae/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | import { cep, runAction } from "vite-cep-plugin"; 5 | import cepConfig from "./cep.config"; 6 | import path from "path"; 7 | import { extendscriptConfig } from "./vite.es.config"; 8 | 9 | const extensions = [".js", ".ts", ".tsx"]; 10 | 11 | const devDist = "dist"; 12 | const cepDist = "cep"; 13 | 14 | const src = path.resolve(__dirname, "src"); 15 | const root = path.resolve(src, "ui"); 16 | const outDir = path.resolve(__dirname, "dist", "cep"); 17 | 18 | const debugReact = process.env.DEBUG_REACT === "true"; 19 | const isProduction = process.env.NODE_ENV === "production"; 20 | const isMetaPackage = process.env.ZIP_PACKAGE === "true"; 21 | const isPackage = process.env.ZXP_PACKAGE === "true" || isMetaPackage; 22 | const isServe = process.env.SERVE_PANEL === "true"; 23 | const action = process.env.ACTION; 24 | 25 | let input = {}; 26 | cepConfig.panels.map((panel) => { 27 | input[panel.name] = path.resolve(root, panel.mainPath); 28 | }); 29 | 30 | const config = { 31 | cepConfig, 32 | isProduction, 33 | isPackage, 34 | isMetaPackage, 35 | isServe, 36 | debugReact, 37 | dir: `${__dirname}/${devDist}`, 38 | cepDist: cepDist, 39 | zxpDir: `${__dirname}/${devDist}/zxp`, 40 | zipDir: `${__dirname}/${devDist}/zip`, 41 | packages: cepConfig.installModules || [], 42 | }; 43 | 44 | if (action) { 45 | runAction(config, action); 46 | process.exit(); 47 | } 48 | 49 | // https://vitejs.dev/config/ 50 | export default defineConfig({ 51 | plugins: [react(), cep(config)], 52 | resolve: { 53 | alias: [{ find: "@esTypes", replacement: path.resolve(__dirname, "src") }], 54 | }, 55 | root, 56 | clearScreen: false, 57 | server: { 58 | port: cepConfig.port, 59 | }, 60 | preview: { 61 | port: cepConfig.servePort, 62 | }, 63 | 64 | build: { 65 | sourcemap: isPackage ? cepConfig.zxp.sourceMap : cepConfig.build?.sourceMap, 66 | watch: { 67 | include: "src/script/**", 68 | }, 69 | // commonjsOptions: { 70 | // transformMixedEsModules: true, 71 | // }, 72 | rollupOptions: { 73 | input, 74 | output: { 75 | manualChunks: {}, 76 | // esModule: false, 77 | preserveModules: false, 78 | format: "cjs", 79 | }, 80 | }, 81 | target: "chrome74", 82 | outDir, 83 | }, 84 | }); 85 | 86 | // rollup es3 build 87 | const outPathExtendscript = path.join("dist", "cep", "jsx", "index.js"); 88 | extendscriptConfig( 89 | `src/script/index.ts`, 90 | outPathExtendscript, 91 | cepConfig, 92 | extensions, 93 | isProduction, 94 | isPackage 95 | ); 96 | -------------------------------------------------------------------------------- /ae/vite.es.config.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import { rollup, watch, RollupOptions, OutputOptions } from "rollup"; 3 | import nodeResolve from "@rollup/plugin-node-resolve"; 4 | import babel from "@rollup/plugin-babel"; 5 | import { jsxInclude, jsxBin, jsxPonyfill } from "vite-cep-plugin"; 6 | import { CEP_Config } from "vite-cep-plugin"; 7 | import json from "@rollup/plugin-json"; 8 | import path from "path"; 9 | 10 | const GLOBAL_THIS = "thisObj"; 11 | 12 | export const extendscriptConfig = ( 13 | extendscriptEntry: string, 14 | outPath: string, 15 | cepConfig: CEP_Config, 16 | extensions: string[], 17 | isProduction: boolean, 18 | isPackage: boolean 19 | ) => { 20 | console.log(outPath); 21 | const config: RollupOptions = { 22 | input: extendscriptEntry, 23 | treeshake: true, 24 | output: { 25 | file: outPath, 26 | sourcemap: isPackage 27 | ? cepConfig.zxp.sourceMap 28 | : cepConfig.build?.sourceMap, 29 | }, 30 | plugins: [ 31 | json(), 32 | nodeResolve({ 33 | extensions, 34 | }), 35 | babel({ 36 | extensions, 37 | exclude: /node_modules/, 38 | babelrc: false, 39 | babelHelpers: "inline", 40 | presets: ["@babel/preset-env", "@babel/preset-typescript"], 41 | plugins: [ 42 | "@babel/plugin-syntax-dynamic-import", 43 | "@babel/plugin-proposal-class-properties", 44 | ], 45 | }), 46 | jsxPonyfill(), 47 | jsxInclude({ 48 | iife: true, 49 | globalThis: GLOBAL_THIS, 50 | }), 51 | jsxBin(isPackage ? cepConfig.zxp.jsxBin : cepConfig.build?.jsxBin), 52 | ], 53 | }; 54 | 55 | async function build() { 56 | const bundle = await rollup(config); 57 | await bundle.write(config.output as OutputOptions); 58 | await bundle.close(); 59 | } 60 | 61 | const triggerHMR = () => { 62 | // No built-in way to trigger Vite's HMR reload from outside the root folder 63 | // Workaround will read and save index.html file for each panel to triggger reload 64 | console.log("ExtendScript Change"); 65 | cepConfig.panels.map((panel) => { 66 | const tmpPath = path.join(process.cwd(), "src", "js", panel.mainPath); 67 | if (fs.existsSync(tmpPath)) { 68 | const txt = fs.readFileSync(tmpPath, { encoding: "utf-8" }); 69 | fs.writeFileSync(tmpPath, txt, { encoding: "utf-8" }); 70 | } 71 | }); 72 | }; 73 | 74 | const watchRollup = async () => { 75 | const watcher = watch(config); 76 | watcher.on("event", ({ result }: any) => { 77 | if (result) { 78 | triggerHMR(); 79 | result.close(); 80 | } 81 | }); 82 | watcher.close(); 83 | }; 84 | 85 | if (isProduction) { 86 | build(); 87 | } else { 88 | watchRollup(); 89 | } 90 | }; 91 | -------------------------------------------------------------------------------- /common/defaultCode.ts: -------------------------------------------------------------------------------- 1 | const defaultCode = ` 2 | // A monaco code editor for expressions 3 | // with docs and autocompletion 4 | 5 | // Hover over values to see the docs! 6 | const wiggled = thisComp.layer("layer name").transform.position.wiggle(1, 10); 7 | 8 | // Press Shift + Alt + F to format code with prettier 9 | // Press Cntrl/Cmd + S to save a shareable url to the clipboard 10 | `.trim(); 11 | 12 | export default defaultCode; 13 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | -------------------------------------------------------------------------------- /web/.nvmrc: -------------------------------------------------------------------------------- 1 | 16 -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Expressions Editor | Motion Developer 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "serve": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@monaco-editor/react": "^4.2.2", 12 | "expression-globals-typescript": "^3.2.6", 13 | "lz-string": "^1.4.4", 14 | "prettier": "^2.4.1", 15 | "react": "^17.0.0", 16 | "react-dom": "^17.0.0", 17 | "react-hot-toast": "^2.1.1" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^16.9.4", 21 | "@types/react": "^17.0.0", 22 | "@types/react-dom": "^17.0.0", 23 | "@vitejs/plugin-react-refresh": "^1.3.1", 24 | "typescript": "^4.3.2", 25 | "vite": "^2.5.4" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /web/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Editor from "@monaco-editor/react"; 3 | import defaultCode from "../../common/defaultCode"; 4 | import expressionTypes from "expression-globals-typescript/dist/index.d.ts?raw"; 5 | import theme from "../../common/onedarkpro-theme.json"; 6 | import { 7 | compressToEncodedURIComponent, 8 | decompressFromEncodedURIComponent, 9 | } from "lz-string"; 10 | import toast, { Toaster } from "react-hot-toast"; 11 | import prettier from "prettier/esm/standalone"; 12 | import prettierBabel from "prettier/esm/parser-babel"; 13 | 14 | function App() { 15 | const libCode = expressionTypes.replace(/export /g, ""); 16 | 17 | function loadContentFromUrl() { 18 | const params = new URLSearchParams(window.location.search); 19 | const encoded = params.get("state"); 20 | 21 | if (encoded == null) { 22 | return null; 23 | } 24 | 25 | const decoded = decompressFromEncodedURIComponent(encoded); 26 | if (decoded == null) { 27 | throw new Error("failed decompression"); 28 | } 29 | return decoded; 30 | } 31 | 32 | const [value, setValue] = React.useState(defaultCode); 33 | React.useEffect(() => { 34 | const valueFromUrl = loadContentFromUrl(); 35 | if (valueFromUrl) { 36 | setValue(valueFromUrl); 37 | } 38 | }, []); 39 | 40 | function handleEditorWillMount(monaco) { 41 | // Compiler options 42 | monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ 43 | allowNonTsExtensions: true, 44 | }); 45 | 46 | // Adding type definitions 47 | monaco.languages.typescript.javascriptDefaults.addExtraLib( 48 | `${libCode} 49 | const thisComp = new Comp(); 50 | const thisProperty = new Property<>(); 51 | const thisLayer = new Layer();` 52 | ); 53 | 54 | // Register the custom theme 55 | monaco.editor.defineTheme("one-dark", theme); 56 | // Register prettier as the formatter 57 | monaco.languages.registerDocumentFormattingEditProvider("javascript", { 58 | async provideDocumentFormattingEdits(model, options, token) { 59 | const plugins = [prettierBabel]; 60 | const text = prettier.format(model.getValue(), { 61 | parser: "babel", 62 | plugins, 63 | useTabs: true, 64 | }); 65 | 66 | return [ 67 | { 68 | range: model.getFullModelRange(), 69 | text, 70 | }, 71 | ]; 72 | }, 73 | }); 74 | } 75 | 76 | function handleEditorDidMount(editor, monaco) { 77 | // here is another way to get monaco instance 78 | // you can also store it in `useRef` for further usage 79 | editor.addAction({ 80 | // An unique identifier of the contributed action. 81 | id: "save-to-url", 82 | 83 | // A label of the action that will be presented to the user. 84 | label: "Save to URL", 85 | 86 | // An optional array of keybindings for the action. 87 | keybindings: [ 88 | // chord 89 | monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S), 90 | ], 91 | 92 | // A precondition for this action. 93 | precondition: null, 94 | 95 | // A rule to evaluate on top of the precondition in order to dispatch the keybindings. 96 | keybindingContext: null, 97 | 98 | contextMenuGroupId: "navigation", 99 | 100 | contextMenuOrder: 1.5, 101 | 102 | // Method that will be executed when the action is triggered. 103 | // @param editor The editor instance is passed in as a convinience 104 | run: async function (editor) { 105 | // Encode to URI friendly string 106 | const encoded = compressToEncodedURIComponent(editor.getValue()); 107 | // Replace the current url with a state parameter 108 | window.history.replaceState(null, document.title, `?state=${encoded}`); 109 | // Copy the URL to the clipboard 110 | await navigator.clipboard.writeText(document.location.href); 111 | toast.success("Saved to URL and copied to clipboard!", { 112 | style: { 113 | borderRadius: "16px", 114 | color: "#FFFFFF", 115 | background: "#282C35", 116 | }, 117 | }); 118 | return null; 119 | }, 120 | }); 121 | } 122 | return ( 123 |
124 | 125 | 142 |
143 | ); 144 | } 145 | 146 | export default App; 147 | -------------------------------------------------------------------------------- /web/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /web/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './index.css' 4 | import App from './App' 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ) 12 | -------------------------------------------------------------------------------- /web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": true, 7 | "skipLibCheck": false, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react" 18 | }, 19 | "include": ["./src"] 20 | } 21 | -------------------------------------------------------------------------------- /web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import reactRefresh from '@vitejs/plugin-react-refresh' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [reactRefresh()] 7 | }) 8 | --------------------------------------------------------------------------------