From d48499fb2fecc508c41eacce64025ec6bd5f08e7 Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 14:05:41 -0400 Subject: [PATCH 1/8] folder added --- Import files from another server/readme.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Import files from another server/readme.md diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md new file mode 100644 index 0000000..e69de29 From 4e4cc83f85ebc6e39f036a2ffd20c91c958848b3 Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 14:47:29 -0400 Subject: [PATCH 2/8] import guide added --- Import files from another server/.debug | 29 + Import files from another server/.gitignore | 3 + .../CSXS/manifest.xml | 75 ++ .../client/index.html | 19 + .../client/index.js | 69 ++ .../client/js/lib/DownloadCSInterfaceHere.md | 2 + .../client/localServer.html | 13 + .../host/index.jsx | 6 + .../package-lock.json | 763 ++++++++++++++++++ Import files from another server/package.json | 18 + Import files from another server/readme.md | 456 +++++++++++ .../server/main.js | 40 + 12 files changed, 1493 insertions(+) create mode 100644 Import files from another server/.debug create mode 100644 Import files from another server/.gitignore create mode 100644 Import files from another server/CSXS/manifest.xml create mode 100644 Import files from another server/client/index.html create mode 100644 Import files from another server/client/index.js create mode 100644 Import files from another server/client/js/lib/DownloadCSInterfaceHere.md create mode 100644 Import files from another server/client/localServer.html create mode 100644 Import files from another server/host/index.jsx create mode 100644 Import files from another server/package-lock.json create mode 100644 Import files from another server/package.json create mode 100644 Import files from another server/server/main.js diff --git a/Import files from another server/.debug b/Import files from another server/.debug new file mode 100644 index 0000000..0528b06 --- /dev/null +++ b/Import files from another server/.debug @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Import files from another server/.gitignore b/Import files from another server/.gitignore new file mode 100644 index 0000000..883aea4 --- /dev/null +++ b/Import files from another server/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +node_modules +client/js/lib/CSInterface.js diff --git a/Import files from another server/CSXS/manifest.xml b/Import files from another server/CSXS/manifest.xml new file mode 100644 index 0000000..b9c2ba8 --- /dev/null +++ b/Import files from another server/CSXS/manifest.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + ./client/index.html + ./host/index.jsx + + + true + + + Panel + Panel Import Example + + + 500 + 350 + + + 200 + 200 + + + 600 + 400 + + + + + + + + + + ./client/localServer.html + + --enable-nodejs + --mixed-context + + + + false + + + Custom + + + 500 + 350 + + + + + + + + diff --git a/Import files from another server/client/index.html b/Import files from another server/client/index.html new file mode 100644 index 0000000..f519f24 --- /dev/null +++ b/Import files from another server/client/index.html @@ -0,0 +1,19 @@ + + + + + Import Example Panel + + +

Import Example Panel

