├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── examples └── simple │ ├── .debug │ ├── CSXS │ └── manifest.xml │ ├── es │ └── hello-world.es │ ├── extension.html │ ├── gulpfile.js │ ├── index.html │ ├── index.js │ └── webpack.config.js ├── index.js ├── lib ├── CSInterface.js └── json.es ├── package.json └── plugin.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"], 3 | "plugins": [], 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | examples/*/build 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Michael Delaney 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # extend-script-loader 2 | 3 | This package allows for easy execution of ExtendScript (ES) files directly from a Adobe Common Extensibility Platform (CEP) panel. 4 | 5 | ## Why 6 | 7 | The process for setting up bi-directional communication between CEP and ES is a bit tedious to work with. This improves that process by allowing you to simply import your ES code and run it directly from the presentation layer. We also get free hot reloading on ES files when used with Hot Module Reloading (HMR). 8 | 9 | ## Installation 10 | 11 | ```bash 12 | npm install --save-dev extend-script-loader 13 | ``` 14 | 15 | ## Usage 16 | 17 | __Note:__ Examples use ES6 syntax on the CEP side. Use babel or similar to transpile. 18 | 19 | You'll need to add extend-script-loader to the list of loaders within your webpack configuration like so: 20 | 21 | ```javascript 22 | module: { 23 | loaders: [ 24 | { 25 | test: /\.es?$/, // js or jsx will also work if preferred. 26 | exclude: /(node_modules|bower_components)/, 27 | loader: 'extend-script', // 'extend-script-loader' is also a legal name to reference 28 | } 29 | ] 30 | } 31 | ``` 32 | 33 | Make sure CSInterface is loaded in the CEP panel. 34 | 35 | ```html 36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | Then write your ES inside of an Immediately-Invoked Function Expression (IIFE): 44 | 45 | ```javascript 46 | // hello-world.es 47 | (function() { 48 | writeLn('Hello world!'); 49 | })(); 50 | ``` 51 | 52 | Lastly, import and run the script inside your CEP panel: 53 | 54 | ```javascript 55 | // app.js 56 | import helloWorld from './hello-world.es' 57 | 58 | helloWorld(); 59 | ``` 60 | 61 | If run with After Effects as the target, you'll see ````Hello world!```` inside of the Info panel. 62 | 63 | 64 | ## Advanced Usage 65 | 66 | It's also possible to send and receive data to scripts. 67 | 68 | ### Receiving data from CEP 69 | 70 | Return a function inside the script that will accept parameters passed from CEP: 71 | 72 | ```javascript 73 | // send-number.es 74 | (function() { 75 | return function(number) { 76 | writeLn('Number from CEP: ' + number); 77 | }; 78 | })(); 79 | ``` 80 | 81 | ```javascript 82 | // app.js 83 | import sendNumber from './send-number.es' 84 | 85 | sendNumber(Math.random() * 100); 86 | ``` 87 | 88 | ### Receiving data from ES 89 | 90 | Return a value inside the script that will be passed to CEP: 91 | 92 | ```javascript 93 | // receive-number.es 94 | (function() { 95 | return function() { 96 | return Math.random() * 100 97 | }; 98 | })(); 99 | ``` 100 | 101 | ```javascript 102 | // app.js 103 | import receiveNumber from './receive-number.es' 104 | 105 | receiveNumber((err, result) => { 106 | console.log('Number from ES: ' + result); 107 | }); 108 | ``` 109 | 110 | __Note:__ You can return any JSON parseable data (including objects and arrays). 111 | 112 | ```javascript 113 | // send-object.es 114 | (function() { 115 | return function() { 116 | return {foo: 'bar'} 117 | }; 118 | })(); 119 | ``` 120 | 121 | ```javascript 122 | // app.js 123 | import sendObj from './send-object.es' 124 | 125 | sendObj((err, result) => { 126 | console.log('Object from ES: ', result); 127 | }); 128 | ``` 129 | 130 | ### Passing and receiving data inside CEP. 131 | 132 | You can pass as many parameters as desired to the script. The callback will always be added as the last parameter. 133 | 134 | ```javascript 135 | // app.js 136 | import scriptWithManyParameters from './my-script.es' 137 | 138 | scriptWithManyParameters('foo', 'bar', (err, result) => { 139 | // this is still called no matter how many parameters are passed to scriptWithManyParameters 140 | }); 141 | ``` 142 | 143 | ## Exceptions 144 | 145 | Currently, when any exception is thrown inside of an ES file it is caught and the error object is passed back to the CEP invocator's callback and also logged in the CEP console. This is because ExtendScript Toolkit is too slow and painful to work with and I've found it faster to just check the error's message and line number and then fix it in my text editor of choice. A configuration/query parameter to "unwrap" the try/catch to disable this could be added later if needed. 146 | 147 | ```javascript 148 | // throw-exception.es 149 | (function() { 150 | throw Error('MyError: an error happened here.'); 151 | })(); 152 | ``` 153 | 154 | ```javascript 155 | // app.js 156 | import throwException from './throw-exception.es' 157 | 158 | throwException((err, result) => { 159 | if (err) { 160 | console.log(err.message); // MyError: an error happened here. 161 | console.log(err.line); // 2 162 | console.log(err.source); /* the entire script's source. this might be useful for some advanced 163 | CEP error displaying in the future. 164 | */ 165 | } 166 | }); 167 | ``` 168 | 169 | ## Contributing 170 | 171 | 1. Fork it! 172 | 2. Create your feature branch: `git checkout -b my-new-feature` 173 | 3. Commit your changes: `git commit -am 'Add some feature'` 174 | 4. Push to the branch: `git push origin my-new-feature` 175 | 5. Submit a pull request :D 176 | 177 | ## Todos 178 | 179 | * Auto include CSInterface.js in CEP panel. 180 | * Ability to import multiple functions from ES script: 181 | 182 | ```javascript 183 | // app.js 184 | import { functionA, functionB } from './multiple-functions.es' 185 | ``` 186 | 187 | ## History 188 | 189 | TODO: Write history 190 | 191 | ## License 192 | 193 | The MIT License (MIT) 194 | -------------------------------------------------------------------------------- /examples/simple/.debug: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/simple/CSXS/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ./extension.html 22 | 23 | --allow-file-access-from-files 24 | --allow-file-access 25 | --enable-nodejs 26 | --mixed-context 27 | 28 | 29 | 30 | true 31 | 32 | 33 | Panel 34 | Extend Script Loader Simple 35 | 36 | 37 | 400 38 | 400 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/simple/es/hello-world.es: -------------------------------------------------------------------------------- 1 | (function() { 2 | return function(rand) { 3 | writeLn('Hello world! ' + rand); 4 | } 5 | })(); 6 | -------------------------------------------------------------------------------- /examples/simple/extension.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/simple/gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp') 2 | const gutil = require('gulp-util') 3 | const fs = require('fs') 4 | const path = require('path') 5 | const del = require('del') 6 | const webpack = require('webpack') 7 | const WebpackDevServer = require('webpack-dev-server') 8 | const exec = require('child_process').exec 9 | 10 | const CEP_EXTENSIONS_PATH = path.join(process.env.HOME, 'Library/Application\ Support/Adobe/CEP/extensions') 11 | 12 | gulp.task('build:copy', () => { 13 | return gulp.src(['CSXS/*', '.debug', 'index.html', 'extension.html'], { base: '.' }) 14 | .pipe(gulp.dest('build')) 15 | }) 16 | 17 | gulp.task('build:webpack', (done) => { 18 | webpack(require('./webpack.config.js'), (err, stats) => { 19 | if(err) throw new gutil.PluginError('webpack', err); 20 | gutil.log('[webpack]', stats.toString()) 21 | done() 22 | }) 23 | }) 24 | 25 | gulp.task('build:server', (done) => { 26 | new WebpackDevServer(webpack(require('./webpack.config.js')), { 27 | contentBase: path.join(__dirname, 'build'), 28 | publicPath: '/', 29 | hot: true, 30 | }).listen(3000, 'localhost', (err) => { 31 | if (err) throw new debug.PluginError('webpack-dev-server', err) 32 | gutil.log('[webpack-dev-server]', `http://localhost:${3000}`) 33 | done() 34 | }) 35 | }) 36 | 37 | gulp.task('dev:link', (done) => { 38 | const target = path.join(CEP_EXTENSIONS_PATH, 'com.extend-script-loader.simple') 39 | del.sync(target, { force: true }) 40 | fs.symlinkSync(path.join(__dirname, 'build'), target) 41 | done() 42 | }) 43 | 44 | gulp.task('dev:debug-enable', (done) => { 45 | exec(` 46 | defaults write com.adobe.CSXS.6 PlayerDebugMode 1; 47 | defaults write com.adobe.CSXS.5 PlayerDebugMode 1; 48 | defaults write com.adobe.CSXS.4 PlayerDebugMode 1; 49 | `, done) 50 | }) 51 | 52 | gulp.task('dev:debug-disable', (done) => { 53 | exec(` 54 | defaults delete com.adobe.CSXS.6 PlayerDebugMode; 55 | defaults delete com.adobe.CSXS.5 PlayerDebugMode; 56 | defaults delete com.adobe.CSXS.4 PlayerDebugMode; 57 | `, done) 58 | }) 59 | 60 | gulp.task('default', gulp.series(gulp.parallel('dev:debug-enable', 'build:copy', 'build:server'), 'dev:link')) 61 | -------------------------------------------------------------------------------- /examples/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Extend Script Loader Simple 5 | 6 | 7 | 8 | 9 |

