expensify-common 2.0.188 → 2.0.190

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.
Files changed (78) hide show
  1. package/dist/Logger.js +11 -1
  2. package/dist/esm/API.d.ts +11 -0
  3. package/dist/esm/API.js +786 -0
  4. package/dist/esm/APIDeferred.d.ts +7 -0
  5. package/dist/esm/APIDeferred.js +216 -0
  6. package/dist/esm/BrowserDetect.d.ts +19 -0
  7. package/dist/esm/BrowserDetect.js +105 -0
  8. package/dist/esm/CLI.js +37 -29
  9. package/dist/esm/CONST.d.ts +1727 -0
  10. package/dist/esm/CONST.js +1847 -0
  11. package/dist/esm/Cookie.d.ts +68 -0
  12. package/dist/esm/Cookie.js +159 -0
  13. package/dist/esm/CredentialsWrapper.d.ts +32 -0
  14. package/dist/esm/CredentialsWrapper.js +46 -0
  15. package/dist/esm/Device.d.ts +8 -0
  16. package/dist/esm/Device.js +24 -0
  17. package/dist/esm/ExpenseRule.d.ts +39 -0
  18. package/dist/esm/ExpenseRule.js +77 -0
  19. package/dist/esm/ExpensiMark.d.ts +197 -0
  20. package/dist/esm/ExpensiMark.js +1374 -0
  21. package/dist/esm/Func.d.ts +40 -0
  22. package/dist/esm/Func.js +69 -0
  23. package/dist/esm/Log.d.ts +3 -0
  24. package/dist/esm/Log.js +35 -0
  25. package/dist/esm/Logger.d.ts +82 -0
  26. package/dist/esm/Logger.js +148 -0
  27. package/dist/esm/Network.d.ts +6 -0
  28. package/dist/esm/Network.js +168 -0
  29. package/dist/esm/Num.d.ts +95 -0
  30. package/dist/esm/Num.js +190 -0
  31. package/dist/esm/PageEvent.d.ts +25 -0
  32. package/dist/esm/PageEvent.js +22 -0
  33. package/dist/esm/PubSub.d.ts +2 -0
  34. package/dist/esm/PubSub.js +111 -0
  35. package/dist/esm/ReportHistoryStore.d.ts +8 -0
  36. package/dist/esm/ReportHistoryStore.js +199 -0
  37. package/dist/esm/SafeString.js +2 -2
  38. package/dist/esm/Templates.d.ts +58 -0
  39. package/dist/esm/Templates.js +196 -0
  40. package/dist/esm/Url.d.ts +10 -0
  41. package/dist/esm/Url.js +15 -0
  42. package/dist/esm/components/CopyText.d.ts +45 -0
  43. package/dist/esm/components/CopyText.js +56 -0
  44. package/dist/esm/components/StepProgressBar.d.ts +26 -0
  45. package/dist/esm/components/StepProgressBar.js +40 -0
  46. package/dist/esm/components/form/element/combobox.d.ts +231 -0
  47. package/dist/esm/components/form/element/combobox.js +812 -0
  48. package/dist/esm/components/form/element/dropdown.d.ts +35 -0
  49. package/dist/esm/components/form/element/dropdown.js +61 -0
  50. package/dist/esm/components/form/element/dropdownItem.d.ts +55 -0
  51. package/dist/esm/components/form/element/dropdownItem.js +113 -0
  52. package/dist/esm/components/form/element/onOffSwitch.d.ts +94 -0
  53. package/dist/esm/components/form/element/onOffSwitch.js +167 -0
  54. package/dist/esm/components/form/element/switch.d.ts +58 -0
  55. package/dist/esm/components/form/element/switch.js +98 -0
  56. package/dist/esm/fastMerge.d.ts +9 -0
  57. package/dist/esm/fastMerge.js +58 -0
  58. package/dist/esm/index.d.ts +22 -0
  59. package/dist/esm/index.js +22 -0
  60. package/dist/esm/jquery.expensifyIframify.d.ts +9 -0
  61. package/dist/esm/jquery.expensifyIframify.js +397 -0
  62. package/dist/esm/md5.d.ts +2 -0
  63. package/dist/esm/md5.js +170 -0
  64. package/dist/esm/mixins/PubSub.d.ts +20 -0
  65. package/dist/esm/mixins/PubSub.js +47 -0
  66. package/dist/esm/mixins/extraClasses.d.ts +8 -0
  67. package/dist/esm/mixins/extraClasses.js +37 -0
  68. package/dist/esm/mixins/validationClasses.d.ts +12 -0
  69. package/dist/esm/mixins/validationClasses.js +30 -0
  70. package/dist/esm/str.d.ts +604 -0
  71. package/dist/esm/str.js +1036 -0
  72. package/dist/esm/tlds.d.ts +2 -0
  73. package/dist/esm/tlds.js +2 -0
  74. package/dist/esm/utils.d.ts +30 -0
  75. package/dist/esm/utils.js +65 -0
  76. package/dist/index.d.ts +1 -0
  77. package/dist/index.js +8 -1
  78. package/package.json +221 -4
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Invokes the given callback with the given arguments
3
+ *
4
+ * @param {Function} callback
5
+ * @param {Array} [args]
6
+ * @param {Object} [scope]
7
+ *
8
+ * @returns {Mixed}
9
+ */
10
+ export function invoke(callback: Function, args?: any[], scope?: Object): Mixed;
11
+ /**
12
+ * This is nearly the same as invoke, except that it assumes that the callback returns a promise. The callback doesn't
13
+ * HAVE to return a promise, but it CAN, and if it doesn't, then we provide a promise
14
+ *
15
+ * @param {Function} callback
16
+ * @param {Array} [args]
17
+ * @param {Object} [scope]
18
+ *
19
+ * @returns {Promise}
20
+ */
21
+ export function invokeAsync(callback: Function, args?: any[], scope?: Object): Promise<any>;
22
+ /**
23
+ * Invokes all the given callbacks with the given arguments
24
+ *
25
+ * @param {Function[]} callbacks
26
+ * @param {Array} [args]
27
+ */
28
+ export function bulkInvoke(callbacks: Function[], args?: any[]): void;
29
+ /**
30
+ * Throws an uncaught error in an attempt to stop JS execution
31
+ */
32
+ export function die(): void;
33
+ /**
34
+ * Call the method on a list of objects
35
+ *
36
+ * @param {object|array} list
37
+ * @param {string} methodName
38
+ * @returns {Array}
39
+ */
40
+ export function mapByName(list: object | array, methodName: string): any[];
@@ -0,0 +1,69 @@
1
+ import * as Utils from './utils';
2
+ /**
3
+ * Invokes the given callback with the given arguments
4
+ *
5
+ * @param {Function} callback
6
+ * @param {Array} [args]
7
+ * @param {Object} [scope]
8
+ *
9
+ * @returns {Mixed}
10
+ */
11
+ function invoke(callback, args, scope) {
12
+ if (!Utils.isFunction(callback)) {
13
+ return null;
14
+ }
15
+ return callback.apply(scope, args || []);
16
+ }
17
+ /**
18
+ * This is nearly the same as invoke, except that it assumes that the callback returns a promise. The callback doesn't
19
+ * HAVE to return a promise, but it CAN, and if it doesn't, then we provide a promise
20
+ *
21
+ * @param {Function} callback
22
+ * @param {Array} [args]
23
+ * @param {Object} [scope]
24
+ *
25
+ * @returns {Promise}
26
+ */
27
+ function invokeAsync(callback, args, scope) {
28
+ if (!Utils.isFunction(callback)) {
29
+ return Promise.resolve();
30
+ }
31
+ let promiseFromCallback = callback.apply(scope, args || []);
32
+ // If there was not a promise returned from the prefetch callback, then create a dummy promise and resolve it
33
+ if (!promiseFromCallback) {
34
+ promiseFromCallback = Promise.resolve();
35
+ }
36
+ return promiseFromCallback;
37
+ }
38
+ /**
39
+ * Invokes all the given callbacks with the given arguments
40
+ *
41
+ * @param {Function[]} callbacks
42
+ * @param {Array} [args]
43
+ */
44
+ function bulkInvoke(callbacks, args) {
45
+ for (const callback of callbacks) {
46
+ invoke(callback, args);
47
+ }
48
+ }
49
+ /**
50
+ * Throws an uncaught error in an attempt to stop JS execution
51
+ */
52
+ function die() {
53
+ throw new Error('Aborting JavaScript execution');
54
+ }
55
+ /**
56
+ * Call the method on a list of objects
57
+ *
58
+ * @param {object|array} list
59
+ * @param {string} methodName
60
+ * @returns {Array}
61
+ */
62
+ function mapByName(list, methodName) {
63
+ let arr = list;
64
+ if (!Array.isArray(arr)) {
65
+ arr = Object.values(arr);
66
+ }
67
+ return arr.map((item) => item[methodName].call(item));
68
+ }
69
+ export { invoke, invokeAsync, bulkInvoke, die, mapByName };
@@ -0,0 +1,3 @@
1
+ declare const _default: Logger;
2
+ export default _default;
3
+ import Logger from './Logger';
@@ -0,0 +1,35 @@
1
+ /* eslint-disable no-console */
2
+ import API from './API';
3
+ import Network from './Network';
4
+ import Logger from './Logger';
5
+ import * as Utils from './utils';
6
+ /**
7
+ * Network interface for logger.
8
+ *
9
+ * @param {Logger} logger
10
+ * @param {Object} params
11
+ * @param {Object} params.parameters
12
+ * @param {String} params.message
13
+ * @returns {Promise}
14
+ */
15
+ function serverLoggingCallback(logger, params) {
16
+ return API(Network('/api/')).logToServer(params);
17
+ }
18
+ /**
19
+ * Local log messages for client logging.
20
+ *
21
+ * @param {String} message
22
+ */
23
+ function clientLoggingCallback(message) {
24
+ if (Utils.isWindowAvailable() && typeof window.g_printableReport !== 'undefined' && window.g_printableReport === true) {
25
+ return;
26
+ }
27
+ if (window.console && Utils.isFunction(console.log)) {
28
+ console.log(message);
29
+ }
30
+ }
31
+ export default new Logger({
32
+ serverLoggingCallback,
33
+ clientLoggingCallback,
34
+ isDebug: Utils.isWindowAvailable() ? window.DEBUG : false,
35
+ });
@@ -0,0 +1,82 @@
1
+ type Parameters = string | Record<string, unknown> | Array<Record<string, unknown>> | Error;
2
+ type ServerLoggingCallbackOptions = {
3
+ api_setCookie: boolean;
4
+ logPacket: string;
5
+ };
6
+ type ServerLoggingCallback = (logger: Logger, options: ServerLoggingCallbackOptions) => Promise<{
7
+ requestID: string;
8
+ }> | undefined;
9
+ type ClientLoggingCallBack = (message: string, extraData: Parameters) => void;
10
+ type LogLine = {
11
+ message: string;
12
+ parameters: Parameters;
13
+ onlyFlushWithOthers?: boolean;
14
+ timestamp: Date;
15
+ email?: string | null;
16
+ };
17
+ type LoggerOptions = {
18
+ serverLoggingCallback: ServerLoggingCallback;
19
+ isDebug: boolean;
20
+ clientLoggingCallback: ClientLoggingCallBack;
21
+ maxLogLinesBeforeFlush?: number;
22
+ getContextEmail?: () => string | null;
23
+ };
24
+ export default class Logger {
25
+ logLines: LogLine[];
26
+ serverLoggingCallback: ServerLoggingCallback;
27
+ clientLoggingCallback: ClientLoggingCallBack;
28
+ isDebug: boolean;
29
+ maxLogLinesBeforeFlush: number;
30
+ getContextEmail?: () => string | null;
31
+ constructor({ serverLoggingCallback, isDebug, clientLoggingCallback, maxLogLinesBeforeFlush, getContextEmail }: LoggerOptions);
32
+ /**
33
+ * Ask the server to write the log message
34
+ */
35
+ logToServer(): void;
36
+ /**
37
+ * Add a message to the list
38
+ * @param parameters The parameters associated with the message
39
+ * @param forceFlushToServer Should we force flushing all logs to server?
40
+ * @param onlyFlushWithOthers A request will never be sent to the server if all loglines have this set to true
41
+ */
42
+ add(message: string, parameters: Parameters, forceFlushToServer: boolean, onlyFlushWithOthers?: boolean, extraData?: Parameters): void;
43
+ /**
44
+ * Caches an informational message locally, to be sent to the server if
45
+ * needed later.
46
+ *
47
+ * @param message The message to log.
48
+ * @param sendNow if true, the message will be sent right away.
49
+ * @param parameters The parameters to send along with the message
50
+ * @param onlyFlushWithOthers A request will never be sent to the server if all loglines have this set to true
51
+ */
52
+ info(message: string, sendNow?: boolean, parameters?: Parameters, onlyFlushWithOthers?: boolean, extraData?: Parameters): void;
53
+ /**
54
+ * Logs an alert.
55
+ *
56
+ * @param message The message to alert.
57
+ * @param parameters The parameters to send along with the message
58
+ * @param includeStackTrace Must be disabled for testing
59
+ */
60
+ alert(message: string, parameters?: Parameters, includeStackTrace?: boolean): void;
61
+ /**
62
+ * Logs a warn.
63
+ *
64
+ * @param message The message to warn.
65
+ * @param parameters The parameters to send along with the message
66
+ */
67
+ warn(message: string, parameters?: Parameters): void;
68
+ /**
69
+ * Logs a hmmm.
70
+ *
71
+ * @param message The message to hmmm.
72
+ * @param parameters The parameters to send along with the message
73
+ */
74
+ hmmm(message: string, parameters?: Parameters): void;
75
+ /**
76
+ * Logs a message in the browser console.
77
+ *
78
+ * @param message The message to log.
79
+ */
80
+ client(message: string, extraData?: Parameters): void;
81
+ }
82
+ export {};
@@ -0,0 +1,148 @@
1
+ const MAX_LOG_LINES_BEFORE_FLUSH = 50;
2
+ // The server drops (and alerts on) any single log message whose byte length exceeds 1MB, so cap
3
+ // each message just below that. We truncate rather than drop so oversized lines are still logged
4
+ // (head of the message + a marker) instead of being lost. The margin leaves room for the marker.
5
+ const ONE_MEGABYTE = 1024 * 1024;
6
+ const MAX_LOG_MESSAGE_LENGTH = ONE_MEGABYTE - 1024;
7
+ export default class Logger {
8
+ constructor({ serverLoggingCallback, isDebug, clientLoggingCallback, maxLogLinesBeforeFlush, getContextEmail }) {
9
+ // An array of log lines that limits itself to a certain number of entries (deleting the oldest)
10
+ this.logLines = [];
11
+ this.serverLoggingCallback = serverLoggingCallback;
12
+ this.clientLoggingCallback = clientLoggingCallback;
13
+ this.isDebug = isDebug;
14
+ this.maxLogLinesBeforeFlush = maxLogLinesBeforeFlush || MAX_LOG_LINES_BEFORE_FLUSH;
15
+ this.getContextEmail = getContextEmail;
16
+ // Public Methods
17
+ this.info = this.info.bind(this);
18
+ this.alert = this.alert.bind(this);
19
+ this.warn = this.warn.bind(this);
20
+ this.hmmm = this.hmmm.bind(this);
21
+ this.client = this.client.bind(this);
22
+ }
23
+ /**
24
+ * Ask the server to write the log message
25
+ */
26
+ logToServer() {
27
+ var _a, _b;
28
+ // We do not want to call the server with an empty list or if all the lines has onlyFlushWithOthers=true
29
+ if (!this.logLines.length || ((_a = this.logLines) === null || _a === void 0 ? void 0 : _a.every((l) => l.onlyFlushWithOthers))) {
30
+ return;
31
+ }
32
+ // We don't care about log setting web cookies so let's define it as false
33
+ const linesToLog = (_b = this.logLines) === null || _b === void 0 ? void 0 : _b.map((l) => {
34
+ // eslint-disable-next-line no-param-reassign
35
+ delete l.onlyFlushWithOthers;
36
+ return l;
37
+ });
38
+ this.logLines = [];
39
+ const promise = this.serverLoggingCallback(this, {
40
+ api_setCookie: false,
41
+ logPacket: JSON.stringify(linesToLog),
42
+ });
43
+ if (!promise) {
44
+ return;
45
+ }
46
+ promise.then((response) => {
47
+ if (!response.requestID) {
48
+ return;
49
+ }
50
+ this.info('Previous log requestID', false, { requestID: response.requestID }, true);
51
+ });
52
+ }
53
+ /**
54
+ * Add a message to the list
55
+ * @param parameters The parameters associated with the message
56
+ * @param forceFlushToServer Should we force flushing all logs to server?
57
+ * @param onlyFlushWithOthers A request will never be sent to the server if all loglines have this set to true
58
+ */
59
+ add(message, parameters, forceFlushToServer, onlyFlushWithOthers = false, extraData = '') {
60
+ // Capture the user's email at the moment this specific log line is created
61
+ // This ensures the log retains user context even if the session is cleared before sending
62
+ let email = null;
63
+ try {
64
+ email = this.getContextEmail ? this.getContextEmail() : null;
65
+ }
66
+ catch (_a) {
67
+ // Silently fail if getContextEmail throws - logging should not crash
68
+ }
69
+ let cappedMessage = message;
70
+ if (message.length > MAX_LOG_MESSAGE_LENGTH) {
71
+ const omittedCount = message.length - MAX_LOG_MESSAGE_LENGTH;
72
+ cappedMessage = `${message.slice(0, MAX_LOG_MESSAGE_LENGTH)}…[truncated ${omittedCount} characters]`;
73
+ }
74
+ const length = this.logLines.push({
75
+ message: cappedMessage,
76
+ parameters,
77
+ onlyFlushWithOthers,
78
+ timestamp: new Date(),
79
+ email,
80
+ });
81
+ if (this.isDebug) {
82
+ this.client(`${message} - ${JSON.stringify(parameters)}`, extraData);
83
+ }
84
+ // If we're over the limit, flush the logs
85
+ if (length > this.maxLogLinesBeforeFlush || forceFlushToServer) {
86
+ this.logToServer();
87
+ }
88
+ }
89
+ /**
90
+ * Caches an informational message locally, to be sent to the server if
91
+ * needed later.
92
+ *
93
+ * @param message The message to log.
94
+ * @param sendNow if true, the message will be sent right away.
95
+ * @param parameters The parameters to send along with the message
96
+ * @param onlyFlushWithOthers A request will never be sent to the server if all loglines have this set to true
97
+ */
98
+ info(message, sendNow = false, parameters = '', onlyFlushWithOthers = false, extraData = '') {
99
+ const msg = `[info] ${message}`;
100
+ this.add(msg, parameters, sendNow, onlyFlushWithOthers, extraData);
101
+ }
102
+ /**
103
+ * Logs an alert.
104
+ *
105
+ * @param message The message to alert.
106
+ * @param parameters The parameters to send along with the message
107
+ * @param includeStackTrace Must be disabled for testing
108
+ */
109
+ alert(message, parameters = {}, includeStackTrace = true) {
110
+ const msg = `[alrt] ${message}`;
111
+ const params = parameters;
112
+ if (includeStackTrace && typeof params === 'object' && !Array.isArray(params)) {
113
+ params.stack = JSON.stringify(new Error().stack);
114
+ }
115
+ this.add(msg, params, true);
116
+ }
117
+ /**
118
+ * Logs a warn.
119
+ *
120
+ * @param message The message to warn.
121
+ * @param parameters The parameters to send along with the message
122
+ */
123
+ warn(message, parameters = '') {
124
+ const msg = `[warn] ${message}`;
125
+ this.add(msg, parameters, true);
126
+ }
127
+ /**
128
+ * Logs a hmmm.
129
+ *
130
+ * @param message The message to hmmm.
131
+ * @param parameters The parameters to send along with the message
132
+ */
133
+ hmmm(message, parameters = '') {
134
+ const msg = `[hmmm] ${message}`;
135
+ this.add(msg, parameters, false);
136
+ }
137
+ /**
138
+ * Logs a message in the browser console.
139
+ *
140
+ * @param message The message to log.
141
+ */
142
+ client(message, extraData = '') {
143
+ if (!this.clientLoggingCallback) {
144
+ return;
145
+ }
146
+ this.clientLoggingCallback(message, extraData);
147
+ }
148
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @param {String} endpoint
3
+ *
4
+ * @returns {Object}
5
+ */
6
+ export default function Network(endpoint: string): Object;
@@ -0,0 +1,168 @@
1
+ import $ from 'jquery';
2
+ import * as Utils from './utils';
3
+ /**
4
+ * Adds our API command to the URL so the API call is more easily identified in the
5
+ * network tab of the JS console
6
+ *
7
+ * @param {string} command
8
+ * @param {string} url
9
+ * @returns {string}
10
+ */
11
+ function addCommandToUrl(command, url) {
12
+ let newUrl = url;
13
+ if (command) {
14
+ // Add a ? to the end of the URL if there isn't one already
15
+ if (newUrl.indexOf('?') === -1) {
16
+ newUrl = `${newUrl}?`;
17
+ }
18
+ newUrl = `${newUrl}&command=${command}`;
19
+ }
20
+ return newUrl;
21
+ }
22
+ /**
23
+ * @param {String} endpoint
24
+ *
25
+ * @returns {Object}
26
+ */
27
+ export default function Network(endpoint) {
28
+ // A flag that turns true when the user navigates away
29
+ let isNavigatingAway = false;
30
+ // If URL ends in `/` we're using /api/{command} format.
31
+ const isNewURLFormat = endpoint[endpoint.length - 1] === '/';
32
+ if (!endpoint) {
33
+ throw new Error('Cannot instantiate Network without an url endpoint');
34
+ }
35
+ // Attach a listener to the event indicating that we're leaving a page
36
+ if (Utils.isWindowAvailable()) {
37
+ window.onbeforeunload = () => {
38
+ isNavigatingAway = true;
39
+ };
40
+ }
41
+ return {
42
+ /**
43
+ * @param {String} url to fetch
44
+ * @returns {Deferred}
45
+ */
46
+ get(url) {
47
+ return $.get(url);
48
+ },
49
+ /**
50
+ * @param {Object} parameters
51
+ *
52
+ * @returns {$.Deferred}
53
+ */
54
+ post(parameters) {
55
+ // Build request
56
+ let newURL = endpoint;
57
+ if (isNewURLFormat) {
58
+ // Remove command from parameters and use it in the URL
59
+ const command = parameters.command;
60
+ // eslint-disable-next-line no-param-reassign
61
+ delete parameters.command;
62
+ newURL = `${endpoint}${command}`;
63
+ }
64
+ const settings = {
65
+ url: newURL,
66
+ type: 'POST',
67
+ data: parameters,
68
+ };
69
+ const formData = new FormData();
70
+ let shouldUseFormData = false;
71
+ // Add the API command to our URL (for console debugging purposes)
72
+ // Note that parameters.command is empty if we're using the new API format and this will do nothing.
73
+ settings.url = addCommandToUrl(parameters.command, settings.url);
74
+ // Check to see if parameters contains a File or Blob object
75
+ // If it does, we should use formData instead of parameters and update
76
+ // the ajax settings accordingly
77
+ for (const [key, value] of Object.entries(parameters)) {
78
+ if (value === undefined) {
79
+ continue;
80
+ }
81
+ // Populate formData in case we need it
82
+ formData.append(key, value);
83
+ if (value instanceof File || value instanceof Blob) {
84
+ shouldUseFormData = true;
85
+ }
86
+ }
87
+ if (shouldUseFormData) {
88
+ settings.processData = false;
89
+ settings.contentType = false;
90
+ settings.data = formData;
91
+ }
92
+ return $.ajax(settings);
93
+ },
94
+ /**
95
+ * Uses the fetch API to send a keepalive request that will complete
96
+ * even if the browser is closed
97
+ *
98
+ * Note: This method ONLY provides partial support for sending complex data structures.
99
+ * It supports a single level array of objects with no nested properties
100
+ * eg. [{one: 1}, {two:2}]
101
+ *
102
+ * @param {Object} parameters
103
+ * @returns {$.Deferred}
104
+ */
105
+ keepalive(parameters) {
106
+ // Build request
107
+ const settings = {
108
+ method: 'POST',
109
+ keepalive: true,
110
+ credentials: 'same-origin',
111
+ };
112
+ let url = endpoint;
113
+ // Add the API command to our URL (for console debugging purposes)
114
+ url = addCommandToUrl(parameters.command, url);
115
+ // Add our data as form data
116
+ const formData = new FormData();
117
+ for (const [key, value] of Object.entries(parameters)) {
118
+ if (value === undefined) {
119
+ continue;
120
+ }
121
+ if (Array.isArray(value)) {
122
+ for (const [i, valueItem] of value.entries()) {
123
+ if (Utils.isObject(valueItem)) {
124
+ for (const [valueItemObjectKey, valueItemObjectValue] of Object.entries(valueItem)) {
125
+ formData.append(`${key}[${i}][${valueItemObjectKey}]`, valueItemObjectValue);
126
+ }
127
+ }
128
+ else {
129
+ formData.append(`${key}[${i}]`, valueItem);
130
+ }
131
+ }
132
+ }
133
+ else {
134
+ formData.append(key, value);
135
+ }
136
+ }
137
+ settings.body = formData;
138
+ // Make our request via the fetch API but return it in the form of a jQuery promise
139
+ // so that our API can be consistent
140
+ const promise = new $.Deferred();
141
+ fetch(url, settings)
142
+ .then(() => {
143
+ // No need to return a response since there is no script to process it
144
+ // due to the browser being closed
145
+ promise.resolve();
146
+ })
147
+ .catch((error) => {
148
+ promise.reject(error);
149
+ });
150
+ return promise;
151
+ },
152
+ /**
153
+ * @param {Function} callback
154
+ */
155
+ registerNetworkFailureHandler(callback) {
156
+ $(document).ajaxError((event, jqxhr) => {
157
+ // Some browsers invoke the ajax error callbacks when navigating away during a pending ajax call
158
+ // Ignore this if navigating away
159
+ if (isNavigatingAway) {
160
+ return;
161
+ }
162
+ const response = jqxhr.responseJSON;
163
+ const jsonCode = response ? parseInt(response.jsonCode, 10) : null;
164
+ callback(jsonCode, response);
165
+ });
166
+ },
167
+ };
168
+ }
@@ -0,0 +1,95 @@
1
+ declare namespace _default {
2
+ /**
3
+ * Converts an exponential number into it's non-exponential string equivalent
4
+ *
5
+ * @param {Number} num
6
+ *
7
+ * @returns {String}
8
+ */
9
+ function notExponential(num: number): string;
10
+ /**
11
+ * Format a number, similar to PHP's number_format.
12
+ *
13
+ * @param {Number} _a The number you want to format
14
+ * @param {Number} [b="0"] The number of decimal places you want
15
+ * @param {String} [_c=","] The decimal separator
16
+ * @param {String} [d="."] The thousands separator
17
+ *
18
+ * @todo should be camelCase / needs refactor
19
+ * @returns {String}
20
+ */
21
+ function number_format(_a: number, b?: number, _c?: string, d?: string): string;
22
+ function generateRandom6DigitID(): number;
23
+ /**
24
+ * Converts a number to base 26 (using capital english letters as digits).
25
+ *
26
+ * @param {Number} num The number to convert to base 26.
27
+ *
28
+ * @returns {String} The number, converted to base 26.
29
+ */
30
+ function toBase26LetterCode(num: number): string;
31
+ /**
32
+ * Check if a number is finite and not NaN. i.e.
33
+ *
34
+ * @param {number} number The number to test
35
+ *
36
+ * @returns {Boolean} true if the number is finite and not NaN.
37
+ */
38
+ function isFiniteNumber(number: number): boolean;
39
+ /**
40
+ * Truncates the given number to the given precision.
41
+ *
42
+ * @param {number} number the number to truncate.
43
+ * @param {number} decimals the number of decimals to keep.
44
+ *
45
+ * @returns {number} the truncated number.
46
+ */
47
+ function toPrecision(number: number, decimals: number): number;
48
+ /**
49
+ * Check if a number is between 2 numbers, including them.
50
+ *
51
+ * @param {number} number to check
52
+ * @param {number} a the 1st limit
53
+ * @param {number} b the 2nd limit
54
+ *
55
+ * @returns {boolean}
56
+ */
57
+ function isNumberBetween(number: number, a: number, b: number): boolean;
58
+ /**
59
+ * Returns how many decimals to display (used for currencies).
60
+ *
61
+ * @param {Number} rate
62
+ * @returns {Number}
63
+ */
64
+ function getDisplayDecimals(rate: number): number;
65
+ namespace tax {
66
+ /**
67
+ * Calculate the pre-tax, or net amount
68
+ *
69
+ * @param {Number} total The total to calculate from, in negative cents
70
+ * @param {UserDefinedField} taxUDF The tax UDF
71
+ *
72
+ * @returns {number} The pre-tax amount, in negative cents
73
+ */
74
+ function calculatePreTaxAmount(total: number, taxUDF: UserDefinedField): number;
75
+ /**
76
+ * Calculate the tax amount from the total.
77
+ *
78
+ * @param {Number} total The total to calculate from
79
+ * @param {String} percentage The percentage, as a string, e.g. '20%'
80
+ *
81
+ * @returns {number} The amount of tax
82
+ */
83
+ function calculateTaxFromPercentage(total: number, percentage: string): number;
84
+ /**
85
+ * Calculate the tax amount from a divisor.
86
+ *
87
+ * @param {Number} total The total to calculate from
88
+ * @param {Number} divisor The divisor (0.1 = 10%)
89
+ *
90
+ * @returns {number} The amount of tax
91
+ */
92
+ function calculateTaxFromDivisor(total: number, divisor: number): number;
93
+ }
94
+ }
95
+ export default _default;