+ + + + + + + diff --git a/Import files from another server/client/index.js b/Import files from another server/client/index.js new file mode 100644 index 0000000..a47701d --- /dev/null +++ b/Import files from another server/client/index.js @@ -0,0 +1,69 @@ +/* + CSInterface +*/ +var csInterface = new CSInterface(); + +/* + UI Elements +*/ +var importButton = document.querySelector("#import-button"); +var documentsButton = document.querySelector("#documents-button"); +var extensionButton = document.querySelector("#extension-button"); +var downloadOptions = document.querySelector("#download-options"); + +/* + Event listeners +*/ +importButton.addEventListener("click", importToggle); +documentsButton.addEventListener("click", function(){importTo('documents');}, false); +extensionButton.addEventListener("click", function(){importTo('extension');}, false); + +/* + User folder paths +*/ +var extensionDirectory = csInterface.getSystemPath("extension"); +var documentsDirectory = csInterface.getSystemPath("myDocuments"); + +/* + Starting Node JS +*/ +csInterface.requestOpenExtension("com.cep.import.localserver", ""); + +/* + Helper methods +*/ +function importToggle() { + if (downloadOptions.style.display === "none") { + downloadOptions.style.display = "block"; + importButton.innerText = "Cacel"; + } else { + downloadOptions.style.display = "none"; + importButton.innerText = "Import from external server"; + } +} + +function importTo(location) { + var directory = location == "documents" ? documentsDirectory : extensionDirectory; + var url = "http://localhost:3200/import"; + + $.ajax({ + type: "GET", + url: url, + headers: { + "directory": directory + }, + success: response => { + downloadOptions.style.display = "none"; + importButton.innerText = "Import from external server"; + alert(`File imported. Location: ${response}`); + csInterface.evalScript(`displayFile("${response}")`); + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(errorThrown, jqXHR.responseJSON); + } + }) + +} + + diff --git a/Import files from another server/client/js/lib/DownloadCSInterfaceHere.md b/Import files from another server/client/js/lib/DownloadCSInterfaceHere.md new file mode 100644 index 0000000..f4bd138 --- /dev/null +++ b/Import files from another server/client/js/lib/DownloadCSInterfaceHere.md @@ -0,0 +1,2 @@ +## Access Adobe CEP Repository at https://github.com/Adobe-CEP/CEP-Resources/ +## Copy and paste the newest version of CSInterface.js that's compatible with your version of Creative Cloud \ No newline at end of file diff --git a/Import files from another server/client/localServer.html b/Import files from another server/client/localServer.html new file mode 100644 index 0000000..e6d9fd7 --- /dev/null +++ b/Import files from another server/client/localServer.html @@ -0,0 +1,13 @@ + + + + + + Import Example App + + + + + diff --git a/Import files from another server/host/index.jsx b/Import files from another server/host/index.jsx new file mode 100644 index 0000000..1c4ef49 --- /dev/null +++ b/Import files from another server/host/index.jsx @@ -0,0 +1,6 @@ +function displayFile(path) { + if (app.name == "Adobe Photoshop") { + var fileRef = new File(path) + app.open(fileRef) + } +} diff --git a/Import files from another server/package-lock.json b/Import files from another server/package-lock.json new file mode 100644 index 0000000..f20fbbb --- /dev/null +++ b/Import files from another server/package-lock.json @@ -0,0 +1,763 @@ +{ + "name": "adobe-import-example-panel", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.18", + "negotiator": "0.6.1" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "basic-auth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", + "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.16" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.1" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.3", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.16", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + } + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + }, + "dependencies": { + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.4.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", + "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jquery": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "requires": { + "mime-db": "1.33.0" + } + }, + "morgan": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz", + "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", + "requires": { + "basic-auth": "2.0.0", + "debug": "2.6.9", + "depd": "1.1.2", + "on-finished": "2.3.0", + "on-headers": "1.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "proxy-addr": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", + "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.6.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + } + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.1" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.18" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + } + } +} diff --git a/Import files from another server/package.json b/Import files from another server/package.json new file mode 100644 index 0000000..d56e327 --- /dev/null +++ b/Import files from another server/package.json @@ -0,0 +1,18 @@ +{ + "name": "adobe-import-example-panel", + "version": "1.0.0", + "description": "", + "main": "server/main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "body-parser": "^1.18.2", + "express": "^4.16.2", + "jquery": "^3.3.1", + "morgan": "^1.9.0", + "request": "^2.83.0" + } +} diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index e69de29..0c2b1aa 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -0,0 +1,456 @@ +# Importing files from the network +Many Creative Cloud app extensions require the ability to talk to API services on the web. With both Chromium Embedded Framework (CEF) and Node.js at its core, CEP gives you the flexibility to make network calls from within your extension in the way that makes sense for your workflow. + +This guide and its companion sample extension will show you how you can create a Node.js-based extension to allow users to retrieve files from an external server/url and load them in Adobe host applications. + +By the end of this guide, we will have an Adobe Photoshop extension that: + +1. Downloads an image from a url and saves it in a user-specified location on the local machine +1. Loads the image in Photoshop + + + + + + +##Contents + +1. [Technology Used](#technology-used) +1. [Prerequisites](#prerequisites) +1. [Configuration Setup](#configuration-setup) + 1. [Set up the sample extension](#set-up-the-sample-extension) + 1. [Configure `manifest.xml`](#configure-manifestxml) +1. [Client-side: HTML Markup for user-facing extension](#client-side-html-markup-for-user-facing-extension) +1. [Client-side: HTML Markup for Node.js server extension](#client-side-html-markup-for-nodejs-server-extension) +1. [Client-side: Service API interaction](#client-side-service-api-interaction) + 1. [Instantiate `CSInterface`](#instantiate-csinterface) + 1. [Load the second extension for running an Express server](#load-the-second-extension-for-running-an-express-server) + 1. [Create references to the UI elements](#create-references-to-the-ui-elements) + 1. [Add a click handler to the button](#add-a-click-handler-to-the-button) + 1. [Toggling button to show/hide options](#toggling-button-to-showhide-options) + 1. [Getting the local path](#getting-the-local-path) + 1. [Communicating with the server](#communicating-with-the-server) + 1. [Communicate with the host app](#communicate-with-the-host-app) +1. [Host app: Automation with ExtendScript](#host-app-automation-with-extendscript) + 1. [Create an ExtendScript function](#create-an-extendscript-function) +1. [Server-side: Setup](#server-side-setup) + 1. [Install node modules](#install-node-modules) + 1. [Write server logic in `main.js`](#write-server-logic-in-mainjs) +1. [Troubleshooting and Known Issues](#troubleshooting-and-known-issues) +1. [Other Resources](#other-resources) + + + + +## Technology Used + +- Supported Host Applications: Photoshop +- Libraries/Frameworks/APIs: + - Adobe-specific: [CEP](https://github.com/Adobe-CEP/CEP-Resources) + - Other: [jQuery](https://jquery.com/), [Dropbox Auth API](https://www.dropbox.com/developers/reference/oauth-guide) + + +## Prerequisites +This guide will assume that you have installed all software and completed all steps in the following guides: + +- [Getting Started Guide](https://github.com/Adobe-CEP/Getting-Started-guides) + +## Configuration Setup + +### Set up the sample extension + +The following steps will help you get the sample extension for this guide up and running: + +1. Install the `./com.cep.import/` directory in your `extensions` folder. ([See the Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-folders) if you are unsure where your `extensions` folder is.) +1. [Download CEP's `CSInterface.js` library](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/CSInterface.js) and move it to `./com.cep.import/client/js/lib/CSInterface.js`. + +After following these steps, you'll be able to run the sample extension within the host apps indicated in the [Technology Used](#technology-used) section of this guide. + +### Configure `manifest.xml` + +As noted in the [Getting Started guide](https://github.com/Adobe-CEP/Getting-Started-guides), the `manifest.xml` file is where you set various configurations for your panel, such as supported host apps, panel type, CEF parameters, main path, script path, default/minimum/maximum panel size, and others. Refer to the latest version of XML schema in [CEP Github](https://github.com/Adobe-CEP/CEP-Resources/). + +**List supported host apps and versions** + +The first configuration to set in `manifest.xml` is indicating which Creative Cloud host apps and version numbers your extension supports. For this guide, we'll make an extension that supports Photoshop. So in the `manifest.xml`, make sure you list the supported host names for Photoshop within the `` element: + +```xml + + + + + + + + + + +``` + +Note that the versions indicated in the example code above only target a single version of each host app, for the sake of demo simplicity. Most extension developers will want to target a range of host app versions. To learn how to support multiple host app versions, [see the Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-manifest). + +**Configure the user-facing extension** + +This sample panel is comprised of two separate extensions. However, this does not mean that users will have to load two separate extensions. Only the user-facing panel will be visible to the user while the second extension will be loaded automatically in the background when a simple JavaScript CEP method is called (This will be covered later). Let's configure the user facing extension first. + +In the `manifest.xml`, there is a tag called `` which lists all extensions used in the panel. Let's list the main extension, which includes the client side and the host application side logic. As configured in `manifest.xml`, this extension will be visible to the user. + +```xml + + + +``` + +The next step is to configure details for this main extension, `com.cep.import.panel`. You can insert configurations for this extension by starting with the `` tag under the `` tag: + +```xml + + + ... + +``` + +Under this tag, you can provide details, such as type, script paths, menu name, and sizes: + +```xml + + + + ./client/index.html + ./host/index.jsx + + + true + + + Panel + Panel Import Example + + + 500 + 350 + + + 200 + 200 + + + 600 + 400 + + + + + + +``` + +Now configurations for the main extension have been set up. The next step is to configure the invisible Node.js server extension. + +**Configure the invisible Node.js server extension** + +As mentioned above, there are two separate extensions in this sample panel. The purpose of the second extension,`com.cep.import.localserver`, is to set and start the Node.js server. + +Let's add this second extension to the `` tag. + +```xml + + + + +``` + +Similar to setting the main extension, you need to configure details for this invisible extension, `com.cep.import.localserver`. Note that you can insert multiple `` tags under the `` tag. You need to simply insert another `` tag for this server extension. + +```xml + +``` + +Under this tag, you can provide details, such as type, script paths, menu name, and sizes: + +```xml + + + + ./client/localServer.html + + --enable-nodejs + --mixed-context + + + + false + + + Custom + + + 500 + 350 + + + + + + +``` + +Note that since `com.cep.import.localserver` will be using Node.js, the two parameters, `--enable-nodejs` and `--mixed-context`, are added within `` as seen above. Also, the `` tag is set to `false` and the `` of the extension is set to `Custom`. This setting makes this server extension invisible to the user. + +## Client-side: HTML Markup for user-facing extension + +The user interface for CEP extensions is written in HTML. For this sample, you will need to create two HTML documents, one for each extension. Let's create a HTML for the main extension first. + +As written in the `` tag of the extension in the `manifest.xml` file, you will find the main HTML located at `./com.cep.import/client/index.html`. This HTML will be loaded and be visible to the user. + +See comments **#1-3**: + +```html + + + + + Import Example Panel + + +

