├── .forceignore
├── .github
├── CODEOWNERS
├── FUNDING.yml
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── config
└── project-scratch-def.json
├── force-app
├── main
│ ├── aura
│ │ └── LC_API
│ │ │ ├── LC_API.cmp
│ │ │ ├── LC_API.cmp-meta.xml
│ │ │ ├── LC_APIController.js
│ │ │ ├── LC_APIHelper.js
│ │ │ └── LC_APIRenderer.js
│ ├── classes
│ │ ├── LC_VisualforceDomainController.cls
│ │ └── LC_VisualforceDomainController.cls-meta.xml
│ ├── pages
│ │ ├── LC_APIPage.page
│ │ ├── LC_APIPage.page-meta.xml
│ │ ├── LC_VisualforceDomainPage.page
│ │ └── LC_VisualforceDomainPage.page-meta.xml
│ └── staticresources
│ │ ├── jsforce.resource
│ │ ├── jsforce.resource-meta.xml
│ │ ├── penpal.resource
│ │ └── penpal.resource-meta.xml
└── test
│ └── classes
│ ├── LC_VisualforceDomainControllerTest.cls
│ └── LC_VisualforceDomainControllerTest.cls-meta.xml
├── force-demo
└── main
│ ├── aura
│ ├── LC_FetchDemo
│ │ ├── LC_FetchDemo.cmp
│ │ ├── LC_FetchDemo.cmp-meta.xml
│ │ ├── LC_FetchDemo.design
│ │ └── LC_FetchDemoController.js
│ └── LC_RequestDemo
│ │ ├── LC_RequestDemo.cmp
│ │ ├── LC_RequestDemo.cmp-meta.xml
│ │ ├── LC_RequestDemo.design
│ │ └── LC_RequestDemoController.js
│ ├── flexipages
│ └── LC_Demo.flexipage-meta.xml
│ ├── permissionsets
│ └── LC_Demo.permissionset-meta.xml
│ └── tabs
│ └── LC_Demo.tab-meta.xml
├── package-lock.json
├── package.json
└── sfdx-project.json
/.forceignore:
--------------------------------------------------------------------------------
1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status
2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm
3 | #
4 |
5 | package.xml
6 | **/profiles
7 | **/applications/standard__*
8 |
9 | # LWC configuration files
10 | **/jsconfig.json
11 | **/.eslintrc.json
12 |
13 | # LWC Jest
14 | **/__tests__/**
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | #
2 | # Code Owners File Format
3 | # https://help.github.com/articles/about-code-owners/
4 | #
5 | # A CODEOWNERS file uses a pattern that follows the same rules used in gitignore files.
6 | # The pattern is followed by one or more GitHub usernames or team names using the
7 | # standard @username or @org/team-name format. You can also refer to a user by an
8 | # email address that has been added to their GitHub account, for example user@example.com.
9 | #
10 |
11 | * @douglascayers
12 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://www.paypal.me/douglascayers/ # Replace with a single custom sponsorship URL
13 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### What does this pull request do?
2 |
3 |
4 | ### What issues does this pull request fix or reference?
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Salesforce DX configuration files.
2 | .sfdx/
3 |
4 | # IlluminatedCloud configuration files.
5 | .idea/
6 | IlluminatedCloud/
7 | *.iml
8 |
9 | # Visual Studio Code configuration files.
10 | .vscode/
11 |
12 | # A temp directory where build scripts convert
13 | # source files to metadata format.
14 | mdapi/
15 |
16 | # NPM cache directory.
17 | node_modules/
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Salesforce Open Source Community Code of Conduct
2 |
3 | ## About the Code of Conduct
4 |
5 | Equality is a core value at Salesforce. We believe a diverse and inclusive
6 | community fosters innovation and creativity, and are committed to building a
7 | culture where everyone feels included.
8 |
9 | Salesforce open-source projects are committed to providing a friendly, safe, and
10 | welcoming environment for all, regardless of gender identity and expression,
11 | sexual orientation, disability, physical appearance, body size, ethnicity, nationality,
12 | race, age, religion, level of experience, education, socioeconomic status, or
13 | other similar personal characteristics.
14 |
15 | The goal of this code of conduct is to specify a baseline standard of behavior so
16 | that people with different social values and communication styles can work
17 | together effectively, productively, and respectfully in our open source community.
18 | It also establishes a mechanism for reporting issues and resolving conflicts.
19 |
20 | All questions and reports of abusive, harassing, or otherwise unacceptable behavior
21 | in a Salesforce open-source project may be reported by contacting the Salesforce
22 | Open Source Conduct Committee at ossconduct@salesforce.com.
23 |
24 | ## Our Pledge
25 |
26 | In the interest of fostering an open and welcoming environment, we as
27 | contributors and maintainers pledge to making participation in our project and
28 | our community a harassment-free experience for everyone, regardless of gender
29 | identity and expression, sexual orientation, disability, physical appearance,
30 | body size, ethnicity, nationality, race, age, religion, level of experience, education,
31 | socioeconomic status, or other similar personal characteristics.
32 |
33 | ## Our Standards
34 |
35 | Examples of behavior that contributes to creating a positive environment
36 | include:
37 |
38 | * Using welcoming and inclusive language
39 | * Being respectful of differing viewpoints and experiences
40 | * Gracefully accepting constructive criticism
41 | * Focusing on what is best for the community
42 | * Showing empathy toward other community members
43 |
44 | Examples of unacceptable behavior by participants include:
45 |
46 | * The use of sexualized language or imagery and unwelcome sexual attention or
47 | advances
48 | * Personal attacks, insulting/derogatory comments, or trolling
49 | * Public or private harassment
50 | * Publishing, or threatening to publish, others' private information—such as
51 | a physical or electronic address—without explicit permission
52 | * Other conduct which could reasonably be considered inappropriate in a
53 | professional setting
54 | * Advocating for or encouraging any of the above behaviors
55 |
56 | ## Our Responsibilities
57 |
58 | Project maintainers are responsible for clarifying the standards of acceptable
59 | behavior and are expected to take appropriate and fair corrective action in
60 | response to any instances of unacceptable behavior.
61 |
62 | Project maintainers have the right and responsibility to remove, edit, or
63 | reject comments, commits, code, wiki edits, issues, and other contributions
64 | that are not aligned with this Code of Conduct, or to ban temporarily or
65 | permanently any contributor for other behaviors that they deem inappropriate,
66 | threatening, offensive, or harmful.
67 |
68 | ## Scope
69 |
70 | This Code of Conduct applies both within project spaces and in public spaces
71 | when an individual is representing the project or its community. Examples of
72 | representing a project or community include using an official project email
73 | address, posting via an official social media account, or acting as an appointed
74 | representative at an online or offline event. Representation of a project may be
75 | further defined and clarified by project maintainers.
76 |
77 | ## Enforcement
78 |
79 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
80 | reported by contacting the Salesforce Open Source Conduct Committee
81 | at ossconduct@salesforce.com. All complaints will be reviewed and investigated
82 | and will result in a response that is deemed necessary and appropriate to the
83 | circumstances. The committee is obligated to maintain confidentiality with
84 | regard to the reporter of an incident. Further details of specific enforcement
85 | policies may be posted separately.
86 |
87 | Project maintainers who do not follow or enforce the Code of Conduct in good
88 | faith may face temporary or permanent repercussions as determined by other
89 | members of the project's leadership and the Salesforce Open Source Conduct
90 | Committee.
91 |
92 | ## Attribution
93 |
94 | This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home],
95 | version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html.
96 | It includes adaptions and additions from [Go Community Code of Conduct][golang-coc],
97 | [CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc].
98 |
99 | This Code of Conduct is licensed under the [Creative Commons Attribution 3.0 License][cc-by-3-us].
100 |
101 | [contributor-covenant-home]: https://www.contributor-covenant.org (https://www.contributor-covenant.org/)
102 | [golang-coc]: https://golang.org/conduct
103 | [cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md
104 | [microsoft-coc]: https://opensource.microsoft.com/codeofconduct/
105 | [cc-by-3-us]: https://creativecommons.org/licenses/by/3.0/us/
106 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Call REST API from Lightning Aura Components without Named Credentials
2 |
3 | A simple [promise-based](https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_promises.htm)
4 | [service component](https://developer.salesforce.com/blogs/2018/08/implement-and-use-lightning-service-components.html)
5 | for working with Salesforce REST API and JavaScript Fetch API
6 | directly from your aura component's JavaScript without you needing to
7 | write Apex or configure Named Credentials. Just install and use.
8 |
9 | ## 📝 Table of Contents
10 |
11 | * [Prerequisites](#-prerequisites)
12 | * [Getting Started](#-getting-started)
13 | * [Example Usage](#-example-usage)
14 | * [Sponsoring](#-sponsoring)
15 | * [Contributing](#-contributing)
16 | * [Troubleshooting](#-troubleshooting)
17 | * [Authors](#️-authors)
18 | * [Acknowledgements](#-acknowledgements)
19 | * [Other Utilities](#-other-utilities)
20 | * [License](#-license)
21 |
22 | ## 🚨 Prerequisites
23 |
24 | 1. Enable Lightning Experience
25 | 2. Enable My Domain
26 | 3. Allow IFraming of Visualforce Pages with Clickjack Protection
27 |
28 | You can find step-by-step instructions with screen shots in the [Mass Action Scheduler](https://github.com/douglascayers-org/sfdx-mass-action-scheduler/wiki/Prerequisites) wiki, which is my primary app that uses this component.
29 |
30 | ## 👋 Getting Started
31 |
32 | 1. Deploy this project to your org (you only need what's in `force-app` folder).
33 |
34 | ```
35 | git clone https://github.com/douglascayers/sfdx-lightning-api-component.git
36 |
37 | cd sfdx-lightning-api-component
38 |
39 | sfdx force:org:create -a lapi -s -f config/project-scratch-def.json
40 |
41 | sfdx force:source:deploy -u lapi -p force-app
42 | ```
43 |
44 | 2. Explore the `LC_RequestDemo` and `LC_FetchDemo` components in the `force-demo` folder on usage.
45 |
46 | 3. Try out a demo
47 |
48 | ```
49 | sfdx force:source:deploy -u lapi -p force-demo
50 |
51 | sfdx force:user:permset:assign -n LC_Demo
52 |
53 | sfdx force:org:open -u lapi -p //lightning/n/LC_Demo
54 | ```
55 |
56 | a. Assign yourself the **LC Demo** permission set.
57 |
58 | b. Navigate to the **LC Demo** tab.
59 |
60 | c. Play with the sample components to send different [REST API](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_what_is_rest_api.htm) and [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) requests.
61 |
62 | d. Marvel that you didn't have to write any Apex code or configure a Named Credential :)
63 |
64 | ## 📘 Example Usage
65 |
66 | Add the `` to your aura component and give it an `aura:id` for reference.
67 |
68 | ```xml
69 |
70 |
71 |
72 | ...
73 |
74 | ```
75 |
76 | Find the `` by its `aura:id` then call one of the request methods:
77 | * The `restRequest(..)` method passing in a JSON object with the `url`, `method`, `body`, and any `headers` properties, or
78 | * The `fetchRequest(..)` method passing in a JSON object with the `url` and `options` properties
79 |
80 | ```js
81 | // YourComponentController.js
82 | ({
83 | createAccount: function( component, event, helper ) {
84 |
85 | component.find( 'lc_api' ).restRequest({
86 | 'url' : '/services/data/v47.0/sobjects/Account',
87 | 'method' : 'post',
88 | 'body' : JSON.stringify({
89 | "Name" : "LC Demo Account"
90 | })
91 | }).then( $A.getCallback( function( response ) {
92 | // handle response
93 | // { id: "001f400000YEZB8AAP", success: true, errors: [] }
94 | })).catch( $A.getCallback( function( err ) {
95 | // handle error
96 | }));
97 |
98 | },
99 |
100 | getDataFromGist: function( component, event, helper ) {
101 |
102 | component.find( 'lc_api' ).fetchRequest({
103 | 'url' : 'https://gist.githubusercontent.com/douglascayers/e96c53304dc78dc83e59a85753f29111/raw/sfdx-mass-action-scheduler-version.js',
104 | 'options': {}
105 | }).then( $A.getCallback( function( response ) {
106 | // handle response
107 | })).catch( $A.getCallback( function( err ) {
108 | // handle error
109 | }));
110 |
111 | }
112 |
113 | })
114 | ```
115 |
116 | ## 💎 Sponsoring
117 |
118 | This project is a [free-as-in-speech](https://www.howtogeek.com/howto/31717/what-do-the-phrases-free-speech-vs.-free-beer-really-mean/) and [open source](https://opensource.com/resources/what-open-source) developed passion project of [Doug Ayers](https://douglascayers.com).
119 |
120 | If you've found value in my open source projects, please consider showing your support:
121 | * ⭐️ [Star](https://github.com/douglascayers/sfdx-lightning-api-component) this project on GitHub
122 | * 📣 [Tweet](https://twitter.com/intent/tweet/?url=https%3A%2F%2Fgithub.com%2Fdouglascayers%2Fsfdx-lightning-api-component&text=%E2%9A%A1%EF%B8%8F%20Use%20Salesforce%20REST%20API%20in%20Lightning%20Components%20without%20Named%20Credentials%20or%20Apex%20by%20%40DouglasCAyers&related=douglascayers%2Csalesforcedevs&hashtags=salesforce) this project to your followers
123 | * Contribute a ☕️ or 🌮 via my [virtual tip jar on PayPal](https://www.paypal.me/douglascayers/)
124 |
125 | Thank you! ❤️
126 |
127 | https://douglascayers.com/thanks-for-your-support/
128 |
129 | ## 🙏 Contributing
130 |
131 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
132 |
133 | For code contributions, please follow the [GitHub flow](https://help.github.com/en/articles/github-flow):
134 | 1. Fork this project and [install the source code](#-getting-started).
135 | 2. Create your feature branch (`git checkout -b feature/AmazingFeature`).
136 | 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`).
137 | 4. Push to your feature branch (`git push origin feature/AmazingFeature`).
138 | 5. Open a pull request to the `develop` branch.
139 |
140 | ## 🧐 Troubleshooting
141 |
142 | ### "Access Denied" or "No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://yourinstance.visualforce.com' is therefore not allowed access."
143 |
144 | Your request was blocked due to [Cross-Origin Resource Sharing (CORS) policy](https://help.salesforce.com/articleView?id=extend_code_cors.htm&type=5).
145 |
146 | This can happen when trying to make a request to `/services/apexrest/` endpoint.
147 | For example, the Visualforce domain hosting `LC_APIPage` is on `https://yourinstance.visualforce.com` and is trying to make a web request to `https://yourinstance.my.salesforce.com/services/apexrest/`.
148 | Because the two domains do not match, then CORS policy prevents the request.
149 |
150 | 1. In **Setup**, navigate to **Security | CORS**.
151 |
152 | 2. Add the origin URL mentioned in your error message (e.g. `https://yourinstance.visualforce.com`) to the list of whitelisted domains.
153 |
154 | ## ✍️ Authors
155 |
156 | [Doug Ayers](https://douglascayers.com) develops and maintains the project.
157 |
158 | See also the list of [contributors](https://github.com/douglascayers/sfdx-lightning-api-component/graphs/contributors) who participated in this project.
159 |
160 | ## 🎉 Acknowledgements
161 |
162 | [Penpal](https://github.com/Aaronius/penpal)
163 | for a secure, promise-based library for communicating between windows and iframes.
164 |
165 | [jsforce](https://jsforce.github.io/)
166 | for an elegant, promise-based library for working with Salesforce REST API.
167 |
168 | ## 🎈 Other Utilities
169 |
170 | You should check out [sfdc-lax](https://github.com/ruslan-kurchenko/sfdc-lax) by Ruslan Kurchenko,
171 | a promise-based service component that makes calling Apex actions or using Lightning Data Service a breeze.
172 |
173 | ## 👀 License
174 |
175 | The source code is licensed under the [BSD 3-Clause License](LICENSE)
176 |
--------------------------------------------------------------------------------
/config/project-scratch-def.json:
--------------------------------------------------------------------------------
1 | {
2 | "orgName" : "Lightning API",
3 | "edition" : "Developer",
4 | "features" : [],
5 | "settings" : {
6 | "mobileSettings" : {
7 | "enableS1EncryptedStoragePref2" : false
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/force-app/main/aura/LC_API/LC_API.cmp:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
11 |
12 |
16 |
17 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 |
65 |
66 |
70 |
71 |
72 |
96 |
97 |
101 |
102 |
103 |
104 | {!v.body}
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/force-app/main/aura/LC_API/LC_API.cmp-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 47.0
4 | LC_API
5 |
6 |
--------------------------------------------------------------------------------
/force-app/main/aura/LC_API/LC_APIController.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Doug Ayers
3 | Website: https://douglascayers.com
4 | GitHub: https://github.com/douglascayers/sfdx-lightning-api-component
5 | License: BSD 3-Clause License
6 | */
7 | ({
8 | /**
9 | * Called once during component initialization phase.
10 | */
11 | onInit: function( component, event, helper ) {
12 | helper._penpal = {};
13 | helper.makeApexRequest( component, 'c.getVisualforceDomainURL' ).then( $A.getCallback( function( vfDomainURL ) {
14 | component.set( 'v.iframeSrc', `${vfDomainURL}/apex/LC_APIPage` );
15 | })).catch( $A.getCallback( function( err ) {
16 | console.error( 'LC_API: Error determining visualforce domain', err );
17 | }));
18 | },
19 |
20 | /**
21 | * Called once after ltng:require has loaded scripts.
22 | */
23 | onScriptsLoaded: function( component, event, helper ) {
24 |
25 | },
26 |
27 | /**
28 | * Called each time the component renders itself.
29 | */
30 | onRender: function( component, event, helper ) {
31 |
32 | const isPenpalFrameCreated = component.get( 'v.penpalFrameCreated' );
33 |
34 | // For Penpal to operate correctly, you must ensure that `connectToChild`
35 | // is called before the iframe has called `connectToParent`.
36 | // Since the iframe source is calculated asynchronously,
37 | // we listen to the component's render events and each time
38 | // check if the iframe source is ready, and if so, then we initialize
39 | // penpal to connect this component to the iframe.
40 | // Since we only want to do this once, we also set the initialized flag.
41 | if ( !isPenpalFrameCreated ) {
42 |
43 | const container = component.find( 'penpalFrameContainer' );
44 | const iframeSrc = component.get( 'v.iframeSrc' );
45 |
46 | // Ensure the container element has rendered otherwise we can't
47 | // append child elements to it. And wait for the iframe source to
48 | // be available otherwise no reason to create the iframe element.
49 | if ( !$A.util.isEmpty( container ) && !$A.util.isEmpty( iframeSrc ) ) {
50 |
51 | $A.createComponent(
52 | "aura:html",
53 | {
54 | "aura:id": "penpalFrame",
55 | "tag": "iframe",
56 | "HTMLAttributes": {
57 | "src": iframeSrc
58 | }
59 | },
60 | function ( iframeCmp, status, errorMessage ) {
61 |
62 | // This callback happened asynchronously, so make one
63 | // more check on whether the penpal frame has been initialized or not
64 | // in the off chance a separate render cycle got here before this one.
65 | const isPenpalFrameCreated = component.get( 'v.penpalFrameCreated' );
66 |
67 | if ( isPenpalFrameCreated ) {
68 |
69 | console.log( 'LC_API: iframe is already initialized' );
70 |
71 | } else if ( status === 'SUCCESS' ) {
72 |
73 | // At this point, the iframe component has been constructed
74 | // but not yet been rendered, so we don't have access to the
75 | // HTML iframe element yet. We need to wait for another render cycle,
76 | // that is, we need to wait for the render() method to be called again
77 | // after we append the new iframe component to the body of its container.
78 | // Once we're able to find the 'penpalFrame' on the page then
79 | // we can proceed with the rest of the penpal initialization.
80 |
81 | component.set( 'v.penpalFrameCreated', true );
82 |
83 | container.set( 'v.body', [ iframeCmp ] );
84 |
85 | console.info( 'LC_API: iframe initialized' );
86 |
87 | } else if ( status === 'INCOMPLETE' ) {
88 |
89 | console.warn( 'LC_API: No response from server or client is offline' );
90 |
91 | } else if ( status === 'ERROR' ) {
92 |
93 | console.error( 'LC_API: Error creating iframe: ' + errorMessage );
94 |
95 | }
96 |
97 | }
98 | );
99 |
100 | } // else, iframe source is empty, keep waiting
101 |
102 | } else {
103 |
104 | const isPenpalFrameConnected = component.get( 'v.penpalFrameConnected' );
105 | const iframeCmp = component.find( 'penpalFrame' );
106 |
107 | if ( !$A.util.isEmpty( iframeCmp ) && !isPenpalFrameConnected ) {
108 |
109 | const connection = Penpal.connectToChild({
110 | // The iframe to which a connection should be made
111 | iframe: iframeCmp.getElement()
112 | });
113 |
114 | helper._penpal.connection = connection;
115 |
116 | connection.promise.then( $A.getCallback( function( child ) {
117 |
118 | // Cache a reference to the child so that we can
119 | // use it in the restRequest/fetchRequest methods,
120 | // as well as be able to destroy it when this component unrenders.
121 | helper._penpal.child = child;
122 | console.info( 'LC_API: connected to iframe ' + iframeCmp.getGlobalId() );
123 | component.set( 'v.penpalFrameConnected', true );
124 |
125 | })).catch( $A.getCallback( function( err ) {
126 |
127 | console.error( 'LC_API: Error establishing connection to iframe ' + iframeCmp.getGlobalId(), err );
128 | component.set( 'v.penpalFrameConnected', false );
129 |
130 | }));
131 |
132 | }
133 |
134 | }
135 |
136 | },
137 |
138 | onRestRequest: function( component, event, helper ) {
139 | const params = event.getParam( 'arguments' );
140 | return helper.handleRestRequest( component, params.request );
141 | },
142 |
143 | onFetchRequest: function( component, event, helper ) {
144 | const params = event.getParam( 'arguments' );
145 | return helper.handleFetchRequest( component, params.request );
146 | }
147 | })
148 | /*
149 | BSD 3-Clause License
150 |
151 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
152 | All rights reserved.
153 |
154 | Redistribution and use in source and binary forms, with or without
155 | modification, are permitted provided that the following conditions are met:
156 |
157 | * Redistributions of source code must retain the above copyright notice, this
158 | list of conditions and the following disclaimer.
159 |
160 | * Redistributions in binary form must reproduce the above copyright notice,
161 | this list of conditions and the following disclaimer in the documentation
162 | and/or other materials provided with the distribution.
163 |
164 | * Neither the name of the copyright holder nor the names of its
165 | contributors may be used to endorse or promote products derived from
166 | this software without specific prior written permission.
167 |
168 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
169 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
171 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
172 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
173 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
174 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
175 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
176 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
177 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
178 | */
--------------------------------------------------------------------------------
/force-app/main/aura/LC_API/LC_APIHelper.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Doug Ayers
3 | Website: https://douglascayers.com
4 | GitHub: https://github.com/douglascayers/sfdx-lightning-api-component
5 | License: BSD 3-Clause License
6 | */
7 | ({
8 | handleRestRequest: function( component, request ) {
9 |
10 | const helper = this;
11 |
12 | const defaultRequest = {
13 | 'method' : 'get'
14 | };
15 |
16 | const defaultHeaders = {
17 | 'Content-Type': 'application/json'
18 | };
19 |
20 | request = Object.assign( {}, defaultRequest, request );
21 | request.headers = Object.assign( {}, defaultHeaders, request.headers );
22 |
23 | return helper.getPenpalChild().then( $A.getCallback( function( child ) {
24 | return helper.makePenpalRequest( 'rest', child, request );
25 | }));
26 |
27 | },
28 |
29 | handleFetchRequest: function( component, request ) {
30 |
31 | const helper = this;
32 |
33 | return helper.getPenpalChild().then( $A.getCallback( function( child ) {
34 | return helper.makePenpalRequest( 'fetch', child, request );
35 | }));
36 |
37 | },
38 |
39 | // ------------------------------------------------------------
40 |
41 | /**
42 | * For internal use.
43 | * Returns a promise waiting for the parent-child penpal handshake to complete
44 | * then resolves with reference to the penpal child for making requests.
45 | */
46 | getPenpalChild: function() {
47 |
48 | const helper = this;
49 |
50 | return new Promise( $A.getCallback( function( resolve, reject ) {
51 |
52 | let child = helper._penpal.child;
53 |
54 | if ( child ) {
55 |
56 | resolve( child );
57 |
58 | } else {
59 |
60 | // all time values in milliseconds
61 | const timeout = 10000; // ten seconds
62 | const pollFrequency = 500; // half a second
63 | const startTime = new Date().getTime();
64 | const endTime = startTime + timeout;
65 |
66 | const timerId = setInterval( $A.getCallback( function() {
67 |
68 | child = helper._penpal.child;
69 |
70 | if ( child ) {
71 |
72 | // parent-child penpal handshake now complete
73 | clearInterval( timerId );
74 | resolve( child );
75 |
76 | } else {
77 |
78 | // check if we have exceeded our timeout
79 | const currentTime = new Date().getTime();
80 | if ( currentTime > endTime ) {
81 | clearInterval( timerId );
82 | reject( 'LC_API: Timeout trying to establish connection to iframe' );
83 | }
84 | // else, keep polling
85 |
86 | }
87 |
88 | }), pollFrequency );
89 |
90 | }
91 |
92 | }));
93 |
94 | },
95 |
96 | /**
97 | * For internal use.
98 | * Returns a promise waiting for the parent-child penpal request to complete
99 | * then resolves with response from the child iframe.
100 | */
101 | makePenpalRequest: function( requestType, child, request ) {
102 |
103 | let p;
104 |
105 | if ( requestType === 'rest' ) {
106 | p = child.restRequest( request );
107 | } else if ( requestType === 'fetch' ) {
108 | p = child.fetchRequest( request );
109 | } else {
110 | p = Promise.resolve({
111 | success: false,
112 | data: 'LC_API: Invalid request type: ' + requestType
113 | });
114 | }
115 |
116 | return p.then( $A.getCallback( function( response ) {
117 | if ( response.success ) {
118 | return response.data;
119 | } else {
120 | return Promise.reject( response.data );
121 | }
122 | }));
123 |
124 | },
125 |
126 | /**
127 | * For internal use.
128 | * Returns a promise waiting for the Apex request to complete
129 | * then resolves with the JSON response, or rejects if any error.
130 | *
131 | * @param component
132 | * (required) Reference to the component who has access to the Aura Enabled method specified by `actionName`.
133 | * @param actionName
134 | * (required) Name of the Aura Enabled Apex method in form `c.methodName`.
135 | * @param params
136 | * (optional) JSON map of request parameters to pass to the Apex action.
137 | * @param options
138 | * (optional) JSON map of options to customize the request.
139 | * `background` set to true will execute request in background thread.
140 | * `storable` set to true will cache the response.
141 | */
142 | makeApexRequest: function( component, actionName, params, options ) {
143 |
144 | const helper = this;
145 |
146 | return new Promise( $A.getCallback( function( resolve, reject ) {
147 |
148 | const action = component.get( actionName );
149 |
150 | if ( params ) {
151 | action.setParams( params );
152 | }
153 |
154 | if ( options ) {
155 | if ( options.background ) { action.setBackground(); }
156 | if ( options.storable ) { action.setStorable(); }
157 | }
158 |
159 | action.setCallback( helper, function( response ) {
160 | if ( component.isValid() && response.getState() === 'SUCCESS' ) {
161 |
162 | resolve( response.getReturnValue() );
163 |
164 | } else {
165 |
166 | console.error( 'Error calling action "' + actionName + '" with state: ' + response.getState() );
167 |
168 | helper.logActionErrors( response.getError() );
169 |
170 | reject( response.getError() );
171 |
172 | }
173 | });
174 |
175 | $A.enqueueAction( action );
176 |
177 | }));
178 |
179 | },
180 |
181 | /**
182 | * For internal use.
183 | * Logs to console errors object.
184 | * Errors may be a String or Array.
185 | */
186 | logActionErrors: function( errors ) {
187 | if ( errors ) {
188 | if ( errors.length > 0 ) {
189 | for ( var i = 0; i < errors.length; i++ ) {
190 | console.error( 'Error: ' + errors[i].message );
191 | }
192 | } else {
193 | console.error( 'Error: ' + errors );
194 | }
195 | } else {
196 | console.error( 'Unknown error' );
197 | }
198 | }
199 |
200 | })
201 | /*
202 | BSD 3-Clause License
203 |
204 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
205 | All rights reserved.
206 |
207 | Redistribution and use in source and binary forms, with or without
208 | modification, are permitted provided that the following conditions are met:
209 |
210 | * Redistributions of source code must retain the above copyright notice, this
211 | list of conditions and the following disclaimer.
212 |
213 | * Redistributions in binary form must reproduce the above copyright notice,
214 | this list of conditions and the following disclaimer in the documentation
215 | and/or other materials provided with the distribution.
216 |
217 | * Neither the name of the copyright holder nor the names of its
218 | contributors may be used to endorse or promote products derived from
219 | this software without specific prior written permission.
220 |
221 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
222 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
223 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
224 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
225 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
226 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
227 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
228 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
229 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
230 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
231 | */
232 |
--------------------------------------------------------------------------------
/force-app/main/aura/LC_API/LC_APIRenderer.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Doug Ayers
3 | Website: https://douglascayers.com
4 | GitHub: https://github.com/douglascayers/sfdx-lightning-api-component
5 | License: BSD 3-Clause License
6 | */
7 | ({
8 | unrender: function( component, helper ) {
9 | this.superUnrender();
10 | // When component unrenders then cleanup penpal
11 | // resources by destroying the connection and nulling out
12 | // the helper's cached reference to the connection and child.
13 | // This ensures that the helper.handleXyzRequest(..) methods
14 | // wait appropriately for the new parent-child handshake to complete
15 | // when this component is re-initialized and scripts are loaded.
16 | if ( helper._penpal && helper._penpal.connection ) {
17 | helper._penpal.connection.destroy();
18 | helper._penpal = {};
19 | }
20 | }
21 | })
22 | /*
23 | BSD 3-Clause License
24 |
25 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
26 | All rights reserved.
27 |
28 | Redistribution and use in source and binary forms, with or without
29 | modification, are permitted provided that the following conditions are met:
30 |
31 | * Redistributions of source code must retain the above copyright notice, this
32 | list of conditions and the following disclaimer.
33 |
34 | * Redistributions in binary form must reproduce the above copyright notice,
35 | this list of conditions and the following disclaimer in the documentation
36 | and/or other materials provided with the distribution.
37 |
38 | * Neither the name of the copyright holder nor the names of its
39 | contributors may be used to endorse or promote products derived from
40 | this software without specific prior written permission.
41 |
42 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
46 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
51 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 | */
--------------------------------------------------------------------------------
/force-app/main/classes/LC_VisualforceDomainController.cls:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Doug Ayers
3 | Website: https://douglascayers.com
4 | GitHub: https://github.com/douglascayers/sfdx-lightning-api-component
5 | License: BSD 3-Clause License
6 | */
7 | public with sharing class LC_VisualforceDomainController {
8 |
9 | // Aura Component
10 |
11 | @AuraEnabled( cacheable = true )
12 | public static String getVisualforceDomainURL() {
13 | PageReference vfPage = Page.LC_VisualforceDomainPage;
14 | return ( Test.isRunningTest() ? 'https://visualforce.com' : vfPage.getContent().toString().trim() );
15 | }
16 |
17 | // -----------------------------------------------------------------------------
18 |
19 | // Visualforce Page
20 |
21 | public String getDomainURL() {
22 | URL requestURL = URL.getCurrentRequestUrl();
23 | return requestURL.toExternalForm().substringBefore( requestURL.getPath() );
24 | }
25 |
26 | }
27 | /*
28 | BSD 3-Clause License
29 |
30 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
31 | All rights reserved.
32 |
33 | Redistribution and use in source and binary forms, with or without
34 | modification, are permitted provided that the following conditions are met:
35 |
36 | * Redistributions of source code must retain the above copyright notice, this
37 | list of conditions and the following disclaimer.
38 |
39 | * Redistributions in binary form must reproduce the above copyright notice,
40 | this list of conditions and the following disclaimer in the documentation
41 | and/or other materials provided with the distribution.
42 |
43 | * Neither the name of the copyright holder nor the names of its
44 | contributors may be used to endorse or promote products derived from
45 | this software without specific prior written permission.
46 |
47 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
51 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
54 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
55 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 | */
--------------------------------------------------------------------------------
/force-app/main/classes/LC_VisualforceDomainController.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 47.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/force-app/main/pages/LC_APIPage.page:
--------------------------------------------------------------------------------
1 |
7 |
10 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/force-app/main/pages/LC_APIPage.page-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 47.0
4 | false
5 | false
6 |
7 |
8 |
--------------------------------------------------------------------------------
/force-app/main/pages/LC_VisualforceDomainPage.page:
--------------------------------------------------------------------------------
1 |
7 | {!domainURL}
14 |
--------------------------------------------------------------------------------
/force-app/main/pages/LC_VisualforceDomainPage.page-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 47.0
4 | false
5 | false
6 |
7 |
8 |
--------------------------------------------------------------------------------
/force-app/main/staticresources/jsforce.resource-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Public
4 | application/javascript
5 | v1.9.3
6 | http://jsforce.github.io/
7 |
8 |
--------------------------------------------------------------------------------
/force-app/main/staticresources/penpal.resource:
--------------------------------------------------------------------------------
1 | /**
2 | * Author: Aaron Hardy
3 | * https://unpkg.com/penpal@4.1.1/dist/penpal.min.js
4 | * https://github.com/Aaronius/penpal
5 | */
6 | var Penpal=function(){"use strict";const e="handshake";const n="handshake-reply";const t="call";const r="reply";const o="fulfilled";const i="rejected";const c="message";const s="DataCloneError";const a="ConnectionDestroyed";const d="ConnectionTimeout";const l="NotInIframe";const u="NoIframeSrc";var m=()=>{const e=[];let n=false;return{destroy(){n=true;e.forEach(e=>{e()})},onDestroy(t){n?t():e.push(t)}}};const h={"http:":"80","https:":"443"};const f=/^(https?:)?\/\/([^\/:]+)?(:(\d+))?/;const g=["file:","data:"];var p=e=>{if(e&&g.find(n=>e.startsWith(n))){return"null"}const n=document.location;const t=f.exec(e);let r;let o;let i;if(t){r=t[1]?t[1]:n.protocol;o=t[2];i=t[4]}else{r=n.protocol;o=n.hostname;i=n.port}const c=i&&i!==h[r]?`:${i}`:"";return`${r}//${o}${c}`};var v=e=>{return function(){if(e){for(var n=arguments.length,t=new Array(n),r=0;r{let n=e.name,t=e.message,r=e.stack;return{name:n,message:t,stack:r}};const w=e=>{const n=new Error;Object.keys(e).forEach(t=>n[t]=e[t]);return n};var y=(e,n,a)=>{const d=e.localName,l=e.local,u=e.remote,m=e.originForSending,h=e.originForReceiving;let f=false;a(`${d}: Connecting call receiver`);const g=e=>{if(e.source!==u||e.data.penpal!==t){return}if(e.origin!==h){a(`${d} received message from origin ${e.origin} which did not match expected origin ${h}`);return}const c=e.data,l=c.methodName,g=c.args,p=c.id;a(`${d}: Received ${l}() call`);const v=e=>{return n=>{a(`${d}: Sending ${l}() reply`);if(f){a(`${d}: Unable to send ${l}() reply due to destroyed connection`);return}const t={penpal:r,id:p,resolution:e,returnValue:n};if(e===i&&n instanceof Error){t.returnValue=E(n);t.returnValueIsError=true}try{u.postMessage(t,m)}catch(e){if(e.name===s){u.postMessage({penpal:r,id:p,resolution:i,returnValue:E(e),returnValueIsError:true},m)}throw e}}};new Promise(e=>e(n[l].apply(n,g))).then(v(o),v(i))};l.addEventListener(c,g);return()=>{f=true;l.removeEventListener(c,g)}};let $=0;var N=()=>++$;var C=(e,n,i,s,d)=>{const l=n.localName,u=n.local,m=n.remote,h=n.originForSending,f=n.originForReceiving;let g=false;d(`${l}: Connecting call sender`);const p=e=>{return function(){for(var n=arguments.length,i=new Array(n),p=0;p{const a=N();const g=t=>{if(t.source!==m||t.data.penpal!==r||t.data.id!==a){return}if(t.origin!==f){d(`${l} received message from origin ${t.origin} which did not match expected origin ${f}`);return}d(`${l}: Received ${e}() reply`);u.removeEventListener(c,g);let i=t.data.returnValue;if(t.data.returnValueIsError){i=w(i)}(t.data.resolution===o?n:s)(i)};u.addEventListener(c,g);m.postMessage({penpal:t,id:a,methodName:e,args:i},h)})}};i.reduce((e,n)=>{e[n]=p(n);return e},e);return()=>{g=true}};const I=6e4;var T=t=>{let r=t.iframe,o=t.methods,i=o===void 0?{}:o,s=t.childOrigin,l=t.timeout,h=t.debug;const f=v(h);const g=window;const E=m(),w=E.destroy,$=E.onDestroy;if(!s){if(!r.src&&!r.srcdoc){const e=new Error("Iframe must have src or srcdoc property defined.");e.code=u;throw e}s=p(r.src)}const N=s==="null"?"*":s;const T=new Promise((t,o)=>{let u;if(l!==undefined){u=setTimeout(()=>{const e=new Error(`Connection to child timed out after ${l}ms`);e.code=d;o(e);w()},l)}const m={};let h;let p;const v=o=>{const c=r.contentWindow;if(o.source!==c||o.data.penpal!==e){return}if(o.origin!==s){f(`Parent received handshake from origin ${o.origin} which did not match expected origin ${s}`);return}f("Parent: Received handshake, sending reply");o.source.postMessage({penpal:n,methodNames:Object.keys(i)},N);const a={localName:"Parent",local:g,remote:c,originForSending:N,originForReceiving:s};if(p){p()}p=y(a,i,f);$(p);if(h){h.forEach(e=>{delete m[e]})}h=o.data.methodNames;const d=C(m,a,h,w,f);$(d);clearTimeout(u);t(m)};g.addEventListener(c,v);f("Parent: Awaiting handshake");var E=setInterval(()=>{if(!document.contains(r)){clearInterval(E);w()}},I);$(()=>{g.removeEventListener(c,v);clearInterval(E);const e=new Error("Connection destroyed");e.code=a;o(e)})});return{promise:T,destroy:w}};var k=function(){let t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{},r=t.parentOrigin,o=r===void 0?"*":r,i=t.methods,s=i===void 0?{}:i,u=t.timeout,h=t.debug;const f=v(h);if(window===window.top){const e=new Error("connectToParent() must be called within an iframe");e.code=l;throw e}const g=m(),p=g.destroy,E=g.onDestroy;const w=window;const $=w.parent;const N=new Promise((t,r)=>{let i;if(u!==undefined){i=setTimeout(()=>{const e=new Error(`Connection to parent timed out after ${u}ms`);e.code=d;r(e);p()},u)}const l=e=>{try{clearTimeout()}catch(e){return}if(e.source!==$||e.data.penpal!==n){return}if(o!=="*"&&o!==e.origin){f(`Child received handshake reply from origin ${e.origin} which did not match expected origin ${o}`);return}f("Child: Received handshake reply");w.removeEventListener(c,l);const r={localName:"Child",local:w,remote:$,originForSending:e.origin==="null"?"*":e.origin,originForReceiving:e.origin};const a={};const d=y(r,s,f);E(d);const u=C(a,r,e.data.methodNames,p,f);E(u);clearTimeout(i);t(a)};w.addEventListener(c,l);E(()=>{w.removeEventListener(c,l);const e=new Error("Connection destroyed");e.code=a;r(e)});f("Child: Sending handshake");$.postMessage({penpal:e,methodNames:Object.keys(s)},o)});return{promise:N,destroy:p}};var O={ERR_CONNECTION_DESTROYED:a,ERR_CONNECTION_TIMEOUT:d,ERR_NOT_IN_IFRAME:l,ERR_NO_IFRAME_SRC:u,connectToChild:T,connectToParent:k};return O}();
7 |
8 | // Expose penpal to lightning components by adding it to the `window` object.
9 | // https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_share_code.htm
10 | window.Penpal = Penpal;
11 |
12 | /*
13 | The MIT License (MIT)
14 |
15 | Copyright (c) 2016, Aaron Hardy
16 |
17 | Permission is hereby granted, free of charge, to any person obtaining a copy
18 | of this software and associated documentation files (the "Software"), to deal
19 | in the Software without restriction, including without limitation the rights
20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 | copies of the Software, and to permit persons to whom the Software is
22 | furnished to do so, subject to the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be included in all
25 | copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 | SOFTWARE.
34 | */
--------------------------------------------------------------------------------
/force-app/main/staticresources/penpal.resource-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Public
4 | application/javascript
5 | v4.1.1
6 | https://github.com/Aaronius/penpal
7 |
8 |
--------------------------------------------------------------------------------
/force-app/test/classes/LC_VisualforceDomainControllerTest.cls:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Doug Ayers
3 | Website: https://douglascayers.com
4 | GitHub: https://github.com/douglascayers/sfdx-lightning-api-component
5 | License: BSD 3-Clause License
6 | */
7 | @IsTest
8 | private class LC_VisualforceDomainControllerTest {
9 |
10 | // Aura Component
11 |
12 | @IsTest
13 | static void test_get_visualforce_domain_url() {
14 |
15 | Test.startTest();
16 |
17 | String vfDomainURL = LC_VisualforceDomainController.getVisualforceDomainURL();
18 |
19 | System.assertEquals( 'https://visualforce.com', vfDomainURL );
20 |
21 | Test.stopTest();
22 |
23 | }
24 |
25 | // -----------------------------------------------------------------------------
26 |
27 | // Visualforce Page
28 |
29 | @IsTest
30 | static void test_get_domain_url() {
31 |
32 | Test.setCurrentPage( Page.LC_VisualforceDomainPage );
33 |
34 | Test.startTest();
35 |
36 | LC_VisualforceDomainController controller = new LC_VisualforceDomainController();
37 |
38 | String domainURL = controller.getDomainURL();
39 |
40 | // The test is not running in Visualforce context,
41 | // so best we can get here is domain in Apex context.
42 | System.assertEquals( URL.getSalesforceBaseUrl().toExternalForm(), domainURL );
43 |
44 | Test.stopTest();
45 |
46 | }
47 |
48 | }
49 | /*
50 | BSD 3-Clause License
51 |
52 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
53 | All rights reserved.
54 |
55 | Redistribution and use in source and binary forms, with or without
56 | modification, are permitted provided that the following conditions are met:
57 |
58 | * Redistributions of source code must retain the above copyright notice, this
59 | list of conditions and the following disclaimer.
60 |
61 | * Redistributions in binary form must reproduce the above copyright notice,
62 | this list of conditions and the following disclaimer in the documentation
63 | and/or other materials provided with the distribution.
64 |
65 | * Neither the name of the copyright holder nor the names of its
66 | contributors may be used to endorse or promote products derived from
67 | this software without specific prior written permission.
68 |
69 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
70 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
71 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
72 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
73 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
74 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
75 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
76 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
77 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
78 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
79 | */
--------------------------------------------------------------------------------
/force-app/test/classes/LC_VisualforceDomainControllerTest.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 47.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/force-demo/main/aura/LC_FetchDemo/LC_FetchDemo.cmp:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
{!v.responseText}
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/force-demo/main/aura/LC_FetchDemo/LC_FetchDemo.cmp-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 47.0
4 | LC_FetchDemo
5 |
6 |
--------------------------------------------------------------------------------
/force-demo/main/aura/LC_FetchDemo/LC_FetchDemo.design:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
13 |
14 |
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/force-demo/main/aura/LC_FetchDemo/LC_FetchDemoController.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Doug Ayers
3 | Website: https://douglascayers.com
4 | GitHub: https://github.com/douglascayers/sfdx-lightning-api-component
5 | License: BSD 3-Clause License
6 | */
7 | ({
8 | onSubmitRequestConfirmed: function( component, event, helper ) {
9 |
10 | component.set( 'v.responseText', 'please wait...' );
11 |
12 | let url = component.get( 'v.url' );
13 | let method = component.get( 'v.httpMethod' );
14 | let body = component.get( 'v.requestBody' );
15 | let headers = component.get( 'v.requestHeaders' );
16 |
17 | component.find( 'lc_api' ).fetchRequest({
18 | 'url' : url,
19 | 'options' : {
20 | 'method' : method,
21 | 'body' : ( method.toLowerCase() === 'get' ) ? null : body,
22 | 'headers' : headers
23 | }
24 | }).then( $A.getCallback( function( response ) {
25 | component.set( 'v.responseIsError', false );
26 | component.set( 'v.responseText', JSON.stringify( response, null, 2 ) );
27 | })).catch( $A.getCallback( function( err ) {
28 | component.set( 'v.responseIsError', true );
29 | component.set( 'v.responseText', JSON.stringify( err, null, 2 ) );
30 | }));
31 |
32 | }
33 | })
34 | /*
35 | BSD 3-Clause License
36 |
37 | Copyright (c) 2018-2019, Doug Ayers, douglascayers.com
38 | All rights reserved.
39 |
40 | Redistribution and use in source and binary forms, with or without
41 | modification, are permitted provided that the following conditions are met:
42 |
43 | * Redistributions of source code must retain the above copyright notice, this
44 | list of conditions and the following disclaimer.
45 |
46 | * Redistributions in binary form must reproduce the above copyright notice,
47 | this list of conditions and the following disclaimer in the documentation
48 | and/or other materials provided with the distribution.
49 |
50 | * Neither the name of the copyright holder nor the names of its
51 | contributors may be used to endorse or promote products derived from
52 | this software without specific prior written permission.
53 |
54 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
55 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
57 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
58 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
60 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
61 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
62 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
63 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 | */
--------------------------------------------------------------------------------
/force-demo/main/aura/LC_RequestDemo/LC_RequestDemo.cmp:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |