@blockquote-web-components/ajax-provider 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 ajax-provider
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,359 @@
1
+ # AJAX Provider Documentation
2
+
3
+ A class that provides AJAX functionality with event handling capabilities.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Introduction](#introduction)
8
+ - [Installation](#installation)
9
+ - [Usage](#usage)
10
+ - [Creating an Instance](#creating-an-instance)
11
+ - [Configuring AJAX Requests](#configuring-ajax-requests)
12
+ - [Sending AJAX Requests](#sending-ajax-requests)
13
+ - [Event Handling](#event-handling)
14
+ - [API Reference](#api-reference)
15
+
16
+ ## Introduction
17
+
18
+ The AJAX Provider is a JavaScript class that provides AJAX functionality with event handling capabilities through [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget). It uses the `AjaxProviderMixin`, a mixin that leverages RxJS to manage AJAX requests efficiently.
19
+
20
+ ## Installation
21
+
22
+ To use the AJAX Provider, you need to install it as a package dependency.
23
+
24
+ ```bash
25
+ npm install @blockquote-web-components/ajax-provider
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ### Creating an Instance
31
+
32
+ To use the AJAX Provider, first, create an instance of the `AjaxProvider` class.
33
+
34
+ ```js
35
+ import { AjaxProvider } from '@blockquote-web-components/ajax-provider';
36
+
37
+ // A basic request configuration looks like this:
38
+ const ajaxProvider = new AjaxProvider({
39
+ url: 'https://httpbin.org/get',
40
+ });
41
+ ```
42
+
43
+ ```js
44
+ // Default method
45
+ method: 'GET',
46
+
47
+ // Default request Headers.
48
+ headers: {
49
+ Accept: 'application/json, text/plain, *\/*; q=0.01',
50
+ 'Content-Type': 'application/json',
51
+ }
52
+ ```
53
+
54
+ ### Configuring AJAX Requests
55
+
56
+ You can configure your AJAX request by setting various options on the `ajaxProvider` instance. Here are some common configuration options:
57
+
58
+ ```js
59
+ const ajaxProvider = new AjaxProvider({
60
+ url: 'https://httpbin.org/get',
61
+ path: method.toLowerCase(),
62
+ method: 'POST',
63
+ headers: {
64
+ 'Content-Type': 'application/json',
65
+ 'rxjs-custom-header': 'Rxjs',
66
+ },
67
+ body: {
68
+ rxjs: `Hi`,
69
+ },
70
+ includeDownloadProgress: true,
71
+ includeUploadProgress: true,
72
+ });
73
+ ```
74
+
75
+ ### Sending AJAX Requests
76
+
77
+ Once you have configured the AJAX request, you can send it using the `generateRequest` method. This method returns a promise that resolves with the AJAX response or attaching event listeners to handle various stages of the AJAX request.
78
+
79
+ ```js
80
+ const ajaxProvider = new AjaxProvider({
81
+ url: 'https://api.github.com/users',
82
+ queryParams: 'per_page=4',
83
+ });
84
+
85
+ ajaxProvider
86
+ .generateRequest()
87
+ .then(response => {
88
+ console.log('Response:', response.response);
89
+ })
90
+ .catch(error => {
91
+ console.log('Error:', error.message);
92
+ });
93
+ ```
94
+
95
+ ### Event Handling
96
+
97
+ The AJAX Provider allows you to handle events related to HTTP requests. You can listen to events such as:
98
+
99
+ - `'presend'` --> `'progress'` --> `'response'` --> `'responseend'`
100
+ - `'presend'` --> `'error'` --> `'errorend'`
101
+
102
+ Here's how to set up event listeners:
103
+
104
+ ```js
105
+ const ajaxProvider = new AjaxProvider({
106
+ url: 'https://api.github.com/users',
107
+ queryParams: 'per_page=3',
108
+ });
109
+
110
+ ajaxProvider.addEventListener('ajaxpresend', ({ detail }) => {
111
+ console.log('Preparing to send request...', detail);
112
+ });
113
+
114
+ ajaxProvider.addEventListener('ajaxprogress', ({ detail }) => {
115
+ console.log(`Progress: ${detail.loaded} of ${detail.total} bytes`);
116
+ });
117
+
118
+ ajaxProvider.addEventListener('ajaxresponse', ({ detail }) => {
119
+ const { response } = detail;
120
+ console.log('Received response:', response);
121
+ });
122
+
123
+ ajaxProvider.addEventListener('ajaxresponseend', ({ detail }) => {
124
+ console.log('End request:', detail);
125
+ });
126
+
127
+ ajaxProvider.addEventListener('ajaxerror', ({ detail }) => {
128
+ const error = detail;
129
+ console.log('Request error:', error.message);
130
+ });
131
+
132
+ ajaxProvider.addEventListener('ajaxerrorend', ({ detail }) => {
133
+ console.log('End error:', detail);
134
+ });
135
+
136
+ ajaxProvider.generateRequest();
137
+ ```
138
+
139
+ ## API Reference
140
+
141
+ Requests can be made by passing the relevant config to `AjaxProvider`.
142
+
143
+ #### Properties
144
+
145
+ #### [Configuration for the RxJS/ajax creation function.](https://rxjs.dev/api/ajax/AjaxConfig)
146
+
147
+ - `url`: The base URL for the AJAX request. _(string)_
148
+ - `body`: The request body. (\*)
149
+ - `async`: Whether or not to send the request asynchronously. _(boolean)_
150
+ - Default value: `true`
151
+ - `method`: The HTTP request method (e.g., GET, POST). _(string)_
152
+ - Default value: `GET`
153
+ - `headers`: Custom headers for the request. _(Object|undefined)_
154
+ - Default value:
155
+ - Accept: 'application/json, text/plain, *\/*; q=0.01'
156
+ - Content-Type: 'application/json'
157
+ - `timeout`: The request timeout in milliseconds. _(number)_
158
+ - Default value: `0`
159
+ - `user`: The user for authentication. _(string)_
160
+ - `password`: The password for authentication. _(string)_
161
+ - `withCredentials`: Indicates whether to include credentials with the request. _(boolean)_
162
+ - Default value: `false`
163
+ - `xsrfCookieName`: The name of the XSRF cookie. _(string)_
164
+ - `xsrfHeaderName`: The name of the XSRF header. _(string)_
165
+ - `responseType`: The response type (e.g., 'json', 'text'). _(string)_
166
+ - Default value: `json`
167
+ - `queryParams`: The query parameters to include in the request URL. _(Object|undefined)_
168
+ - `includeDownloadProgress`: Indicates whether to include download progress in the response. _(boolean)_
169
+ - Default value: `false`
170
+ - `includeUploadProgress`: Indicates whether to include upload progress in the response. _(boolean)_
171
+ - Default value: `false`
172
+
173
+ #### Configuration `AJAX Provider`.
174
+
175
+ - `path`: The path to append to the base URL. _(string)_
176
+ - `dispatchEventContext`: The context for dispatching events. _(AjaxProvider instance)_
177
+ - `lastResponse`: The last AJAX response object. _(Object)_
178
+ - `lastError`: The last error object. _(Object)_
179
+ - `customEventPrefix`: A custom event prefix for events related to HTTP requests. _(string)_
180
+ - Default value: `ajax`
181
+ - `avoidBoundary`: Set to `true` to stop delegating the use of [boundaries for multipart requests to the browser](https://github.com/axios/axios/issues/4631). _(boolean)_
182
+ - Only change this to `true` if you know what you are doing.
183
+ Default value: `false`
184
+
185
+ #### Methods
186
+
187
+ - `generateRequest()`: Generates and sends the AJAX request. This method can be used both with promises and by attaching event listeners to handle various stages of the AJAX request.
188
+
189
+
190
+ ### `src/AjaxProvider.js`:
191
+
192
+ #### class: `AjaxProvider`
193
+
194
+ ##### Mixins
195
+
196
+ | Name | Module | Package |
197
+ | ------------------- | ------------------------- | ------- |
198
+ | `AjaxProviderMixin` | /src/AjaxProviderMixin.js | |
199
+
200
+ ##### Fields
201
+
202
+ | Name | Privacy | Type | Default | Description | Inherited From |
203
+ | ------------------------- | ------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
204
+ | `dispatchEventContext` | | `Object` | `this` | The context for dispatching events. | |
205
+ | `lastResponse` | | `Object` | `undefined` | The last AJAX response object. | |
206
+ | `lastError` | | `Object` | `undefined` | The last error object. | |
207
+ | `customEventPrefix` | | `string` | `'ajax'` | A custom event prefix for events related to HTTP requests. | |
208
+ | `avoidBoundary` | | `boolean` | `false` | Set to \`true\` to stop delegating the use of boundaries for multipart requests to the browser.
Only change this to \`true\` if you know what you are doing. | |
209
+ | `url` | | `string` | `''` | The base URL for the AJAX request. | AjaxProviderMixin |
210
+ | `path` | | `string` | `''` | The path to append to the base URL. | AjaxProviderMixin |
211
+ | `body` | | `*` | `undefined` | The request body. | AjaxProviderMixin |
212
+ | `async` | | `boolean` | `true` | Whether or not to send the request asynchronously. | AjaxProviderMixin |
213
+ | `method` | | `string` | `'GET'` | The HTTP request method (e.g., GET, POST). | AjaxProviderMixin |
214
+ | `_headers` | | `Object` | `{ Accept: 'application/json, text/plain, */*; q=0.01', 'Content-Type': 'application/json', }` | The default headers for the request. | AjaxProviderMixin |
215
+ | `headers` | | `Object\|undefined` | `undefined` | Custom headers for the request. | AjaxProviderMixin |
216
+ | `timeout` | | `number` | `0` | The request timeout in milliseconds. | AjaxProviderMixin |
217
+ | `user` | | `string` | `''` | The user for authentication. | AjaxProviderMixin |
218
+ | `password` | | `string` | `''` | The password for authentication. | AjaxProviderMixin |
219
+ | `withCredentials` | | `boolean` | `false` | Indicates whether to include credentials with the request. | AjaxProviderMixin |
220
+ | `xsrfCookieName` | | `string` | `''` | The name of the XSRF cookie. | AjaxProviderMixin |
221
+ | `xsrfHeaderName` | | `string` | `''` | The name of the XSRF header. | AjaxProviderMixin |
222
+ | `responseType` | | `string` | `''` | The response type (e.g., 'json', 'text'). | AjaxProviderMixin |
223
+ | `queryParams` | | `Object\|undefined` | `undefined` | The query parameters to include in the request URL. | AjaxProviderMixin |
224
+ | `includeDownloadProgress` | | `boolean` | `false` | Indicates whether to include download progress in the response. | AjaxProviderMixin |
225
+ | `includeUploadProgress` | | `boolean` | `false` | Indicates whether to include upload progress in the response. | AjaxProviderMixin |
226
+
227
+ ##### Methods
228
+
229
+ | Name | Privacy | Description | Parameters | Return | Inherited From |
230
+ | --------------------------- | ------- | ----------------------------------------------------------- | ---------------- | -------------- | ----------------- |
231
+ | `_assignAjaxProviderConfig` | | Assigns configuration options to the AjaxProvider instance. | `config: Object` | | |
232
+ | `generateRequest` | | Generates and sends the AJAX request. | | `Promise<any>` | AjaxProviderMixin |
233
+
234
+ <details><summary>Private API</summary>
235
+
236
+ ##### Methods
237
+
238
+ | Name | Privacy | Description | Parameters | Return | Inherited From |
239
+ | ----------------------- | ------- | --------------------------------------------------------------- | -------------------------- | -------- | ----------------- |
240
+ | `_assignAjaxRxjsConfig` | private | Assigns the configuration settings for the AJAX request. | | `Object` | AjaxProviderMixin |
241
+ | `_joinUrlData` | private | Joins the base URL and path to create the complete request URL. | | `string` | AjaxProviderMixin |
242
+ | `_joinHeaders` | private | Joins the default headers with custom headers. | `formData` | `Object` | AjaxProviderMixin |
243
+ | `_dispatchEvent` | private | Dispatches a custom event with the specified type and payload. | `type: string, payload: *` | | AjaxProviderMixin |
244
+
245
+ </details>
246
+
247
+ <hr/>
248
+
249
+ #### Exports
250
+
251
+ | Kind | Name | Declaration | Module | Package |
252
+ | ---- | -------------- | ------------ | ------------------- | ------- |
253
+ | `js` | `AjaxProvider` | AjaxProvider | src/AjaxProvider.js | |
254
+
255
+ Mixin for providing AJAX functionality using RxJS. This mixin can be used to enhance classes with AJAX capabilities.
256
+
257
+
258
+ ### `src/AjaxProviderMixin.js`:
259
+
260
+ #### mixin: `AjaxProviderMixin`
261
+
262
+ ##### Mixins
263
+
264
+ | Name | Module | Package |
265
+ | ------------- | ------ | --------------------- |
266
+ | `dedupeMixin` | | @open-wc/dedupe-mixin |
267
+
268
+ ##### Parameters
269
+
270
+ | Name | Type | Default | Description |
271
+ | ------ | ---- | ------- | ----------- |
272
+ | `Base` | | | |
273
+
274
+ ##### Fields
275
+
276
+ | Name | Privacy | Type | Default | Description | Inherited From |
277
+ | ------------------------- | ------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | -------------- |
278
+ | `url` | | `string` | `''` | The base URL for the AJAX request. | |
279
+ | `path` | | `string` | `''` | The path to append to the base URL. | |
280
+ | `body` | | `*` | `undefined` | The request body. | |
281
+ | `async` | | `boolean` | `true` | Whether or not to send the request asynchronously. | |
282
+ | `method` | | `string` | `'GET'` | The HTTP request method (e.g., GET, POST). | |
283
+ | `_headers` | | `Object` | `{ Accept: 'application/json, text/plain, */*; q=0.01', 'Content-Type': 'application/json', }` | The default headers for the request. | |
284
+ | `headers` | | `Object\|undefined` | `undefined` | Custom headers for the request. | |
285
+ | `timeout` | | `number` | `0` | The request timeout in milliseconds. | |
286
+ | `user` | | `string` | `''` | The user for authentication. | |
287
+ | `password` | | `string` | `''` | The password for authentication. | |
288
+ | `withCredentials` | | `boolean` | `false` | Indicates whether to include credentials with the request. | |
289
+ | `xsrfCookieName` | | `string` | `''` | The name of the XSRF cookie. | |
290
+ | `xsrfHeaderName` | | `string` | `''` | The name of the XSRF header. | |
291
+ | `responseType` | | `string` | `''` | The response type (e.g., 'json', 'text'). | |
292
+ | `queryParams` | | `Object\|undefined` | `undefined` | The query parameters to include in the request URL. | |
293
+ | `includeDownloadProgress` | | `boolean` | `false` | Indicates whether to include download progress in the response. | |
294
+ | `includeUploadProgress` | | `boolean` | `false` | Indicates whether to include upload progress in the response. | |
295
+
296
+ ##### Methods
297
+
298
+ | Name | Privacy | Description | Parameters | Return | Inherited From |
299
+ | ----------------- | ------- | ------------------------------------- | ---------- | -------------- | -------------- |
300
+ | `generateRequest` | | Generates and sends the AJAX request. | | `Promise<any>` | |
301
+
302
+ <details><summary>Private API</summary>
303
+
304
+ ##### Methods
305
+
306
+ | Name | Privacy | Description | Parameters | Return | Inherited From |
307
+ | ----------------------- | ------- | --------------------------------------------------------------- | -------------------------- | -------- | -------------- |
308
+ | `_assignAjaxRxjsConfig` | private | Assigns the configuration settings for the AJAX request. | | `Object` | |
309
+ | `_joinUrlData` | private | Joins the base URL and path to create the complete request URL. | | `string` | |
310
+ | `_joinHeaders` | private | Joins the default headers with custom headers. | `formData` | `Object` | |
311
+ | `_dispatchEvent` | private | Dispatches a custom event with the specified type and payload. | `type: string, payload: *` | | |
312
+
313
+ </details>
314
+
315
+ <hr/>
316
+
317
+ #### Exports
318
+
319
+ | Kind | Name | Declaration | Module | Package |
320
+ | ---- | ------------------- | ----------------- | ------------------------ | ------- |
321
+ | `js` | `AjaxProviderMixin` | AjaxProviderMixin | src/AjaxProviderMixin.js | |
322
+
323
+ ### `src/utils.js`:
324
+
325
+ #### Variables
326
+
327
+ | Name | Description | Type |
328
+ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
329
+ | `isStandardBrowserEnv` | Determines if the code is running in a standard browser environment.&#xA;&#xA;This function checks for specific conditions that indicate whether the code is&#xA;running in a standard browser environment, allowing Axios to work in various&#xA;environments like web workers, React Native, or NativeScript. | |
330
+ | `isStandardBrowserWebWorkerEnv` | Determines if the code is running in a standard browser WebWorker environment.&#xA;&#xA;This function checks for specific conditions that indicate whether the code is&#xA;running in a standard browser WebWorker environment. It takes into account the&#xA;limitations of the \`isStandardBrowserEnv\` method when working with WebWorkers. | |
331
+
332
+ <hr/>
333
+
334
+ #### Functions
335
+
336
+ | Name | Description | Parameters | Return |
337
+ | ----------------- | --------------------------------------------------------------------------- | ------------------------------------- | --------- |
338
+ | `isFormData` | Determine if a value is a FormData | `thing: *` | `boolean` |
339
+ | `assignIfDefined` | Utility function to assign a property to an object if the value is defined. | `obj: Object, prop: string, value: *` | |
340
+
341
+ <hr/>
342
+
343
+ #### Exports
344
+
345
+ | Kind | Name | Declaration | Module | Package |
346
+ | ---- | ------------------------------- | ----------------------------- | ------------ | ------- |
347
+ | `js` | `isStandardBrowserEnv` | isStandardBrowserEnv | src/utils.js | |
348
+ | `js` | `isStandardBrowserWebWorkerEnv` | isStandardBrowserWebWorkerEnv | src/utils.js | |
349
+ | `js` | `isFormData` | isFormData | src/utils.js | |
350
+ | `js` | `assignIfDefined` | assignIfDefined | src/utils.js | |
351
+
352
+ ### `index.js`:
353
+
354
+ #### Exports
355
+
356
+ | Kind | Name | Declaration | Module | Package |
357
+ | ---- | ------------------- | ----------------- | -------------------------- | ------- |
358
+ | `js` | `AjaxProvider` | AjaxProvider | ./src/AjaxProvider.js | |
359
+ | `js` | `AjaxProviderMixin` | AjaxProviderMixin | ./src/AjaxProviderMixin.js | |
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { AjaxProvider } from './src/AjaxProvider.js';
2
+ export { AjaxProviderMixin } from './src/AjaxProviderMixin.js';
package/package.json ADDED
@@ -0,0 +1,159 @@
1
+ {
2
+ "name": "@blockquote-web-components/ajax-provider",
3
+ "version": "1.0.0",
4
+ "description": "Webcomponent ajax-provider following open-wc recommendations",
5
+ "keywords": [
6
+ "lit",
7
+ "web-component",
8
+ "lit-element"
9
+ ],
10
+ "license": "MIT",
11
+ "author": "ajax-provider",
12
+ "type": "module",
13
+ "exports": {
14
+ ".": {
15
+ "default": "./index.js"
16
+ },
17
+ "./package.json": {
18
+ "default": "./package.json"
19
+ },
20
+ "./src/AjaxProviderMixin.js": {
21
+ "default": "./src/AjaxProviderMixin.js"
22
+ },
23
+ "./define/ajax-provider.js": {
24
+ "default": "./define/ajax-provider.js"
25
+ },
26
+ "./index.js": {
27
+ "default": "./index.js"
28
+ }
29
+ },
30
+ "main": "index.js",
31
+ "module": "index.js",
32
+ "files": [
33
+ "/src/",
34
+ "index.js"
35
+ ],
36
+ "scripts": {
37
+ "analyze": "cem analyze --litelement --globs \"{src,define}/**/*.{js,ts}\" \"index.js\"",
38
+ "analyze:doc": "npm run analyze && npx web-component-analyzer \"{src,define}/**/*.{js,ts}\" \"index.js\" \"README.js\" --outFile README.md",
39
+ "build": "echo \"This is not a TypeScript project, so no need to build.\"",
40
+ "dev:vite": "vite build",
41
+ "format": "npm run format:eslint && npm run format:prettier && npm run format:stylelint",
42
+ "format:eslint": "eslint \"**/*.{js,ts,html}\" --fix --ignore-path .eslintignore",
43
+ "format:prettier": "prettier \"**/*.{js,ts,json,html}\" --write --ignore-path .eslintignore",
44
+ "format:stylelint": "stylelint \"**/*.{scss,css}\" --fix --allow-empty-input --ignore-path .eslintignore",
45
+ "postinstall": "npm run sort:package",
46
+ "lint": "npm run lint:eslint && npm run lint:prettier && npm run lint:stylelint",
47
+ "lint:eslint": "eslint \"**/*.{js,ts,html}\" --ignore-path .eslintignore",
48
+ "lint:prettier": "prettier \"**/*.{js,ts,json,html}\" --check --ignore-path .eslintignore",
49
+ "lint:stylelint": "stylelint \"**/*.{scss,css}\" --allow-empty-input --ignore-path .eslintignore",
50
+ "preview:vite": "vite preview",
51
+ "sass:watch": "sass-style-template",
52
+ "sort:package": "npx sort-package-json",
53
+ "start": "concurrently -k -r \"npm:sass:watch\" \"npm:vite\"",
54
+ "test": "wtr --coverage",
55
+ "test:watch": "wtr --watch",
56
+ "vite": "vite"
57
+ },
58
+ "lint-staged": {
59
+ "**/*.{js,ts,html}": [
60
+ "npm run format:eslint"
61
+ ],
62
+ "**/*.{js,ts,json,html}": [
63
+ "npm run format:prettier"
64
+ ],
65
+ "**/*.{scss,css}": [
66
+ "npm run format:stylelint"
67
+ ]
68
+ },
69
+ "prettier": {
70
+ "arrowParens": "avoid",
71
+ "printWidth": 100,
72
+ "singleQuote": true,
73
+ "trailingComma": "all",
74
+ "overrides": [
75
+ {
76
+ "files": "*.{scss,css}",
77
+ "options": {
78
+ "printWidth": 280,
79
+ "singleQuote": false
80
+ }
81
+ }
82
+ ]
83
+ },
84
+ "eslintConfig": {
85
+ "parserOptions": {
86
+ "ecmaVersion": "latest"
87
+ },
88
+ "extends": [
89
+ "@open-wc",
90
+ "prettier"
91
+ ],
92
+ "rules": {
93
+ "class-methods-use-this": "off",
94
+ "indent": [
95
+ "error",
96
+ 2,
97
+ {
98
+ "SwitchCase": 1,
99
+ "ignoredNodes": [
100
+ "PropertyDefinition",
101
+ "TemplateLiteral > *"
102
+ ]
103
+ }
104
+ ],
105
+ "no-unused-expressions": [
106
+ "error",
107
+ {
108
+ "allowShortCircuit": true,
109
+ "allowTernary": true
110
+ }
111
+ ],
112
+ "object-curly-newline": "off",
113
+ "import/extensions": [
114
+ "error",
115
+ "always",
116
+ {
117
+ "ignorePackages": true
118
+ }
119
+ ],
120
+ "import/no-extraneous-dependencies": [
121
+ "error",
122
+ {
123
+ "devDependencies": [
124
+ "**/test/**/*.{js,ts}",
125
+ "**/*.config.{js,ts,mjs,cjs}",
126
+ "**/*.conf.{js,ts,mjs,cjs}"
127
+ ]
128
+ }
129
+ ],
130
+ "import/no-unresolved": "off",
131
+ "import/prefer-default-export": "off",
132
+ "lit/no-native-attributes": "off"
133
+ }
134
+ },
135
+ "stylelint": {
136
+ "extends": "stylelint-config-standard-scss",
137
+ "rules": {
138
+ "custom-property-pattern": null,
139
+ "max-line-length": null,
140
+ "no-duplicate-selectors": null,
141
+ "color-function-notation": null,
142
+ "alpha-value-notation": null
143
+ }
144
+ },
145
+ "dependencies": {
146
+ "@open-wc/dedupe-mixin": "^1.4.0",
147
+ "lit": "^2.8.0",
148
+ "rxjs": "^8.0.0-alpha.12"
149
+ },
150
+ "devDependencies": {
151
+ "@alenaksu/json-viewer": "^2.0.1",
152
+ "@blockquote-web-components/blockquote-base-common-dev-dependencies": "^1.5.0"
153
+ },
154
+ "publishConfig": {
155
+ "access": "public"
156
+ },
157
+ "customElements": "custom-elements.json",
158
+ "gitHead": "1d99c84686394229dadc9d1e19f446588a33c8b6"
159
+ }
@@ -0,0 +1,247 @@
1
+ import { AjaxProviderMixin } from './AjaxProviderMixin.js';
2
+
3
+ /**
4
+ * # AJAX Provider Documentation
5
+ *
6
+ * A class that provides AJAX functionality with event handling capabilities.
7
+ *
8
+ * ## Table of Contents
9
+ *
10
+ * - [Introduction](#introduction)
11
+ * - [Installation](#installation)
12
+ * - [Usage](#usage)
13
+ * - [Creating an Instance](#creating-an-instance)
14
+ * - [Configuring AJAX Requests](#configuring-ajax-requests)
15
+ * - [Sending AJAX Requests](#sending-ajax-requests)
16
+ * - [Event Handling](#event-handling)
17
+ * - [API Reference](#api-reference)
18
+ *
19
+ * ## Introduction
20
+ *
21
+ * The AJAX Provider is a JavaScript class that provides AJAX functionality with event handling capabilities through [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget). It uses the `AjaxProviderMixin`, a mixin that leverages RxJS to manage AJAX requests efficiently.
22
+ *
23
+ * ## Installation
24
+ *
25
+ * To use the AJAX Provider, you need to install it as a package dependency.
26
+ *
27
+ * ```bash
28
+ * npm install @blockquote-web-components/ajax-provider
29
+ * ```
30
+ *
31
+ * ## Usage
32
+ *
33
+ * ### Creating an Instance
34
+ *
35
+ * To use the AJAX Provider, first, create an instance of the `AjaxProvider` class.
36
+ *
37
+ * ```js
38
+ * import { AjaxProvider } from '@blockquote-web-components/ajax-provider';
39
+ *
40
+ * // A basic request configuration looks like this:
41
+ * const ajaxProvider = new AjaxProvider({
42
+ * url: 'https://httpbin.org/get',
43
+ * });
44
+ * ```
45
+ *
46
+ * ```js
47
+ * // Default method
48
+ * method: 'GET',
49
+ *
50
+ * // Default request Headers.
51
+ * headers: {
52
+ * Accept: 'application/json, text/plain, *\/*; q=0.01',
53
+ * 'Content-Type': 'application/json',
54
+ * }
55
+ * ```
56
+ *
57
+ * ### Configuring AJAX Requests
58
+ *
59
+ * You can configure your AJAX request by setting various options on the `ajaxProvider` instance. Here are some common configuration options:
60
+ *
61
+ * ```js
62
+ * const ajaxProvider = new AjaxProvider({
63
+ * url: 'https://httpbin.org/get',
64
+ * path: method.toLowerCase(),
65
+ * method: 'POST',
66
+ * headers: {
67
+ * 'Content-Type': 'application/json',
68
+ * 'rxjs-custom-header': 'Rxjs',
69
+ * },
70
+ * body: {
71
+ * rxjs: `Hi`,
72
+ * },
73
+ * includeDownloadProgress: true,
74
+ * includeUploadProgress: true,
75
+ * });
76
+ * ```
77
+ *
78
+ * ### Sending AJAX Requests
79
+ *
80
+ * Once you have configured the AJAX request, you can send it using the `generateRequest` method. This method returns a promise that resolves with the AJAX response or attaching event listeners to handle various stages of the AJAX request.
81
+ *
82
+ * ```js
83
+ * const ajaxProvider = new AjaxProvider({
84
+ * url: 'https://api.github.com/users',
85
+ * queryParams: 'per_page=4',
86
+ * });
87
+ *
88
+ * ajaxProvider
89
+ * .generateRequest()
90
+ * .then(response => {
91
+ * console.log('Response:', response.response);
92
+ * })
93
+ * .catch(error => {
94
+ * console.log('Error:', error.message);
95
+ * });
96
+ * ```
97
+ *
98
+ * ### Event Handling
99
+ *
100
+ * The AJAX Provider allows you to handle events related to HTTP requests. You can listen to events such as:
101
+ *
102
+ * - `'presend'` --> `'progress'` --> `'response'` --> `'responseend'`
103
+ * - `'presend'` --> `'error'` --> `'errorend'`
104
+ *
105
+ * Here's how to set up event listeners:
106
+ *
107
+ * ```js
108
+ * const ajaxProvider = new AjaxProvider({
109
+ * url: 'https://api.github.com/users',
110
+ * queryParams: 'per_page=3',
111
+ * });
112
+ *
113
+ * ajaxProvider.addEventListener('ajaxpresend', ({ detail }) => {
114
+ * console.log('Preparing to send request...', detail);
115
+ * });
116
+ *
117
+ * ajaxProvider.addEventListener('ajaxprogress', ({ detail }) => {
118
+ * console.log(`Progress: ${detail.loaded} of ${detail.total} bytes`);
119
+ * });
120
+ *
121
+ * ajaxProvider.addEventListener('ajaxresponse', ({ detail }) => {
122
+ * const { response } = detail;
123
+ * console.log('Received response:', response);
124
+ * });
125
+ *
126
+ * ajaxProvider.addEventListener('ajaxresponseend', ({ detail }) => {
127
+ * console.log('End request:', detail);
128
+ * });
129
+ *
130
+ * ajaxProvider.addEventListener('ajaxerror', ({ detail }) => {
131
+ * const error = detail;
132
+ * console.log('Request error:', error.message);
133
+ * });
134
+ *
135
+ * ajaxProvider.addEventListener('ajaxerrorend', ({ detail }) => {
136
+ * console.log('End error:', detail);
137
+ * });
138
+ *
139
+ * ajaxProvider.generateRequest();
140
+ * ```
141
+ *
142
+ * ## API Reference
143
+ *
144
+ * Requests can be made by passing the relevant config to `AjaxProvider`.
145
+ *
146
+ * #### Properties
147
+ *
148
+ * #### [Configuration for the RxJS/ajax creation function.](https://rxjs.dev/api/ajax/AjaxConfig)
149
+ *
150
+ * - `url`: The base URL for the AJAX request. _(string)_
151
+ * - `body`: The request body. (\*)
152
+ * - `async`: Whether or not to send the request asynchronously. _(boolean)_
153
+ * - Default value: `true`
154
+ * - `method`: The HTTP request method (e.g., GET, POST). _(string)_
155
+ * - Default value: `GET`
156
+ * - `headers`: Custom headers for the request. _(Object|undefined)_
157
+ * - Default value:
158
+ * - Accept: 'application/json, text/plain, *\/*; q=0.01'
159
+ * - Content-Type: 'application/json'
160
+ * - `timeout`: The request timeout in milliseconds. _(number)_
161
+ * - Default value: `0`
162
+ * - `user`: The user for authentication. _(string)_
163
+ * - `password`: The password for authentication. _(string)_
164
+ * - `withCredentials`: Indicates whether to include credentials with the request. _(boolean)_
165
+ * - Default value: `false`
166
+ * - `xsrfCookieName`: The name of the XSRF cookie. _(string)_
167
+ * - `xsrfHeaderName`: The name of the XSRF header. _(string)_
168
+ * - `responseType`: The response type (e.g., 'json', 'text'). _(string)_
169
+ * - Default value: `json`
170
+ * - `queryParams`: The query parameters to include in the request URL. _(Object|undefined)_
171
+ * - `includeDownloadProgress`: Indicates whether to include download progress in the response. _(boolean)_
172
+ * - Default value: `false`
173
+ * - `includeUploadProgress`: Indicates whether to include upload progress in the response. _(boolean)_
174
+ * - Default value: `false`
175
+ *
176
+ * #### Configuration `AJAX Provider`.
177
+ *
178
+ * - `path`: The path to append to the base URL. _(string)_
179
+ * - `dispatchEventContext`: The context for dispatching events. _(AjaxProvider instance)_
180
+ * - `lastResponse`: The last AJAX response object. _(Object)_
181
+ * - `lastError`: The last error object. _(Object)_
182
+ * - `customEventPrefix`: A custom event prefix for events related to HTTP requests. _(string)_
183
+ * - Default value: `ajax`
184
+ * - `avoidBoundary`: Set to `true` to stop delegating the use of [boundaries for multipart requests to the browser](https://github.com/axios/axios/issues/4631). _(boolean)_
185
+ * - Only change this to `true` if you know what you are doing.
186
+ * Default value: `false`
187
+ *
188
+ * #### Methods
189
+ *
190
+ * - `generateRequest()`: Generates and sends the AJAX request. This method can be used both with promises and by attaching event listeners to handle various stages of the AJAX request.
191
+ */
192
+ export class AjaxProvider extends AjaxProviderMixin(EventTarget) {
193
+ /**
194
+ * Creates an instance of AjaxProvider.
195
+ * @param {Object} [config={}] - Configuration options for the AjaxProvider.
196
+ */
197
+ constructor(config = {}) {
198
+ super();
199
+
200
+ /**
201
+ * The context for dispatching events.
202
+ * @type {Object}
203
+ */
204
+ this.dispatchEventContext = this;
205
+
206
+ /**
207
+ * The last AJAX response object.
208
+ * @type {Object}
209
+ */
210
+ this.lastResponse = undefined;
211
+
212
+ /**
213
+ * The last error object.
214
+ * @type {Object}
215
+ */
216
+ this.lastError = undefined;
217
+
218
+ /**
219
+ * A custom event prefix for events related to HTTP requests.
220
+ * @type {string}
221
+ */
222
+ this.customEventPrefix = 'ajax';
223
+
224
+ /**
225
+ * Set to `true` to stop delegating the use of boundaries for multipart requests to the browser.
226
+ * Only change this to `true` if you know what you are doing.
227
+ * @type {boolean}
228
+ */
229
+ this.avoidBoundary = false;
230
+
231
+ /**
232
+ * Assigns configuration options to the AjaxProvider instance.
233
+ * @param {Object} options - Configuration options to be assigned.
234
+ */
235
+ this._assignAjaxProviderConfig(config);
236
+ }
237
+
238
+ /**
239
+ * Assigns configuration options to the AjaxProvider instance.
240
+ * @param {Object} config - Configuration config to be assigned.
241
+ */
242
+ _assignAjaxProviderConfig(config) {
243
+ if (config && typeof config === 'object') {
244
+ Object.assign(this, config);
245
+ }
246
+ }
247
+ }
@@ -0,0 +1,241 @@
1
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
2
+ import { lastValueFrom, catchError, tap } from 'rxjs';
3
+ import { ajax } from 'rxjs/ajax';
4
+ import { assignIfDefined, isFormData } from './utils.js';
5
+
6
+ /**
7
+ * Mixin for providing AJAX functionality using RxJS. This mixin can be used to enhance classes with AJAX capabilities.
8
+ */
9
+ const AjaxProvider = Base =>
10
+ // @ts-ignore
11
+ class AjaxProviderBase extends Base {
12
+ constructor() {
13
+ super();
14
+
15
+ /**
16
+ * The base URL for the AJAX request.
17
+ * @type {string}
18
+ */
19
+ this.url = '';
20
+
21
+ /**
22
+ * The path to append to the base URL.
23
+ * @type {string}
24
+ */
25
+ this.path = '';
26
+
27
+ /**
28
+ * The request body.
29
+ * @type {*}
30
+ */
31
+ this.body = undefined;
32
+
33
+ /**
34
+ * Whether or not to send the request asynchronously.
35
+ * @type {boolean}
36
+ */
37
+ this.async = true;
38
+
39
+ /**
40
+ * The HTTP request method (e.g., GET, POST).
41
+ * @type {string}
42
+ */
43
+ this.method = 'GET';
44
+
45
+ /**
46
+ * The default headers for the request.
47
+ * @type {Object}
48
+ */
49
+ this._headers = {
50
+ Accept: 'application/json, text/plain, */*; q=0.01',
51
+ 'Content-Type': 'application/json',
52
+ };
53
+
54
+ /**
55
+ * Custom headers for the request.
56
+ * @type {Object|undefined}
57
+ */
58
+ this.headers = undefined;
59
+
60
+ /**
61
+ * The request timeout in milliseconds.
62
+ * @type {number}
63
+ */
64
+ this.timeout = 0;
65
+
66
+ /**
67
+ * The user for authentication.
68
+ * @type {string}
69
+ */
70
+ this.user = '';
71
+
72
+ /**
73
+ * The password for authentication.
74
+ * @type {string}
75
+ */
76
+ this.password = '';
77
+
78
+ /**
79
+ * Indicates whether to include credentials with the request.
80
+ * @type {boolean}
81
+ */
82
+ this.withCredentials = false;
83
+
84
+ /**
85
+ * The name of the XSRF cookie.
86
+ * @type {string}
87
+ */
88
+ this.xsrfCookieName = '';
89
+
90
+ /**
91
+ * The name of the XSRF header.
92
+ * @type {string}
93
+ */
94
+ this.xsrfHeaderName = '';
95
+
96
+ /**
97
+ * The response type (e.g., 'json', 'text').
98
+ * @type {string}
99
+ */
100
+ this.responseType = '';
101
+
102
+ /**
103
+ * The query parameters to include in the request URL.
104
+ * @type {Object|undefined}
105
+ */
106
+ this.queryParams = undefined;
107
+
108
+ /**
109
+ * Indicates whether to include download progress in the response.
110
+ * @type {boolean}
111
+ */
112
+ this.includeDownloadProgress = false;
113
+
114
+ /**
115
+ * Indicates whether to include upload progress in the response.
116
+ * @type {boolean}
117
+ */
118
+ this.includeUploadProgress = false;
119
+ }
120
+
121
+ /**
122
+ * Assigns the configuration settings for the AJAX request.
123
+ *
124
+ * @returns {Object} config - Configuration for the ajax creation function.
125
+ * @private
126
+ */
127
+ _assignAjaxRxjsConfig() {
128
+ const config = {
129
+ url: this._joinUrlData(),
130
+ async: this.async,
131
+ method: this.method,
132
+ timeout: this.timeout,
133
+ withCredentials: this.withCredentials,
134
+ includeDownloadProgress: this.includeDownloadProgress,
135
+ includeUploadProgress: this.includeUploadProgress,
136
+ };
137
+
138
+ assignIfDefined(config, 'body', this.body);
139
+ assignIfDefined(config, 'headers', this._joinHeaders(this.body));
140
+ assignIfDefined(config, 'user', this.user);
141
+ assignIfDefined(config, 'password', this.password);
142
+ assignIfDefined(config, 'xsrfCookieName', this.xsrfHeaderName);
143
+ assignIfDefined(config, 'xsrfHeaderName', this.xsrfHeaderName);
144
+ assignIfDefined(config, 'responseType', this.responseType);
145
+ assignIfDefined(config, 'queryParams', this.queryParams);
146
+ return config;
147
+ }
148
+
149
+ /**
150
+ * Joins the base URL and path to create the complete request URL.
151
+ *
152
+ * @returns {string} The complete request URL or an empty string if not valid.
153
+ * @private
154
+ */
155
+ _joinUrlData() {
156
+ if (typeof this.url === 'string' && typeof this.path === 'string') {
157
+ if (this.url.length && this.path.length) {
158
+ return `${this.url}/${this.path}`;
159
+ }
160
+ return this.url;
161
+ }
162
+ return '';
163
+ }
164
+
165
+ /**
166
+ * Joins the default headers with custom headers.
167
+ *
168
+ * @returns {Object} Merged headers.
169
+ * @private
170
+ */
171
+ _joinHeaders(formData) {
172
+ const assignHeaders = { ...this._headers, ...(this.headers || {}) };
173
+
174
+ if (isFormData(formData) && !this.avoidBoundary) {
175
+ delete assignHeaders['Content-Type']; // Let the browser set it
176
+ }
177
+
178
+ return assignHeaders;
179
+ }
180
+
181
+ /**
182
+ * Dispatches a custom event with the specified type and payload.
183
+ *
184
+ * @param {string} type - The type of the custom event.
185
+ * @param {*} payload - The payload to include in the custom event.
186
+ * @private
187
+ */
188
+ _dispatchEvent(type, payload) {
189
+ if (this.dispatchEventContext) {
190
+ const event = new CustomEvent(`${this.customEventPrefix}${type}`, {
191
+ bubbles: true,
192
+ composed: true,
193
+ detail: payload,
194
+ });
195
+
196
+ this.dispatchEventContext.dispatchEvent(event);
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Generates and sends the AJAX request.
202
+ *
203
+ * @returns {Promise<any>} A promise that resolves with the AJAX response.
204
+ *
205
+ * @fires ajaxpresend - Fired before a request is sent.
206
+ * @fires ajaxprogress - Fired when some progress state is received.
207
+ * @fires ajaxresponse - Fired when a response is received.
208
+ * @fires ajaxresponseend - Fired after a response is received.
209
+ * @fires ajaxerror - Fired when an error is received.
210
+ * @fires ajaxerrorend - Fired after a error is received.
211
+ */
212
+ async generateRequest() {
213
+ this._dispatchEvent('presend', true);
214
+
215
+ const toPromise$ = await lastValueFrom(
216
+ ajax(this._assignAjaxRxjsConfig()).pipe(
217
+ tap(response => {
218
+ const setProgress = {
219
+ type: response.type,
220
+ loaded: response.loaded,
221
+ total: response.total,
222
+ };
223
+ this._dispatchEvent('progress', setProgress);
224
+ }),
225
+ catchError(error => {
226
+ this._dispatchEvent('error', error);
227
+ this._dispatchEvent('errorend', true);
228
+ this.lastError = error;
229
+ return Promise.reject(error);
230
+ }),
231
+ ),
232
+ );
233
+
234
+ this._dispatchEvent('response', toPromise$);
235
+ this._dispatchEvent('responseend', true);
236
+ this.lastResponse = toPromise$;
237
+ return toPromise$;
238
+ }
239
+ };
240
+
241
+ export const AjaxProviderMixin = dedupeMixin(AjaxProvider);
package/src/utils.js ADDED
@@ -0,0 +1,77 @@
1
+ /* c8 ignore start */
2
+
3
+ /**
4
+ * Determines if the code is running in a standard browser environment.
5
+ *
6
+ * This function checks for specific conditions that indicate whether the code is
7
+ * running in a standard browser environment, allowing Axios to work in various
8
+ * environments like web workers, React Native, or NativeScript.
9
+ *
10
+ * @returns {boolean} True if running in a standard browser environment, false otherwise.
11
+ */
12
+ export const isStandardBrowserEnv = (() => {
13
+ /**
14
+ * Check if the `navigator` object is defined, and if so, check the `product`
15
+ * property to see if it indicates a non-standard environment such as React Native
16
+ * or NativeScript.
17
+ */
18
+ if (typeof navigator !== 'undefined') {
19
+ const { product } = navigator;
20
+ return !(product === 'ReactNative' || product === 'NativeScript' || product === 'NS');
21
+ }
22
+
23
+ /**
24
+ * If the `navigator` object is undefined, check if `window` and `document` objects
25
+ * are defined, which are typical of standard browser environments.
26
+ */
27
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
28
+ })();
29
+
30
+ /**
31
+ * Determines if the code is running in a standard browser WebWorker environment.
32
+ *
33
+ * This function checks for specific conditions that indicate whether the code is
34
+ * running in a standard browser WebWorker environment. It takes into account the
35
+ * limitations of the `isStandardBrowserEnv` method when working with WebWorkers.
36
+ *
37
+ * @returns {boolean} True if running in a standard browser WebWorker environment, false otherwise.
38
+ */
39
+ export const isStandardBrowserWebWorkerEnv = (() =>
40
+ /**
41
+ * Check if the `WorkerGlobalScope` object is defined, and if so, verify that `self`
42
+ * is an instance of `WorkerGlobalScope` and that `importScripts` is a function.
43
+ * These conditions are typical of a standard browser WebWorker environment.
44
+ */
45
+ typeof WorkerGlobalScope !== 'undefined' &&
46
+ // eslint-disable-next-line no-undef, no-restricted-globals
47
+ self instanceof WorkerGlobalScope &&
48
+ // eslint-disable-next-line no-restricted-globals
49
+ typeof self.importScripts === 'function')();
50
+
51
+ /* c8 ignore stop */
52
+
53
+ /**
54
+ * Determine if a value is a FormData
55
+ *
56
+ * @param {*} thing The value to test
57
+ * @returns {boolean} True if value is an FormData, otherwise false
58
+ */
59
+ export const isFormData = thing =>
60
+ (thing && thing instanceof FormData) ||
61
+ (typeof thing === 'object' &&
62
+ typeof thing.append === 'function' /* c8 ignore next */ &&
63
+ Object.prototype.toString.call(thing) === '[object FormData]');
64
+
65
+ /**
66
+ * Utility function to assign a property to an object if the value is defined.
67
+ *
68
+ * @param {Object} obj - The object to which the property will be assigned.
69
+ * @param {string} prop - The property name.
70
+ * @param {*} value - The value to assign if it is defined.
71
+ */
72
+ export const assignIfDefined = (obj, prop, value) => {
73
+ if (value) {
74
+ // eslint-disable-next-line no-param-reassign
75
+ obj[prop] = value;
76
+ }
77
+ };