Import Example Panel

+ + + + + + + + + + + + + + +``` + +This HTML markup for the main extension, `com.cep.import.panel`, is the HTML page users will see when they first launch your panel. + +## Client-side: HTML Markup for Node.js server extension + +As written in the `` tag of the server extension, another HTML markup will be loaded from `./com.cep.import/client/localServer.html` in the background and run the `cep_node` method to start the Node.JS server at `/server/main.js`. This HTML will be invisible to users as mentioned above. + +_Note: the server extension will load only after the main extension's JavaScript invokes `csInterface.requestOpenExtension()` function. This will be explained shortly in [the later section](#load-the-second-extension-for-running-an-express-server)_ + +see comments **#1**: + +```html + + + + + + Import Example App + + + + +``` + +The sole purpose of this HTML markup for the server extension, `com.cep.import.localserver`, is to start the Node.js server. This page will not be visible to users. + +## Client-side: Service API interaction +As we saw in the previous section's `index.html` code, the client-side JavaScript for the main extension is located at `./com.cep.import/client/js/index.js`. We will look at this `index.js` file in this section. + +### Instantiate `CSInterface` +For any CEP extension, you'll need an instance of `CSInterface`, which, among other things, gives you a way to communicate with the host app's scripting engine: + +```javascript +var csInterface = new CSInterface(); +``` + +We'll make use of this `csInterface` constant later on. + +### Load the second extension for running an Express server +`csInterface` has a method called `requestOpenExtension`, which opens another extension given an extension ID. In this sample, this method is used to launch the server extension: + +```javascript +csInterface.requestOpenExtension("com.cep.import.localserver", ""); +``` + +Simply include the line above in your main extension’s JavaScript file, `client/index.js`. This will open the HTML markup of the invisible server extension. Then, JavaScript written in the HTML markup will start the Node.js server located at `/server/main.js`. Once the second extension is loaded, the Express located at `/server/main.js` will start as written in `/client/localServer.html`. + +### Create references to the UI elements +In `index.js`, we'll first reference the elements in our `index.html`: + +```javascript +var importButton = document.querySelector("#import-button"); +var documentsButton = document.querySelector("#documents-button"); +var extensionButton = document.querySelector("#extension-button"); +var downloadOptions = document.querySelector("#download-options"); +``` + +We'll work with these UI elements in the next step. + +### Add a click handler to the button +We'll add a click handler to the buttons: + +```javascript +importButton.addEventListener("click", importToggle); +documentsButton.addEventListener("click", function(){importTo('documents');}, false); +extensionButton.addEventListener("click", function(){importTo('extension');}, false); +``` + +We'll make the `importToggle()` and `importTo()` helper methods in the next step. + +### Toggling button to show/hide options +`importToggle()` helper function simply shows/hides the options and changes the text of the button dynamically. +``` +function importToggle() { + if (downloadOptions.style.display === "none") { + downloadOptions.style.display = "block"; + importButton.innerText = "Cacel"; + } else { + downloadOptions.style.display = "none"; + importButton.innerText = "Import from external server"; + } +} +``` + +### Getting the local path +`CSInterface` has a method called `getSystemPath()` which returns the user's path. In this example, we only use two user paths. Refer to [CSInterface Documentation](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/CSInterface.js) for other paths. +``` +var extensionDirectory = csInterface.getSystemPath("extension"); +var documentsDirectory = csInterface.getSystemPath("myDocuments"); +``` +We will use these directory variables in the following section. + +### Communicating with the server +In this sample, `importTo()` uses `jQuery` to communicate with the server. (see comments **#1-6**) +```javascript +function importTo(location) { + /* 1) Uses the correct variable based on the user's input */ + var directory = location == "documents" ? documentsDirectory : extensionDirectory; + /* 2) Server import endpoint */ + var url = "http://localhost:3200/import"; + + $.ajax({ + type: "GET", + url: url, + headers: { + "directory": directory + }, + success: response => { + /* 3) Hide options */ + downloadOptions.style.display = "none"; + + /* 4) Change the button text */ + importButton.innerText = "Import from external server"; + + /* 5) Show the user where the file was saved */ + alert(`File imported. Location: ${response}`); + + /* 6) Use ExtendScript to show the file in Photoshop */ + csInterface.evalScript(`displayFile("${response}")`); + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(errorThrown, jqXHR.responseJSON); + } + }) + +} +``` + +### Communicate with the host app +To communicate with the host app's scripting engine, we'll make use of the `csInterface.evalScript()` method. (If you need a refresher on the `.evalScript()` method, refer to the [Getting Started guide](https://github.com/Adobe-CEP/Getting-Started-guides).) + +In this sample app, our `.evalScript()` call will be invoked once we get the response back from the server in the step above. We could interpret the `.evalScript()` call in the code above as meaning: + +> Hey host app, call the `displayFile()` function from my ExtendScript file. + +We’ll need to make sure that ExtendScript function exists in the next section. + +## Host app: Automation with ExtendScript +Many CC host apps like Photoshop and InDesign (and many more) can be automated with ExtendScript. In this sample extension, we're going to simply display the downloaded asset in Photoshop. + +Note once again that this sample app is extremely simple for the purpose of focus. ExtendScript provides many deep features to automate work in CC host apps; you can explore more ExtendScript features in our Scripting Guides. + +The ExtendScript file for this extension is located at `./com.cep.import/host/index.jsx`. + + +### Create an ExtendScript function +In the extension's `index.jsx` file, let's create a function called `displayFile()`. (see comments **#1-3**): + +```javascript +function displayFile(path) { + /* 1) First, check if the user is in the supported host app, Photoshop, in this case */ + if (app.name == "Adobe Photoshop") { + + /* 2) Create a file reference */ + var fileRef = new File(path) + + /* 3) Open the file inside Photoshop */ + app.open(fileRef) + } +} +``` + +The function runs and displays the downloaded asset in Photoshop. Note that this function does not `return` anything. However, you can write your ExtendScript function to `return` something, which can be captured in a callback like below: + +```javascript +csInterface.evalScript('doSomething()', function(value){ + console.log(value) +}) +``` + +## Server-side: Setup +### Install Node.js and npm +[Download and install Node.js and its package manager, npm](https://www.npmjs.com/get-npm), and make sure you have the `package.json` file in the root level directory of your panel. + +### Install node modules +Make sure to install all node dependencies required by this extension. +``` +npm install +``` + +### Write server logic in `main.js` +This sample extension uses `express` and `http` to set up a server. Make sure to the same port, in this case, `3000`. While this example simply downloads an image from a url, you can imagin you can modifiy this to hit other APIs or your own server to retrieve data. (see comments **#1-4**): + +``` +app.get("/import", (req, res, next) => { + + /* 1) Grab the desired directory from the headers and insert the default image name */ + var path = req.headers["directory"] + "/placeholder.png" + + /* 2) Note this uri variable can be a server endpoint as well */ + var uri = "http://via.placeholder.com/350x150"; + + download(uri, path, function(){ + /* 3) Once download is completed, send the path to the client side */ + res.status(200).send(path) + }); + + /* 4) Helper function to download the asset using the fs module */ + var download = function(uri, filepath, callback){ + request.head(uri, function(err, res, body){ + request(uri).pipe(fs.createWriteStream(filepath)).on('close', callback); + }); + }; + +}); +``` + +After saving the file, the server simply responds with the path of the file, which is eventually used by `index.jsx` to load the image in Photoshop. + +## Troubleshooting and Known Issues +Articles about common issues are [here](!LINK). + +You can submit tickets for bugs and feature requests [here](!LINK). + +## Other Resources +- [CEP Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md) +- [Photoshop ExtendScript](https://www.adobe.com/devnet/photoshop/scripting.html) diff --git a/Import files from another server/server/main.js b/Import files from another server/server/main.js new file mode 100644 index 0000000..ae81568 --- /dev/null +++ b/Import files from another server/server/main.js @@ -0,0 +1,40 @@ +const express = require("express"); +const app = express(); +const request = require('request'); +const http = require('http'); +const path = require("path"); +const bodyParser = require("body-parser"); +const logger = require("morgan"); +const fs = require('fs'); +const httpServer = http.Server(app); + +module.exports = run + +function run(){ + var port = 3200; + var hostname = "localhost" + httpServer.listen(port); + + app.use(logger("dev")); + app.use(bodyParser.json()); + app.use(bodyParser.urlencoded({ limit: '50mb',extended: true })); + app.use(express.static(path.join(__dirname, "../client"))); + + app.get("/import", (req, res, next) => { + + var path = req.headers["directory"] + "/placeholder.png" + var uri = "http://via.placeholder.com/350x150"; + + var saveImage = function(uri, filepath, callback){ + request.head(uri, function(err, res, body){ + request(uri).pipe(fs.createWriteStream(filepath)).on('close', callback); + }); + }; + + saveImage(uri, path, function(){ + res.status(200).send(path) + }); + + + }); +} \ No newline at end of file From f7046e7fde2f7f8a621fd70bbb97e21817042542 Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 14:50:51 -0400 Subject: [PATCH 3/8] readme modified --- Import files from another server/readme.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index 0c2b1aa..5febcd5 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -9,11 +9,11 @@ By the end of this guide, we will have an Adobe Photoshop extension that: 1. Loads the image in Photoshop - + -##Contents +## Contents 1. [Technology Used](#technology-used) 1. [Prerequisites](#prerequisites) @@ -34,6 +34,7 @@ By the end of this guide, we will have an Adobe Photoshop extension that: 1. [Host app: Automation with ExtendScript](#host-app-automation-with-extendscript) 1. [Create an ExtendScript function](#create-an-extendscript-function) 1. [Server-side: Setup](#server-side-setup) + 1. [Install Node.js and npm](#install-nodejs-and-npm) 1. [Install node modules](#install-node-modules) 1. [Write server logic in `main.js`](#write-server-logic-in-mainjs) 1. [Troubleshooting and Known Issues](#troubleshooting-and-known-issues) From 4fd8d50a3d7e957670724fb5450ed35224e524d4 Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 14:59:01 -0400 Subject: [PATCH 4/8] folder structure changed --- .../{ => com.cep.import}/CSXS/manifest.xml | 0 .../{ => com.cep.import}/client/index.html | 0 .../{ => com.cep.import}/client/index.js | 0 .../client/js/lib/DownloadCSInterfaceHere.md | 0 .../client/localServer.html | 0 .../{ => com.cep.import}/host/index.jsx | 0 .../{ => com.cep.import}/package-lock.json | 0 .../{ => com.cep.import}/package.json | 0 .../{ => com.cep.import}/server/main.js | 0 .../readme-assets/folder-structure.png | Bin 0 -> 42943 bytes Import files from another server/readme.md | 5 +++++ 11 files changed, 5 insertions(+) rename Import files from another server/{ => com.cep.import}/CSXS/manifest.xml (100%) rename Import files from another server/{ => com.cep.import}/client/index.html (100%) rename Import files from another server/{ => com.cep.import}/client/index.js (100%) rename Import files from another server/{ => com.cep.import}/client/js/lib/DownloadCSInterfaceHere.md (100%) rename Import files from another server/{ => com.cep.import}/client/localServer.html (100%) rename Import files from another server/{ => com.cep.import}/host/index.jsx (100%) rename Import files from another server/{ => com.cep.import}/package-lock.json (100%) rename Import files from another server/{ => com.cep.import}/package.json (100%) rename Import files from another server/{ => com.cep.import}/server/main.js (100%) create mode 100644 Import files from another server/readme-assets/folder-structure.png diff --git a/Import files from another server/CSXS/manifest.xml b/Import files from another server/com.cep.import/CSXS/manifest.xml similarity index 100% rename from Import files from another server/CSXS/manifest.xml rename to Import files from another server/com.cep.import/CSXS/manifest.xml diff --git a/Import files from another server/client/index.html b/Import files from another server/com.cep.import/client/index.html similarity index 100% rename from Import files from another server/client/index.html rename to Import files from another server/com.cep.import/client/index.html diff --git a/Import files from another server/client/index.js b/Import files from another server/com.cep.import/client/index.js similarity index 100% rename from Import files from another server/client/index.js rename to Import files from another server/com.cep.import/client/index.js diff --git a/Import files from another server/client/js/lib/DownloadCSInterfaceHere.md b/Import files from another server/com.cep.import/client/js/lib/DownloadCSInterfaceHere.md similarity index 100% rename from Import files from another server/client/js/lib/DownloadCSInterfaceHere.md rename to Import files from another server/com.cep.import/client/js/lib/DownloadCSInterfaceHere.md diff --git a/Import files from another server/client/localServer.html b/Import files from another server/com.cep.import/client/localServer.html similarity index 100% rename from Import files from another server/client/localServer.html rename to Import files from another server/com.cep.import/client/localServer.html diff --git a/Import files from another server/host/index.jsx b/Import files from another server/com.cep.import/host/index.jsx similarity index 100% rename from Import files from another server/host/index.jsx rename to Import files from another server/com.cep.import/host/index.jsx diff --git a/Import files from another server/package-lock.json b/Import files from another server/com.cep.import/package-lock.json similarity index 100% rename from Import files from another server/package-lock.json rename to Import files from another server/com.cep.import/package-lock.json diff --git a/Import files from another server/package.json b/Import files from another server/com.cep.import/package.json similarity index 100% rename from Import files from another server/package.json rename to Import files from another server/com.cep.import/package.json diff --git a/Import files from another server/server/main.js b/Import files from another server/com.cep.import/server/main.js similarity index 100% rename from Import files from another server/server/main.js rename to Import files from another server/com.cep.import/server/main.js diff --git a/Import files from another server/readme-assets/folder-structure.png b/Import files from another server/readme-assets/folder-structure.png new file mode 100644 index 0000000000000000000000000000000000000000..9a0a0e1b47b16d1b4d36dcaeda9c41f91b25a4a9 GIT binary patch literal 42943 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%0DnLU}0e~KOX~#qT&1ZtZVS`;EoM{*_`c!keL?S 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 literal 0 HcmV?d00001 diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index 5febcd5..1ae3429 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -56,6 +56,11 @@ This guide will assume that you have installed all software and completed all st - [Getting Started Guide](https://github.com/Adobe-CEP/Getting-Started-guides) +## Folder Structure +If you have a directory structure similar to the one suggested in the [Getting Started Guide](https://github.com/Adobe-CEP/Getting-Started-guides), all you have to add is a folder designated for your server, a Node.js file, a `main.js` file inside the server folder, and another HTML file, `localServer.html`, all under the existing client folder: + +![](readme-assets/folder-structure.png) + ## Configuration Setup ### Set up the sample extension From f15196c49d5b14b343478532ecf97c8600dcd77f Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 15:00:20 -0400 Subject: [PATCH 5/8] readme modified --- Import files from another server/readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index 1ae3429..e814e73 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -61,6 +61,10 @@ If you have a directory structure similar to the one suggested in the [Getting S ![](readme-assets/folder-structure.png) +The `main.js` file is a Node.js file where write server logic. The root directory can be saved either at the root level or at the user level, depending on who’s allowed to use the extension (refer to the [CEP 8 HTML Extension Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-folders) for the exact paths). + +Note that except for the required CSXS folder, which must contain manifest.xml, the folder structure is flexible. + ## Configuration Setup ### Set up the sample extension From 114fb23b693e9a5f5ab79196811c78124e87a8e7 Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 15:00:49 -0400 Subject: [PATCH 6/8] readme modified --- Import files from another server/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index e814e73..70b6558 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -63,7 +63,7 @@ If you have a directory structure similar to the one suggested in the [Getting S The `main.js` file is a Node.js file where write server logic. The root directory can be saved either at the root level or at the user level, depending on who’s allowed to use the extension (refer to the [CEP 8 HTML Extension Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-folders) for the exact paths). -Note that except for the required CSXS folder, which must contain manifest.xml, the folder structure is flexible. +Note that except for the required `CSXS` folder, which must contain manifest.xml, the folder structure is flexible. ## Configuration Setup From d5e18a5fbdf6146732fb1e5b92950423e2f9d21f Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 15:01:16 -0400 Subject: [PATCH 7/8] readme toc modified --- Import files from another server/readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index 70b6558..d064ee6 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -17,6 +17,7 @@ By the end of this guide, we will have an Adobe Photoshop extension that: 1. [Technology Used](#technology-used) 1. [Prerequisites](#prerequisites) +1. [Folder Structure](#folder-structure) 1. [Configuration Setup](#configuration-setup) 1. [Set up the sample extension](#set-up-the-sample-extension) 1. [Configure `manifest.xml`](#configure-manifestxml) From f4103e313f045560fb0b9a17844222213c4541fa Mon Sep 17 00:00:00 2001 From: Steve Kwak Date: Tue, 1 May 2018 15:03:27 -0400 Subject: [PATCH 8/8] readme toc modified --- Import files from another server/readme.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Import files from another server/readme.md b/Import files from another server/readme.md index d064ee6..a85bbca 100644 --- a/Import files from another server/readme.md +++ b/Import files from another server/readme.md @@ -19,25 +19,11 @@ By the end of this guide, we will have an Adobe Photoshop extension that: 1. [Prerequisites](#prerequisites) 1. [Folder Structure](#folder-structure) 1. [Configuration Setup](#configuration-setup) - 1. [Set up the sample extension](#set-up-the-sample-extension) - 1. [Configure `manifest.xml`](#configure-manifestxml) 1. [Client-side: HTML Markup for user-facing extension](#client-side-html-markup-for-user-facing-extension) 1. [Client-side: HTML Markup for Node.js server extension](#client-side-html-markup-for-nodejs-server-extension) 1. [Client-side: Service API interaction](#client-side-service-api-interaction) - 1. [Instantiate `CSInterface`](#instantiate-csinterface) - 1. [Load the second extension for running an Express server](#load-the-second-extension-for-running-an-express-server) - 1. [Create references to the UI elements](#create-references-to-the-ui-elements) - 1. [Add a click handler to the button](#add-a-click-handler-to-the-button) - 1. [Toggling button to show/hide options](#toggling-button-to-showhide-options) - 1. [Getting the local path](#getting-the-local-path) - 1. [Communicating with the server](#communicating-with-the-server) - 1. [Communicate with the host app](#communicate-with-the-host-app) 1. [Host app: Automation with ExtendScript](#host-app-automation-with-extendscript) - 1. [Create an ExtendScript function](#create-an-extendscript-function) 1. [Server-side: Setup](#server-side-setup) - 1. [Install Node.js and npm](#install-nodejs-and-npm) - 1. [Install node modules](#install-node-modules) - 1. [Write server logic in `main.js`](#write-server-logic-in-mainjs) 1. [Troubleshooting and Known Issues](#troubleshooting-and-known-issues) 1. [Other Resources](#other-resources)