Hello World

10 | 11 | -------------------------------------------------------------------------------- /examples/simple/index.js: -------------------------------------------------------------------------------- 1 | var helloWorld = require("./es/hello-world.es") 2 | 3 | helloWorld(Math.random()) 4 | 5 | if (module.hot) { 6 | module.hot.accept() 7 | } 8 | -------------------------------------------------------------------------------- /examples/simple/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | const ExtendScriptPlugin = require('../../plugin.js') 4 | 5 | module.exports = { 6 | devtool: 'eval', 7 | debug: true, 8 | entry: [ 9 | 'webpack-dev-server/client?http://localhost:3000', 10 | 'webpack/hot/only-dev-server', 11 | path.join(__dirname, 'index.js'), 12 | ], 13 | output: { 14 | path: path.join(__dirname, 'build'), 15 | filename: 'bundle.js', 16 | publicPath: '/', 17 | }, 18 | module: { 19 | loaders: [ 20 | { 21 | test: /\.es?$/, 22 | exclude: /(node_modules|bower_components)/, 23 | loader: path.join(__dirname, '../../index.js'), // replace with extend-script or extend-script-loader outside of this package 24 | }, 25 | ], 26 | }, 27 | 28 | plugins: [ 29 | new webpack.HotModuleReplacementPlugin(), 30 | new webpack.NoErrorsPlugin(), 31 | new ExtendScriptPlugin(), 32 | ], 33 | } 34 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var loaderUtils = require('loader-utils'); 2 | 3 | module.exports = function(content) { 4 | this.cacheable && this.cacheable(); 5 | var query = loaderUtils.parseQuery(this.query); 6 | var scriptString = content.toString().replace(/\n$/, ''); 7 | var scriptEscaped = escape(scriptString); 8 | 9 | var exportedFunction = 10 | `module.exports = function() { 11 | var args = Array.prototype.slice.call(arguments); 12 | 13 | var callback; 14 | if (typeof args[args.length - 1] === 'function') { 15 | callback = args[args.length - 1]; 16 | } 17 | 18 | if (args.length > 1) args.splice(-1,1); // remove callback 19 | 20 | var argsStringified = JSON.stringify(args); 21 | 22 | var cs; 23 | if (window.CSInterface) { 24 | cs = new window.CSInterface(); 25 | } else if (window.parent.CSInterface) { 26 | cs = new window.parent.CSInterface() 27 | } else { 28 | throw Error("[extend-script-loader]: CSInterface not found. Are you sure it's included?") 29 | } 30 | 31 | cs.evalScript(\`(function() { 32 | try { 33 | var result = eval(unescape("${scriptEscaped}")); 34 | if (typeof result === 'function') result = result.apply(this, \${argsStringified}); 35 | result = JSON.stringify({result: result}); 36 | return result; 37 | } catch (err) { 38 | return JSON.stringify({error: err}); 39 | }; 40 | })()\`, function(result) { 41 | result = JSON.parse(result); 42 | 43 | if (result.error) { 44 | var error = result.error; 45 | if (callback) callback(error); 46 | var errorMessage = error.name + " " + error.fileName + ":" + error.line + " " + error.message; 47 | console.error(errorMessage); 48 | return; 49 | } 50 | 51 | if (callback) callback(undefined, result.result); 52 | }); 53 | }`; 54 | 55 | return exportedFunction; 56 | } 57 | module.exports.raw = true; 58 | -------------------------------------------------------------------------------- /lib/CSInterface.js: -------------------------------------------------------------------------------- 1 | /* 2 | ADOBE SYSTEMS INCORPORATED 3 | Copyright 2013 Adobe Systems Incorporated. All Rights Reserved. 4 | 5 | NOTICE: Adobe permits you to use, modify, and distribute this file in 6 | accordance with the terms of the Adobe license agreement accompanying it. 7 | If you have received this file from a source other than Adobe, then your 8 | use, modification, or distribution of it requires the prior written 9 | permission of Adobe. 10 | */ 11 | 12 | 13 | /** 14 | * Stores constants for the window types supported by the CSXS infrastructure. 15 | */ 16 | function CSXSWindowType() 17 | { 18 | }; 19 | 20 | /** Constant for the CSXS window type Panel. */ 21 | CSXSWindowType._PANEL = "Panel"; 22 | 23 | /** Constant for the CSXS window type Modeless. */ 24 | CSXSWindowType._MODELESS = "Modeless"; 25 | 26 | /** Constant for the CSXS window type ModalDialog. */ 27 | CSXSWindowType._MODAL_DIALOG = "ModalDialog"; 28 | 29 | /** EvalScript error message */ 30 | EvalScript_ErrMessage = "EvalScript error."; 31 | 32 | /** 33 | * @class Version 34 | * Defines a version number with major, minor, micro, and special 35 | * components. The major, minor and micro values are numeric; the special 36 | * value can be any string. 37 | * 38 | * @param major The major version component, a positive integer up to nine digits long. 39 | * @param minor The minor version component, a positive integer up to nine digits long. 40 | * @param micro The micro version component, a positive integer up to nine digits long. 41 | * @param special The special version component, an arbitrary string. 42 | * 43 | * @return A new \c Version object. 44 | */ 45 | function Version(major, minor, micro, special) 46 | { 47 | this.major = major; 48 | this.minor = minor; 49 | this.micro = micro; 50 | this.special = special; 51 | }; 52 | 53 | /** 54 | * The maximum value allowed for a numeric version component. 55 | * This reflects the maximum value allowed in PlugPlug and the manifest schema. 56 | */ 57 | Version.MAX_NUM = 999999999; 58 | 59 | /** 60 | * @class VersionBound 61 | * Defines a boundary for a version range, which associates a \c Version object 62 | * with a flag for whether it is an inclusive or exclusive boundary. 63 | * 64 | * @param version The \c #Version object. 65 | * @param inclusive True if this boundary is inclusive, false if it is exclusive. 66 | * 67 | * @return A new \c VersionBound object. 68 | */ 69 | function VersionBound(version, inclusive) 70 | { 71 | this.version = version; 72 | this.inclusive = inclusive; 73 | }; 74 | 75 | /** 76 | * @class VersionRange 77 | * Defines a range of versions using a lower boundary and optional upper boundary. 78 | * 79 | * @param lowerBound The \c #VersionBound object. 80 | * @param upperBound The \c #VersionBound object, or null for a range with no upper boundary. 81 | * 82 | * @return A new \c VersionRange object. 83 | */ 84 | function VersionRange(lowerBound, upperBound) 85 | { 86 | this.lowerBound = lowerBound; 87 | this.upperBound = upperBound; 88 | }; 89 | 90 | /** 91 | * @class Runtime 92 | * Represents a runtime related to the CEP infrastructure. 93 | * Extensions can declare dependencies on particular 94 | * CEP runtime versions in the extension manifest. 95 | * 96 | * @param name The runtime name. 97 | * @param version A \c #VersionRange object that defines a range of valid versions. 98 | * 99 | * @return A new \c Runtime object. 100 | */ 101 | function Runtime(name, versionRange) 102 | { 103 | this.name = name; 104 | this.versionRange = versionRange; 105 | }; 106 | 107 | /** 108 | * @class Extension 109 | * Encapsulates a CEP-based extension to an Adobe application. 110 | * 111 | * @param id The unique identifier of this extension. 112 | * @param name The localizable display name of this extension. 113 | * @param mainPath The path of the "index.html" file. 114 | * @param basePath The base path of this extension. 115 | * @param windowType The window type of the main window of this extension. 116 | Valid values are defined by \c #CSXSWindowType. 117 | * @param width The default width in pixels of the main window of this extension. 118 | * @param height The default height in pixels of the main window of this extension. 119 | * @param minWidth The minimum width in pixels of the main window of this extension. 120 | * @param minHeight The minimum height in pixels of the main window of this extension. 121 | * @param maxWidth The maximum width in pixels of the main window of this extension. 122 | * @param maxHeight The maximum height in pixels of the main window of this extension. 123 | * @param defaultExtensionDataXml The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. 124 | * @param specialExtensionDataXml The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. 125 | * @param requiredRuntimeList An array of \c Runtime objects for runtimes required by this extension. 126 | * @param isAutoVisible True if this extension is visible on loading. 127 | * @param isPluginExtension True if this extension has been deployed in the Plugins folder of the host application. 128 | * 129 | * @return A new \c Extension object. 130 | */ 131 | function Extension(id, name, mainPath, basePath, windowType, width, height, minWidth, minHeight, maxWidth, maxHeight, 132 | defaultExtensionDataXml, specialExtensionDataXml, requiredRuntimeList, isAutoVisible, isPluginExtension) 133 | { 134 | this.id = id; 135 | this.name = name; 136 | this.mainPath = mainPath; 137 | this.basePath = basePath; 138 | this.windowType = windowType; 139 | this.width = width; 140 | this.height = height; 141 | this.minWidth = minWidth; 142 | this.minHeight = minHeight; 143 | this.maxWidth = maxWidth; 144 | this.maxHeight = maxHeight; 145 | this.defaultExtensionDataXml = defaultExtensionDataXml; 146 | this.specialExtensionDataXml = specialExtensionDataXml; 147 | this.requiredRuntimeList = requiredRuntimeList; 148 | this.isAutoVisible = isAutoVisible; 149 | this.isPluginExtension = isPluginExtension; 150 | }; 151 | 152 | /** 153 | * @class CSEvent 154 | * A standard JavaScript event, the base class for CEP events. 155 | * 156 | * @param type The name of the event type. 157 | * @param scope The scope of event, can be "GLOBAL" or "APPLICATION". 158 | * @param appId The unique identifier of the application that generated the event. 159 | * @param extensionId The unique identifier of the extension that generated the event. 160 | * 161 | * @return A new \c CSEvent object 162 | */ 163 | function CSEvent(type, scope, appId, extensionId) 164 | { 165 | this.type = type; 166 | this.scope = scope; 167 | this.appId = appId; 168 | this.extensionId = extensionId; 169 | }; 170 | 171 | /** Event-specific data. */ 172 | CSEvent.prototype.data = ""; 173 | 174 | /** 175 | * @class SystemPath 176 | * Stores operating-system-specific location constants for use in the 177 | * \c #CSInterface.getSystemPath() method. 178 | * @return A new \c SystemPath object. 179 | */ 180 | function SystemPath() 181 | { 182 | }; 183 | 184 | /** The path to user data. */ 185 | SystemPath.USER_DATA = "userData"; 186 | 187 | /** The path to common files for Adobe applications. */ 188 | SystemPath.COMMON_FILES = "commonFiles"; 189 | 190 | /** The path to the user's default document folder. */ 191 | SystemPath.MY_DOCUMENTS = "myDocuments"; 192 | 193 | /** @deprecated. Use \c #SystemPath.Extension. */ 194 | SystemPath.APPLICATION = "application"; 195 | 196 | /** The path to current extension. */ 197 | SystemPath.EXTENSION = "extension"; 198 | 199 | /** The path to hosting application's executable. */ 200 | SystemPath.HOST_APPLICATION = "hostApplication"; 201 | 202 | /** 203 | * @class ColorType 204 | * Stores color-type constants. 205 | */ 206 | function ColorType() 207 | { 208 | }; 209 | 210 | /** RGB color type. */ 211 | ColorType.RGB = "rgb"; 212 | 213 | /** Gradient color type. */ 214 | ColorType.GRADIENT = "gradient"; 215 | 216 | /** Null color type. */ 217 | ColorType.NONE = "none"; 218 | 219 | /** 220 | * @class RGBColor 221 | * Stores an RGB color with red, green, blue, and alpha values. 222 | * All values are in the range [0.0 to 255.0]. Invalid numeric values are 223 | * converted to numbers within this range. 224 | * 225 | * @param red The red value, in the range [0.0 to 255.0]. 226 | * @param green The green value, in the range [0.0 to 255.0]. 227 | * @param blue The blue value, in the range [0.0 to 255.0]. 228 | * @param alpha The alpha (transparency) value, in the range [0.0 to 255.0]. 229 | * The default, 255.0, means that the color is fully opaque. 230 | * 231 | * @return A new RGBColor object. 232 | */ 233 | function RGBColor(red, green, blue, alpha) 234 | { 235 | this.red = red; 236 | this.green = green; 237 | this.blue = blue; 238 | this.alpha = alpha; 239 | }; 240 | 241 | /** 242 | * @class Direction 243 | * A point value in which the y component is 0 and the x component 244 | * is positive or negative for a right or left direction, 245 | * or the x component is 0 and the y component is positive or negative for 246 | * an up or down direction. 247 | * 248 | * @param x The horizontal component of the point. 249 | * @param y The vertical component of the point. 250 | * 251 | * @return A new \c Direction object. 252 | */ 253 | function Direction(x, y) 254 | { 255 | this.x = x; 256 | this.y = y; 257 | }; 258 | 259 | /** 260 | * @class GradientStop 261 | * Stores gradient stop information. 262 | * 263 | * @param offset The offset of the gradient stop, in the range [0.0 to 1.0]. 264 | * @param rgbColor The color of the gradient at this point, an \c #RGBColor object. 265 | * 266 | * @return GradientStop object. 267 | */ 268 | function GradientStop(offset, rgbColor) 269 | { 270 | this.offset = offset; 271 | this.rgbColor = rgbColor; 272 | }; 273 | 274 | /** 275 | * @class GradientColor 276 | * Stores gradient color information. 277 | * 278 | * @param type The gradient type, must be "linear". 279 | * @param direction A \c #Direction object for the direction of the gradient 280 | (up, down, right, or left). 281 | * @param numStops The number of stops in the gradient. 282 | * @param gradientStopList An array of \c #GradientStop objects. 283 | * 284 | * @return A new \c GradientColor object. 285 | */ 286 | function GradientColor(type, direction, numStops, arrGradientStop) 287 | { 288 | this.type = type; 289 | this.direction = direction; 290 | this.numStops = numStops; 291 | this.arrGradientStop = arrGradientStop; 292 | }; 293 | 294 | /** 295 | * @class UIColor 296 | * Stores color information, including the type, anti-alias level, and specific color 297 | * values in a color object of an appropriate type. 298 | * 299 | * @param type The color type, 1 for "rgb" and 2 for "gradient". 300 | The supplied color object must correspond to this type. 301 | * @param antialiasLevel The anti-alias level constant. 302 | * @param color A \c #RGBColor or \c #GradientColor object containing specific color information. 303 | * 304 | * @return A new \c UIColor object. 305 | */ 306 | function UIColor(type, antialiasLevel, color) 307 | { 308 | this.type = type; 309 | this.antialiasLevel = antialiasLevel; 310 | this.color = color; 311 | }; 312 | 313 | /** 314 | * @class AppSkinInfo 315 | * Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects. 316 | * 317 | * @param baseFontFamily The base font family of the application. 318 | * @param baseFontSize The base font size of the application. 319 | * @param appBarBackgroundColor The application bar background color. 320 | * @param panelBackgroundColor The background color of the extension panel. 321 | * @param appBarBackgroundColorSRGB The application bar background color, as sRGB. 322 | * @param panelBackgroundColorSRGB The background color of the extension panel, as sRGB. 323 | * @param systemHighlightColor The operating-system highlight color, as sRGB. 324 | * 325 | * @return AppSkinInfo object. 326 | */ 327 | function AppSkinInfo(baseFontFamily, baseFontSize, appBarBackgroundColor, panelBackgroundColor, appBarBackgroundColorSRGB, panelBackgroundColorSRGB, systemHighlightColor) 328 | { 329 | this.baseFontFamily = baseFontFamily; 330 | this.baseFontSize = baseFontSize; 331 | this.appBarBackgroundColor = appBarBackgroundColor; 332 | this.panelBackgroundColor = panelBackgroundColor; 333 | this.appBarBackgroundColorSRGB = appBarBackgroundColorSRGB; 334 | this.panelBackgroundColorSRGB = panelBackgroundColorSRGB; 335 | this.systemHighlightColor = systemHighlightColor; 336 | }; 337 | 338 | /** 339 | * @class HostEnvironment 340 | * Stores information about the environment in which the extension is loaded. 341 | * 342 | * @param appName The application's name. 343 | * @param appVersion The application's version. 344 | * @param appLocale The application's current license locale. 345 | * @param appUILocale The application's current UI locale. 346 | * @param appId The application's unique identifier. 347 | * @param isAppOffline True if the application is currently offline. 348 | * @param appSkinInfo An \c #AppSkinInfo object containing the application's default color and font styles. 349 | * 350 | * @return A new \c HostEnvironment object. 351 | */ 352 | function HostEnvironment(appName, appVersion, appLocale, appUILocale, appId, isAppOffline, appSkinInfo) 353 | { 354 | this.appName = appName; 355 | this.appVersion = appVersion; 356 | this.appLocale = appLocale; 357 | this.appUILocale = appUILocale; 358 | this.appId = appId; 359 | this.isAppOffline = isAppOffline; 360 | this.appSkinInfo = appSkinInfo; 361 | }; 362 | 363 | //------------------------------ CSInterface ---------------------------------- 364 | 365 | /** 366 | * @class CSInterface 367 | * This is the entry point to the CEP extensibility infrastructure. 368 | * Instantiate this object and use it to: 369 | * 374 | * 375 | * @return A new \c CSInterface object 376 | */ 377 | function CSInterface() 378 | { 379 | }; 380 | 381 | /** 382 | * User can add this event listener to handle native application theme color changes. 383 | * Callback function gives extensions ability to fine-tune their theme color after the 384 | * global theme color has been changed. 385 | * The callback function should be like below: 386 | * 387 | * @example 388 | * // event is a CSEvent object, but user can ignore it. 389 | * function OnAppThemeColorChanged(event) 390 | * { 391 | * // Should get a latest HostEnvironment object from application. 392 | * var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; 393 | * // Gets the style information such as color info from the skinInfo, 394 | * // and redraw all UI controls of your extension according to the style info. 395 | * } 396 | */ 397 | CSInterface.THEME_COLOR_CHANGED_EVENT = "com.adobe.csxs.events.ThemeColorChanged"; 398 | 399 | /** The host environment data object. */ 400 | CSInterface.prototype.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); 401 | 402 | /** Retrieves information about the host environment in which the 403 | * extension is currently running. 404 | * 405 | * @return A \c #HostEnvironment object. 406 | */ 407 | CSInterface.prototype.getHostEnvironment = function() 408 | { 409 | this.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); 410 | return this.hostEnvironment; 411 | }; 412 | 413 | /** Closes this extension. */ 414 | CSInterface.prototype.closeExtension = function() 415 | { 416 | window.__adobe_cep__.closeExtension(); 417 | }; 418 | 419 | /** 420 | * Retrieves a path for which a constant is defined in the system. 421 | * 422 | * @param pathType The path-type constant defined in \c #SystemPath , 423 | * 424 | * @return The platform-specific system path string. 425 | */ 426 | CSInterface.prototype.getSystemPath = function(pathType) 427 | { 428 | var path = decodeURI(window.__adobe_cep__.getSystemPath(pathType)); 429 | var OSVersion = this.getOSInformation(); 430 | if (OSVersion.indexOf("Windows") >= 0) 431 | { 432 | path = path.replace("file:///", ""); 433 | } 434 | else if (OSVersion.indexOf("Mac") >= 0) 435 | { 436 | path = path.replace("file://", ""); 437 | } 438 | return path; 439 | }; 440 | 441 | /** 442 | * Evaluates a JavaScript script, which can use the JavaScript DOM 443 | * of the host application. 444 | * 445 | * @param script The JavaScript script. 446 | * @param callback Optional. A callback function that receives the result of execution. 447 | * If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. 448 | */ 449 | CSInterface.prototype.evalScript = function(script, callback) 450 | { 451 | if(callback == null || callback == undefined) 452 | { 453 | callback = function(result){}; 454 | } 455 | window.__adobe_cep__.evalScript(script, callback); 456 | }; 457 | 458 | /** 459 | * Retrieves the unique identifier of the application. 460 | * in which the extension is currently running. 461 | * 462 | * @return The unique ID string. 463 | */ 464 | CSInterface.prototype.getApplicationID = function() 465 | { 466 | var appId = this.hostEnvironment.appId; 467 | return appId; 468 | }; 469 | 470 | /** 471 | * Retrieves host capability information for the application 472 | * in which the extension is currently running. 473 | * 474 | * @return A JavaScript object that contains the capabilities. 475 | */ 476 | CSInterface.prototype.getHostCapabilities = function() 477 | { 478 | var hostCapabilities = JSON.parse(window.__adobe_cep__.getHostCapabilities() ); 479 | return hostCapabilities; 480 | }; 481 | 482 | /** 483 | * Triggers a CEP event programmatically. Yoy can use it to dispatch 484 | * an event of a predefined type, or of a type you have defined. 485 | * 486 | * @param event A \c CSEvent object. 487 | */ 488 | CSInterface.prototype.dispatchEvent = function(event) 489 | { 490 | if (typeof event.data == "object") 491 | { 492 | event.data = JSON.stringify(event.data); 493 | } 494 | 495 | window.__adobe_cep__.dispatchEvent(event); 496 | }; 497 | 498 | /** 499 | * Registers an interest in a CEP event of a particular type, and 500 | * assigns an event handler. 501 | * The event infrastructure notifies your extension when events of this type occur, 502 | * passing the event object to the registered handler function. 503 | * 504 | * @param type The name of the event type of interest. 505 | * @param listener The JavaScript handler function or method. 506 | * @param obj Optional, the object containing the handler method, if any. 507 | * Default is null. 508 | */ 509 | CSInterface.prototype.addEventListener = function(type, listener, obj) 510 | { 511 | window.__adobe_cep__.addEventListener(type, listener, obj); 512 | }; 513 | 514 | /** 515 | * Removes a registered event listener. 516 | * 517 | * @param type The name of the event type of interest. 518 | * @param listener The JavaScript handler function or method that was registered. 519 | * @param obj Optional, the object containing the handler method, if any. 520 | * Default is null. 521 | */ 522 | CSInterface.prototype.removeEventListener = function(type, listener, obj) 523 | { 524 | window.__adobe_cep__.removeEventListener(type, listener, obj); 525 | }; 526 | 527 | /** 528 | * Loads and launches another extension, or activates the extension if it is already loaded. 529 | * 530 | * @param extensionId The extension's unique identifier. 531 | * @param startupParams Not currently used, pass "". 532 | * 533 | * @example 534 | * To launch the extension "help" with ID "HLP" from this extension, call: 535 | * requestOpenExtension("HLP", ""); 536 | * 537 | */ 538 | CSInterface.prototype.requestOpenExtension = function(extensionId, params) 539 | { 540 | window.__adobe_cep__.requestOpenExtension(extensionId, params); 541 | }; 542 | 543 | /** 544 | * Retrieves the list of extensions currently loaded in the current host application. 545 | * The extension list is initialized once, and remains the same during the lifetime 546 | * of the CEP session. 547 | * 548 | * @param extensionIds Optional, an array of unique identifiers for extensions of interest. 549 | * If omitted, retrieves data for all extensions. 550 | * 551 | * @return Zero or more \c #Extension objects. 552 | */ 553 | CSInterface.prototype.getExtensions = function(extensionIds) 554 | { 555 | var extensionIdsStr = JSON.stringify(extensionIds); 556 | var extensionsStr = window.__adobe_cep__.getExtensions(extensionIdsStr); 557 | 558 | var extensions = JSON.parse(extensionsStr); 559 | return extensions; 560 | }; 561 | 562 | /** 563 | * Retrieves network-related preferences. 564 | * 565 | * @return A JavaScript object containing network preferences. 566 | */ 567 | CSInterface.prototype.getNetworkPreferences = function() 568 | { 569 | var result = window.__adobe_cep__.getNetworkPreferences(); 570 | var networkPre = JSON.parse(result); 571 | 572 | return networkPre; 573 | }; 574 | 575 | /** 576 | * Initializes the resource bundle for this extension with property values 577 | * for the current application and locale. 578 | * To support multiple locales, you must define a property file for each locale, 579 | * containing keyed display-string values for that locale. 580 | * See localization documentation for Extension Builder and related products. 581 | * 582 | * Keys can be in the 583 | * form key.value="localized string", for use in HTML text elements. 584 | * For example, in this input element, the localized \c key.value string is displayed 585 | * instead of the empty \c value string: 586 | * 587 | * 588 | * 589 | * @return An object containing the resource bundle information. 590 | */ 591 | CSInterface.prototype.initResourceBundle = function() 592 | { 593 | var resourceBundle = JSON.parse(window.__adobe_cep__.initResourceBundle()); 594 | var resElms = document.querySelectorAll('[data-locale]'); 595 | for (var n = 0; n < resElms.length; n++) 596 | { 597 | var resEl = resElms[n]; 598 | // Get the resource key from the element. 599 | var resKey = resEl.getAttribute('data-locale'); 600 | if (resKey) 601 | { 602 | // Get all the resources that start with the key. 603 | for (var key in resourceBundle) 604 | { 605 | if (key.indexOf(resKey) == 0) 606 | { 607 | var resValue = resourceBundle[key]; 608 | if (key.indexOf('.') == -1) 609 | { 610 | // No dot notation in resource key, 611 | // assign the resource value to the element's 612 | // innerHTML. 613 | resEl.innerHTML = resValue; 614 | } 615 | else 616 | { 617 | // Dot notation in resource key, assign the 618 | // resource value to the element's property 619 | // whose name corresponds to the substring 620 | // after the dot. 621 | var attrKey = key.substring(key.indexOf('.') + 1); 622 | resEl[attrKey] = resValue; 623 | } 624 | } 625 | } 626 | } 627 | } 628 | return resourceBundle; 629 | }; 630 | 631 | /** 632 | * Writes installation information to a file. 633 | * 634 | * @return The file path. 635 | */ 636 | CSInterface.prototype.dumpInstallationInfo = function() 637 | { 638 | return window.__adobe_cep__.dumpInstallationInfo(); 639 | }; 640 | 641 | /** 642 | * Retrieves version information for the current Operating System, 643 | * See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. 644 | * 645 | * @return A string containing the OS version, or "unknown Operation System". 646 | */ 647 | CSInterface.prototype.getOSInformation = function() 648 | { 649 | var userAgent = navigator.userAgent; 650 | 651 | if ((navigator.platform == "Win32") || (navigator.platform == "Windows")) 652 | { 653 | var winVersion = "Windows platform"; 654 | if (userAgent.indexOf("Windows NT 5.0") > -1) 655 | { 656 | winVersion = "Windows 2000"; 657 | } 658 | else if (userAgent.indexOf("Windows NT 5.1") > -1) 659 | { 660 | winVersion = "Windows XP"; 661 | } 662 | else if (userAgent.indexOf("Windows NT 5.2") > -1) 663 | { 664 | winVersion = "Windows Server 2003"; 665 | } 666 | else if (userAgent.indexOf("Windows NT 6.0") > -1) 667 | { 668 | winVersion = "Windows Vista"; 669 | } 670 | else if (userAgent.indexOf("Windows NT 6.1") > -1) 671 | { 672 | winVersion = "Windows 7"; 673 | } 674 | else if (userAgent.indexOf("Windows NT 6.2") > -1) 675 | { 676 | winVersion = "Windows 8"; 677 | } 678 | 679 | var winBit = "32-bit"; 680 | if (userAgent.indexOf("WOW64") > -1) 681 | { 682 | winBit = "64-bit"; 683 | } 684 | 685 | return winVersion + " " + winBit; 686 | } 687 | else if ((navigator.platform == "MacIntel") || (navigator.platform == "Macintosh")) 688 | { 689 | var agentStr = new String(); 690 | agentStr = userAgent; 691 | var verLength = agentStr.indexOf(")") - agentStr.indexOf("Mac OS X"); 692 | var verStr = agentStr.substr(agentStr.indexOf("Mac OS X"), verLength); 693 | var result = verStr.replace("_", "."); 694 | result = result.replace("_", "."); 695 | return result; 696 | } 697 | 698 | return "Unknown Operation System"; 699 | }; 700 | 701 | /** 702 | * Opens a page in the default system browser. 703 | * 704 | * @param url The URL of the page to open. Must use HTTP or HTTPS protocol. 705 | * 706 | * @return One of these error codes:\n 707 | * \n 713 | */ 714 | CSInterface.prototype.openURLInDefaultBrowser = function(url) 715 | { 716 | return cep.util.openURLInDefaultBrowser(url); 717 | }; 718 | -------------------------------------------------------------------------------- /lib/json.es: -------------------------------------------------------------------------------- 1 | const json = escape(`\"object\"!=typeof JSON&&(JSON={}),function(){\"use strict\";function f(t){return 10>t?\"0\"+t:t}function this_value(){return this.valueOf()}function quote(t){return escapable.lastIndex=0,escapable.test(t)?\'\"\'+t.replace(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 n,r,o,u,f,i=gap,a=e[t];switch(a&&\"object\"==typeof a&&\"function\"==typeof a.toJSON&&(a=a.toJSON(t)),\"function\"==typeof rep&&(a=rep.call(e,t,a)),typeof a){case\"string\":return quote(a);case\"number\":return isFinite(a)?String(a):\"null\";case\"boolean\":case\"null\":return String(a);case\"object\":if(!a)return\"null\";if(gap+=indent,f=[],\"[object Array]\"===Object.prototype.toString.apply(a)){for(u=a.length,n=0;u>n;n+=1)f[n]=str(n,a)||\"null\";return o=0===f.length?\"[]\":gap?\"[\\n\"+gap+f.join(\",\\n\"+gap)+\"\\n\"+i+\"]\":\"[\"+f.join(\",\")+\"]\",gap=i,o}if(rep&&\"object\"==typeof rep)for(u=rep.length,n=0;u>n;n+=1)\"string\"==typeof rep[n]&&(r=rep[n],o=str(r,a),o&&f.push(quote(r)+(gap?\": \":\":\")+o));else for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(o=str(r,a),o&&f.push(quote(r)+(gap?\": \":\":\")+o));return o=0===f.length?\"{}\":gap?\"{\\n\"+gap+f.join(\",\\n\"+gap)+\"\\n\"+i+\"}\":\"{\"+f.join(\",\")+\"}\",gap=i,o}}\"function\"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+\"-\"+f(this.getUTCMonth()+1)+\"-\"+f(this.getUTCDate())+\"T\"+f(this.getUTCHours())+\":\"+f(this.getUTCMinutes())+\":\"+f(this.getUTCSeconds())+\"Z\":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var cx,escapable,gap,indent,meta,rep;\"function\"!=typeof JSON.stringify&&(escapable=\/[\\\\\\\"\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]\/g,meta={\"\\b\":\"\\\\b\",\"\t\":\"\\\\t\",\"\\n\":\"\\\\n\",\"\\f\":\"\\\\f\",\"\\r\":\"\\\\r\",\'\"\':\'\\\\\"\',\"\\\\\":\"\\\\\\\\\"},JSON.stringify=function(t,e,n){var r;if(gap=\"\",indent=\"\",\"number\"==typeof n)for(r=0;n>r;r+=1)indent+=\" \";else\"string\"==typeof n&&(indent=n);if(rep=e,e&&\"function\"!=typeof e&&(\"object\"!=typeof e||\"number\"!=typeof e.length))throw new Error(\"JSON.stringify\");return str(\"\",{\"\":t})}),\"function\"!=typeof JSON.parse&&(cx=\/[\\u0000\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]\/g,JSON.parse=function(text,reviver){function walk(t,e){var n,r,o=t[e];if(o&&\"object\"==typeof o)for(n in o)Object.prototype.hasOwnProperty.call(o,n)&&(r=walk(o,n),void 0!==r?o[n]=r:delete o[n]);return reviver.call(t,e,o)}var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(t){return\"\\\\u\"+(\"0000\"+t.charCodeAt(0).toString(16)).slice(-4)})),\/^[\\],:{}\\s]*$\/.test(text.replace(\/\\\\(?:[\"\\\\\\\/bfnrt]|u[0-9a-fA-F]{4})\/g,\"@\").replace(\/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?\/g,\"]\").replace(\/(?:^|:|,)(?:\\s*\\[)+\/g,\"\")))return j=eval(\"(\"+text+\")\"),\"function\"==typeof reviver?walk({\"\":j},\"\"):j;throw new SyntaxError(\"JSON.parse\")})}();`); 2 | 3 | new CSInterface().evalScript(`eval(unescape("${json}"))`) 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "extend-script-loader", 3 | "version": "1.1.0", 4 | "description": "This package allows for easy execution of ExtendScript files directly from a CEP panel.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "http://github.com/fusepilot/extend-script-loader.git" 9 | }, 10 | "dependencies": { 11 | "loader-utils": "^0.2.12" 12 | }, 13 | "scripts": { 14 | "dev:simple": "cd examples/simple && gulp" 15 | }, 16 | "author": "Michael Delaney (http://fusepilot.com)", 17 | "license": "MIT", 18 | "devDependencies": { 19 | "del": "^2.2.0", 20 | "gulp": "github:gulpjs/gulp#4.0", 21 | "gulp-util": "^3.0.7", 22 | "mocha": "^2.4.5", 23 | "should": "^8.2.2", 24 | "webpack": "^1.12.14", 25 | "webpack-dev-server": "^1.14.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /plugin.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | function ExtendScriptPlugin(options) {} 5 | 6 | ExtendScriptPlugin.prototype.apply = function(compiler) { 7 | compiler.plugin('emit', function(compilation, callback) { 8 | 9 | var interface = fs.readFileSync(path.join(__dirname, './lib/CSInterface.js')) 10 | var json = fs.readFileSync(path.join(__dirname, './lib/JSON.es')) 11 | 12 | compilation.assets['interface.es'] = { 13 | source: function() { 14 | return interface.toString(); 15 | }, 16 | size: function() { 17 | return 1; 18 | } 19 | }; 20 | 21 | compilation.assets['json.es'] = { 22 | source: function() { 23 | return json.toString(); 24 | }, 25 | size: function() { 26 | return 1; 27 | } 28 | }; 29 | 30 | callback(); 31 | }); 32 | }; 33 | 34 | module.exports = ExtendScriptPlugin; 35 | --------------------------------------------------------------------------------