expensify-common 2.0.181 → 2.0.183
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/dist/API.js +19 -24
- package/dist/APIDeferred.js +5 -5
- package/dist/CONST.d.ts +3 -0
- package/dist/CONST.js +4 -1
- package/dist/Cookie.d.ts +5 -5
- package/dist/Cookie.js +6 -6
- package/dist/ExpenseRule.d.ts +10 -10
- package/dist/ExpenseRule.js +9 -9
- package/dist/ExpensiMark.d.ts +23 -51
- package/dist/ExpensiMark.js +311 -333
- package/dist/Func.js +3 -1
- package/dist/Log.js +1 -1
- package/dist/Logger.d.ts +2 -2
- package/dist/Logger.js +6 -4
- package/dist/Network.js +10 -10
- package/dist/Num.d.ts +1 -1
- package/dist/Num.js +9 -5
- package/dist/PageEvent.d.ts +2 -2
- package/dist/PageEvent.js +1 -1
- package/dist/PubSub.js +7 -7
- package/dist/ReportHistoryStore.d.ts +8 -71
- package/dist/ReportHistoryStore.js +106 -180
- package/dist/Templates.d.ts +13 -13
- package/dist/Templates.js +157 -183
- package/dist/components/StepProgressBar.d.ts +8 -4
- package/dist/components/StepProgressBar.js +4 -3
- package/dist/components/form/element/combobox.d.ts +1 -8
- package/dist/components/form/element/combobox.js +37 -37
- package/dist/components/form/element/switch.d.ts +2 -2
- package/dist/components/form/element/switch.js +7 -5
- package/dist/fastMerge.js +0 -2
- package/dist/index.js +0 -1
- package/dist/jquery.expensifyIframify.d.ts +1 -2
- package/dist/jquery.expensifyIframify.js +13 -15
- package/dist/md5.js +30 -29
- package/dist/mixins/PubSub.js +2 -2
- package/dist/str.js +19 -19
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +6 -6
- package/package.json +11 -10
package/dist/Templates.js
CHANGED
|
@@ -45,72 +45,46 @@ const Utils = __importStar(require("./utils"));
|
|
|
45
45
|
* Templates is a global namespace for each template, HTML ones or inlines ones.
|
|
46
46
|
*
|
|
47
47
|
* @type Module
|
|
48
|
-
* @
|
|
48
|
+
* @class
|
|
49
49
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* @param {String} templateValue
|
|
60
|
-
*/
|
|
61
|
-
constructor(templateValue) {
|
|
62
|
-
this.templateValue = templateValue;
|
|
63
|
-
this.compiled = null;
|
|
64
|
-
this.get = this.get.bind(this);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Gets the compiled template using the provided data
|
|
68
|
-
*
|
|
69
|
-
* @param {Object} data
|
|
70
|
-
*
|
|
71
|
-
* @returns {String}
|
|
72
|
-
*/
|
|
50
|
+
const templateStore = {};
|
|
51
|
+
/**
|
|
52
|
+
* @param {String} templateValue
|
|
53
|
+
* @returns {{get: function(Object=): String}}
|
|
54
|
+
*/
|
|
55
|
+
function createInlineTemplate(templateValue) {
|
|
56
|
+
let compiled = null;
|
|
57
|
+
let storedValue = templateValue;
|
|
58
|
+
return {
|
|
73
59
|
get(data = {}) {
|
|
74
|
-
if (!
|
|
75
|
-
|
|
60
|
+
if (!compiled) {
|
|
61
|
+
compiled = (0, template_1.default)(storedValue, {
|
|
76
62
|
imports: {
|
|
77
63
|
// Here we ignore the eslint rule because _ is imported from OD which does not exist in this repo
|
|
78
64
|
// eslint-disable-next-line no-undef, object-shorthand
|
|
79
65
|
_: _,
|
|
80
66
|
},
|
|
81
67
|
});
|
|
82
|
-
|
|
68
|
+
storedValue = '';
|
|
83
69
|
}
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.id = id;
|
|
97
|
-
this.compiled = null;
|
|
98
|
-
this.get = this.get.bind(this);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Gets the compiled template using the provided data
|
|
102
|
-
*
|
|
103
|
-
* @param {Object} data
|
|
104
|
-
*
|
|
105
|
-
* @returns {String}
|
|
106
|
-
*/
|
|
70
|
+
return compiled(data);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* @param {String} id
|
|
76
|
+
* @param {function} getNestedTemplate
|
|
77
|
+
* @returns {{get: function(Object=): String}}
|
|
78
|
+
*/
|
|
79
|
+
function createDOMTemplate(id, getNestedTemplate) {
|
|
80
|
+
let compiled = null;
|
|
81
|
+
return {
|
|
107
82
|
get(data = {}) {
|
|
108
83
|
// Add the "template" object to the parameter to allow nested templates
|
|
109
84
|
const dataToCompile = Object.assign({}, data);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this.compiled = (0, template_1.default)((0, jquery_1.default)(`#${this.id}`).html(), {
|
|
85
|
+
dataToCompile.nestedTemplate = getNestedTemplate;
|
|
86
|
+
if (!compiled) {
|
|
87
|
+
compiled = (0, template_1.default)((0, jquery_1.default)(`#${id}`).html(), {
|
|
114
88
|
imports: {
|
|
115
89
|
// Here we ignore the eslint rule because _ is imported from OD which does not exist in this repo
|
|
116
90
|
// eslint-disable-next-line no-undef, object-shorthand
|
|
@@ -118,143 +92,143 @@ exports.default = (function () {
|
|
|
118
92
|
},
|
|
119
93
|
});
|
|
120
94
|
}
|
|
121
|
-
return
|
|
95
|
+
return compiled(dataToCompile);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns the template
|
|
101
|
+
*
|
|
102
|
+
* @param {Array} templatePath
|
|
103
|
+
* @returns {InlineTemplate|undefined}
|
|
104
|
+
*/
|
|
105
|
+
function getTemplate(templatePath) {
|
|
106
|
+
let template = templateStore;
|
|
107
|
+
for (const pathname of templatePath) {
|
|
108
|
+
template = template[pathname];
|
|
109
|
+
}
|
|
110
|
+
return template;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Based on an array of string, return a reference to the object that should hold the template
|
|
114
|
+
* used to augment the template object
|
|
115
|
+
*
|
|
116
|
+
* @param {Array} wantedNamespace Array of string reprensenting the namespace
|
|
117
|
+
* @returns {Object} Referene to the object holding the namespace
|
|
118
|
+
*/
|
|
119
|
+
function getTemplateNamespace(wantedNamespace) {
|
|
120
|
+
let namespace = templateStore;
|
|
121
|
+
let currentArgument;
|
|
122
|
+
for (let argumentNumber = 0; argumentNumber < wantedNamespace.length; argumentNumber++) {
|
|
123
|
+
currentArgument = wantedNamespace[argumentNumber];
|
|
124
|
+
if (namespace[currentArgument] === undefined) {
|
|
125
|
+
namespace[currentArgument] = {};
|
|
122
126
|
}
|
|
127
|
+
namespace = namespace[currentArgument];
|
|
123
128
|
}
|
|
129
|
+
return namespace;
|
|
130
|
+
}
|
|
131
|
+
const Templates = {
|
|
124
132
|
/**
|
|
125
|
-
*
|
|
133
|
+
* Given a templatePath, return the value
|
|
126
134
|
*
|
|
127
135
|
* @param {Array} templatePath
|
|
128
|
-
* @
|
|
136
|
+
* @param {Object} [data] Information that need to be injected into the template
|
|
137
|
+
* @returns {String}
|
|
129
138
|
*/
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
get(templatePath, data = {}) {
|
|
140
|
+
const template = getTemplate(templatePath);
|
|
141
|
+
if (template === undefined) {
|
|
142
|
+
throw Error(`Template '${templatePath}' is not defined`);
|
|
143
|
+
}
|
|
144
|
+
// Check for the absense of get which means someone is likely using
|
|
145
|
+
// the templating engine wrong and trying to access a template namespace
|
|
146
|
+
if (!{}.propertyIsEnumerable.call(template, 'get')) {
|
|
147
|
+
throw Error(`'${templatePath}' is not a valid template path`);
|
|
148
|
+
}
|
|
149
|
+
return template.get(data);
|
|
150
|
+
},
|
|
137
151
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* @param {Array} wantedNamespace Array of string reprensenting the namespace
|
|
142
|
-
* @return {Object} Referene to the object holding the namespace
|
|
152
|
+
* Given a templatePath, does it have a registered template?
|
|
153
|
+
* @param {Array} templatePath
|
|
154
|
+
* @returns {Boolean}
|
|
143
155
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
has(templatePath) {
|
|
157
|
+
return getTemplate(templatePath) !== undefined;
|
|
158
|
+
},
|
|
159
|
+
/**
|
|
160
|
+
* Inits the templating engine, and slurps all DOM templates in an internal data structure
|
|
161
|
+
*/
|
|
162
|
+
init() {
|
|
163
|
+
// Read the DOM to find all the templates, and make them available to the code
|
|
164
|
+
for (const $el of (0, jquery_1.default)('.js_template').toArray()) {
|
|
165
|
+
const namespaceElements = $el.id.split('_');
|
|
166
|
+
const id = namespaceElements.pop();
|
|
167
|
+
// remove the prefix "template" that MUST be added to have clean HTML ids
|
|
168
|
+
namespaceElements.shift();
|
|
169
|
+
const namespace = getTemplateNamespace(namespaceElements);
|
|
170
|
+
namespace[id] = createDOMTemplate($el.id, Templates.get);
|
|
153
171
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
172
|
+
},
|
|
173
|
+
/**
|
|
174
|
+
* Register a new json object in the template manager
|
|
175
|
+
*
|
|
176
|
+
* @param {Array} wantedNamespace Namespace where we want to store the templates
|
|
177
|
+
* @param {object} templateData The literal object that contain the templates
|
|
178
|
+
*/
|
|
179
|
+
register(wantedNamespace, templateData) {
|
|
180
|
+
const namespace = getTemplateNamespace(wantedNamespace);
|
|
181
|
+
for (const key of Object.keys(templateData)) {
|
|
182
|
+
const template = templateData[key];
|
|
183
|
+
if (Utils.isObject(template)) {
|
|
184
|
+
// If the template is an object, add templates for all keys
|
|
185
|
+
namespace[key] = {};
|
|
186
|
+
for (const templateKey of Object.keys(template)) {
|
|
187
|
+
namespace[key][templateKey] = createInlineTemplate(template[templateKey]);
|
|
188
|
+
}
|
|
168
189
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (!{}.propertyIsEnumerable.call(template, 'get')) {
|
|
172
|
-
throw Error(`'${templatePath}' is not a valid template path`);
|
|
190
|
+
else {
|
|
191
|
+
namespace[key] = createInlineTemplate(template);
|
|
173
192
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
else {
|
|
217
|
-
namespace[key] = new InlineTemplate(template);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
},
|
|
221
|
-
/**
|
|
222
|
-
* Removes a namespace from the templateStore (only used for testing purposes)
|
|
223
|
-
*
|
|
224
|
-
* @param {String} nameSpace
|
|
225
|
-
*/
|
|
226
|
-
unregister(nameSpace) {
|
|
227
|
-
delete templateStore[nameSpace];
|
|
228
|
-
},
|
|
229
|
-
/**
|
|
230
|
-
* Replace the DOM HTML with the template value
|
|
231
|
-
*
|
|
232
|
-
* @param {jQuery} $target Element(s) that will be updated
|
|
233
|
-
* @param {Array} templatePath
|
|
234
|
-
* @param {Object} [data] Information that need to be injected into the template
|
|
235
|
-
*/
|
|
236
|
-
insert($target, templatePath, data = {}) {
|
|
237
|
-
$target.html(this.get(templatePath, data));
|
|
238
|
-
},
|
|
239
|
-
/**
|
|
240
|
-
* Append the template value into a DOM elements
|
|
241
|
-
*
|
|
242
|
-
* @param {jQuery} $target Element(s) that will be updated
|
|
243
|
-
* @param {Array} templatePath
|
|
244
|
-
* @param {Object} data Information that need to be injected into the template
|
|
245
|
-
*/
|
|
246
|
-
prepend($target, templatePath, data) {
|
|
247
|
-
$target.prepend(this.get(templatePath, data));
|
|
248
|
-
},
|
|
249
|
-
/**
|
|
250
|
-
* Prepend the template value into a DOM elements
|
|
251
|
-
*
|
|
252
|
-
* @param {jQuery} $target Element(s) that will be updated
|
|
253
|
-
* @param {array} templatePath
|
|
254
|
-
* @param {object} [data] Information that need to be injected into the template
|
|
255
|
-
*/
|
|
256
|
-
append($target, templatePath, data) {
|
|
257
|
-
$target.append(this.get(templatePath, data));
|
|
258
|
-
},
|
|
259
|
-
};
|
|
260
|
-
})();
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
/**
|
|
196
|
+
* Removes a namespace from the templateStore (only used for testing purposes)
|
|
197
|
+
*
|
|
198
|
+
* @param {String} nameSpace
|
|
199
|
+
*/
|
|
200
|
+
unregister(nameSpace) {
|
|
201
|
+
delete templateStore[nameSpace];
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* Replace the DOM HTML with the template value
|
|
205
|
+
*
|
|
206
|
+
* @param {jQuery} $target Element(s) that will be updated
|
|
207
|
+
* @param {Array} templatePath
|
|
208
|
+
* @param {Object} [data] Information that need to be injected into the template
|
|
209
|
+
*/
|
|
210
|
+
insert($target, templatePath, data = {}) {
|
|
211
|
+
$target.html(this.get(templatePath, data));
|
|
212
|
+
},
|
|
213
|
+
/**
|
|
214
|
+
* Append the template value into a DOM elements
|
|
215
|
+
*
|
|
216
|
+
* @param {jQuery} $target Element(s) that will be updated
|
|
217
|
+
* @param {Array} templatePath
|
|
218
|
+
* @param {Object} data Information that need to be injected into the template
|
|
219
|
+
*/
|
|
220
|
+
prepend($target, templatePath, data) {
|
|
221
|
+
$target.prepend(this.get(templatePath, data));
|
|
222
|
+
},
|
|
223
|
+
/**
|
|
224
|
+
* Prepend the template value into a DOM elements
|
|
225
|
+
*
|
|
226
|
+
* @param {jQuery} $target Element(s) that will be updated
|
|
227
|
+
* @param {array} templatePath
|
|
228
|
+
* @param {object} [data] Information that need to be injected into the template
|
|
229
|
+
*/
|
|
230
|
+
append($target, templatePath, data) {
|
|
231
|
+
$target.append(this.get(templatePath, data));
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
exports.default = Templates;
|
|
@@ -2,12 +2,16 @@ export default StepProgressBar;
|
|
|
2
2
|
/**
|
|
3
3
|
* Step progress bar.
|
|
4
4
|
*
|
|
5
|
-
* @param {
|
|
6
|
-
* @param {
|
|
5
|
+
* @param {object} props Component props
|
|
6
|
+
* @param {array} props.steps Array of {id, title}
|
|
7
|
+
* @param {string} props.currentStep Current step id
|
|
7
8
|
*
|
|
8
|
-
* @
|
|
9
|
+
* @returns {React.Component}
|
|
9
10
|
*/
|
|
10
|
-
declare function StepProgressBar({ steps, currentStep }:
|
|
11
|
+
declare function StepProgressBar({ steps, currentStep }: {
|
|
12
|
+
steps: array;
|
|
13
|
+
currentStep: string;
|
|
14
|
+
}): React.Component;
|
|
11
15
|
declare namespace StepProgressBar {
|
|
12
16
|
export { propTypes };
|
|
13
17
|
}
|
|
@@ -51,10 +51,11 @@ const propTypes = {
|
|
|
51
51
|
/**
|
|
52
52
|
* Step progress bar.
|
|
53
53
|
*
|
|
54
|
-
* @param {
|
|
55
|
-
* @param {
|
|
54
|
+
* @param {object} props Component props
|
|
55
|
+
* @param {array} props.steps Array of {id, title}
|
|
56
|
+
* @param {string} props.currentStep Current step id
|
|
56
57
|
*
|
|
57
|
-
* @
|
|
58
|
+
* @returns {React.Component}
|
|
58
59
|
*/
|
|
59
60
|
function StepProgressBar({ steps, currentStep }) {
|
|
60
61
|
const isCurrentStep = (step) => step.id === currentStep;
|
|
@@ -23,7 +23,7 @@ declare class Combobox extends React.Component<any, any, any> {
|
|
|
23
23
|
/**
|
|
24
24
|
* Returns the selected value(s)
|
|
25
25
|
*
|
|
26
|
-
* @
|
|
26
|
+
* @returns {String}
|
|
27
27
|
*/
|
|
28
28
|
getValue(): string;
|
|
29
29
|
/**
|
|
@@ -106,13 +106,6 @@ declare class Combobox extends React.Component<any, any, any> {
|
|
|
106
106
|
* @param {SyntheticEvent} e
|
|
107
107
|
*/
|
|
108
108
|
closeDropdownOnTabOut(e: SyntheticEvent): void;
|
|
109
|
-
/**
|
|
110
|
-
* Stops events from doing anything outside of the current function (in theory).
|
|
111
|
-
* This doesn't work between jquery and React events because React's event propagation is a separate system.
|
|
112
|
-
*
|
|
113
|
-
* @param {SyntheticEvent} e
|
|
114
|
-
*/
|
|
115
|
-
stopEvent(e: SyntheticEvent): void;
|
|
116
109
|
/**
|
|
117
110
|
* This is triggered whenever there is a key up event in the text input
|
|
118
111
|
*
|
|
@@ -41,6 +41,7 @@ const react_dom_1 = __importDefault(require("react-dom"));
|
|
|
41
41
|
const prop_types_1 = __importDefault(require("prop-types"));
|
|
42
42
|
const classnames_1 = __importDefault(require("classnames"));
|
|
43
43
|
const defer_1 = __importDefault(require("lodash/defer"));
|
|
44
|
+
const get_1 = __importDefault(require("lodash/get"));
|
|
44
45
|
const has_1 = __importDefault(require("lodash/has"));
|
|
45
46
|
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
46
47
|
const template_1 = __importDefault(require("lodash/template"));
|
|
@@ -48,6 +49,22 @@ const uniqBy_1 = __importDefault(require("lodash/uniqBy"));
|
|
|
48
49
|
const str_1 = __importDefault(require("../../../str"));
|
|
49
50
|
const dropdown_1 = __importDefault(require("./dropdown"));
|
|
50
51
|
const Utils = __importStar(require("../../../utils"));
|
|
52
|
+
/**
|
|
53
|
+
* Stops events from doing anything outside of the current function (in theory).
|
|
54
|
+
* This doesn't work between jquery and React events because React's event propagation is a separate system.
|
|
55
|
+
*
|
|
56
|
+
* @param {SyntheticEvent} e
|
|
57
|
+
*/
|
|
58
|
+
function stopEvent(e) {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
if (e.nativeEvent) {
|
|
61
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
e.stopImmediatePropagation();
|
|
65
|
+
}
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
}
|
|
51
68
|
const propTypes = {
|
|
52
69
|
// These are the elements to show in the dropdown
|
|
53
70
|
options: prop_types_1.default.arrayOf(prop_types_1.default.shape({
|
|
@@ -152,7 +169,6 @@ const defaultProps = {
|
|
|
152
169
|
/**
|
|
153
170
|
* A combobox useful for searching for values in a large list
|
|
154
171
|
*/
|
|
155
|
-
// eslint-disable-next-line react/no-unsafe
|
|
156
172
|
class Combobox extends react_1.default.Component {
|
|
157
173
|
constructor(props) {
|
|
158
174
|
super(props);
|
|
@@ -175,7 +191,6 @@ class Combobox extends react_1.default.Component {
|
|
|
175
191
|
this.openDropdown = this.openDropdown.bind(this);
|
|
176
192
|
this.closeDropdown = this.closeDropdown.bind(this);
|
|
177
193
|
this.closeDropdownOnTabOut = this.closeDropdownOnTabOut.bind(this);
|
|
178
|
-
this.stopEvent = this.stopEvent.bind(this);
|
|
179
194
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
180
195
|
this.performSearch = this.performSearch.bind(this);
|
|
181
196
|
this.handleClick = this.handleClick.bind(this);
|
|
@@ -352,7 +367,7 @@ class Combobox extends react_1.default.Component {
|
|
|
352
367
|
}
|
|
353
368
|
this.switchFocusedIndex(oldFocusedIndex, newFocusedIndex);
|
|
354
369
|
this.setState(updateStateDownKey, this.resetClickAwayHandler);
|
|
355
|
-
|
|
370
|
+
stopEvent(e);
|
|
356
371
|
break;
|
|
357
372
|
case 38:
|
|
358
373
|
// Up - move focused selection up
|
|
@@ -364,7 +379,7 @@ class Combobox extends react_1.default.Component {
|
|
|
364
379
|
}
|
|
365
380
|
this.switchFocusedIndex(oldFocusedIndex, newFocusedIndex);
|
|
366
381
|
this.setState(updateStateUpKey, this.resetClickAwayHandler);
|
|
367
|
-
|
|
382
|
+
stopEvent(e);
|
|
368
383
|
break;
|
|
369
384
|
case 13: {
|
|
370
385
|
// Enter - set selection
|
|
@@ -384,7 +399,7 @@ class Combobox extends react_1.default.Component {
|
|
|
384
399
|
currentText = currentValue;
|
|
385
400
|
}
|
|
386
401
|
this.setState(updateStateEnterKey, resetStateEnterKey);
|
|
387
|
-
|
|
402
|
+
stopEvent(e);
|
|
388
403
|
break;
|
|
389
404
|
}
|
|
390
405
|
case 9:
|
|
@@ -395,7 +410,7 @@ class Combobox extends react_1.default.Component {
|
|
|
395
410
|
this.props.onChange(this.initialValue || this.props.value || this.props.defaultValue);
|
|
396
411
|
// Stop the event from propagating if the escape key is pressed
|
|
397
412
|
if (e.which === 27) {
|
|
398
|
-
|
|
413
|
+
stopEvent(e);
|
|
399
414
|
}
|
|
400
415
|
break;
|
|
401
416
|
default:
|
|
@@ -455,16 +470,14 @@ class Combobox extends react_1.default.Component {
|
|
|
455
470
|
return o.isSelected && this.props.alwaysShowSelectedOnTop ? 0 : 1;
|
|
456
471
|
};
|
|
457
472
|
// Take each array and format it, sort it, and move selected items to top (if applicable)
|
|
458
|
-
const formatOptions = (array, arrayStartIndex) =>
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
.slice(0, this.props.maxItemsToShow);
|
|
467
|
-
};
|
|
473
|
+
const formatOptions = (array, arrayStartIndex) => array
|
|
474
|
+
.map((option, index) => formatOption(option, arrayStartIndex + index))
|
|
475
|
+
.sort((a, b) => {
|
|
476
|
+
const sortDiff = sortByOption(a) - sortByOption(b);
|
|
477
|
+
// If sort priority is the same, preserve original order using originalIndex
|
|
478
|
+
return sortDiff !== 0 ? sortDiff : a.originalIndex - b.originalIndex;
|
|
479
|
+
})
|
|
480
|
+
.slice(0, this.props.maxItemsToShow);
|
|
468
481
|
let cumulativeIndex = 0;
|
|
469
482
|
const truncatedOptions = splitOptions
|
|
470
483
|
.map((array) => {
|
|
@@ -496,7 +509,7 @@ class Combobox extends react_1.default.Component {
|
|
|
496
509
|
/**
|
|
497
510
|
* Returns the selected value(s)
|
|
498
511
|
*
|
|
499
|
-
* @
|
|
512
|
+
* @returns {String}
|
|
500
513
|
*/
|
|
501
514
|
getValue() {
|
|
502
515
|
return this.state.currentValue;
|
|
@@ -510,7 +523,7 @@ class Combobox extends react_1.default.Component {
|
|
|
510
523
|
// We need to look in `this.options` for the matching option because `this.state.options` is a truncated list
|
|
511
524
|
// and might not have every option
|
|
512
525
|
const optionMatchingVal = this.options.find((option) => option.value === val);
|
|
513
|
-
const currentText = (
|
|
526
|
+
const currentText = (0, get_1.default)(optionMatchingVal, 'text', '');
|
|
514
527
|
const deselectOption = (initialOption) => {
|
|
515
528
|
const option = initialOption;
|
|
516
529
|
const isSelected = (0, isEqual_1.default)(option.value, val);
|
|
@@ -711,22 +724,6 @@ class Combobox extends react_1.default.Component {
|
|
|
711
724
|
}
|
|
712
725
|
this.handleClick(this.state.currentValue);
|
|
713
726
|
}
|
|
714
|
-
/**
|
|
715
|
-
* Stops events from doing anything outside of the current function (in theory).
|
|
716
|
-
* This doesn't work between jquery and React events because React's event propagation is a separate system.
|
|
717
|
-
*
|
|
718
|
-
* @param {SyntheticEvent} e
|
|
719
|
-
*/
|
|
720
|
-
stopEvent(e) {
|
|
721
|
-
e.preventDefault();
|
|
722
|
-
if (e.nativeEvent) {
|
|
723
|
-
e.nativeEvent.stopImmediatePropagation();
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
e.stopImmediatePropagation();
|
|
727
|
-
}
|
|
728
|
-
e.stopPropagation();
|
|
729
|
-
}
|
|
730
727
|
/**
|
|
731
728
|
* This is triggered whenever there is a change event in the text input
|
|
732
729
|
* (from any valid input that's not being handled from the keyUp event)
|
|
@@ -763,7 +760,7 @@ class Combobox extends react_1.default.Component {
|
|
|
763
760
|
for (let j = 0; j < searchOptions.length; j++) {
|
|
764
761
|
const option = searchOptions[j];
|
|
765
762
|
const isDisabled = option.disabled;
|
|
766
|
-
const isMatch = matchRegexes[i].test(option.text.toString().
|
|
763
|
+
const isMatch = matchRegexes[i].test(option.text.toString().replaceAll(' ', ''));
|
|
767
764
|
// Don't include the disabled options that match the regex unless we specified we want them to show.
|
|
768
765
|
// If we want them to show then add them whether they match the regex or not.
|
|
769
766
|
if ((!isDisabled && isMatch) || (isDisabled && this.props.showDisabledOptionsInResults && isMatch)) {
|
|
@@ -837,12 +834,15 @@ class Combobox extends react_1.default.Component {
|
|
|
837
834
|
};
|
|
838
835
|
const toggleBtnClasses = this.props.bs4 ? 'dropdown-toggle dropdown-toggle-split btn btn-outline-primary' : 'dropdown-toggle btn btn-default';
|
|
839
836
|
return (react_1.default.createElement("div", { className: (0, classnames_1.default)(inputGroupClasses, this.props.extraClasses), onKeyDown: this.handleKeyDown, role: "presentation" },
|
|
840
|
-
react_1.default.createElement("input", { ref: (ref) => (this.value = ref), type: "text", className: (0, classnames_1.default)(['form-control', { error: this.state.hasError }]), disabled: this.state.isDisabled, "aria-label": "...", onChange: this.performSearch, onKeyDown: this.closeDropdownOnTabOut, value: this.props.propertyToDisplay === 'value' ? Utils.unescapeText(this.state.currentValue) : Utils.unescapeText(this.state.currentText.
|
|
837
|
+
react_1.default.createElement("input", { ref: (ref) => (this.value = ref), type: "text", className: (0, classnames_1.default)(['form-control', { error: this.state.hasError }]), disabled: this.state.isDisabled, "aria-label": "...", onChange: this.performSearch, onKeyDown: this.closeDropdownOnTabOut, value: this.props.propertyToDisplay === 'value' ? Utils.unescapeText(this.state.currentValue) : Utils.unescapeText(this.state.currentText.replaceAll(' ', '')), onFocus: this.openDropdown, autoComplete: "off", placeholder: this.props.placeholder, tabIndex: "0" }),
|
|
841
838
|
react_1.default.createElement("div", { className: (0, classnames_1.default)(inputGroupBtnClasses) },
|
|
842
839
|
react_1.default.createElement("button", { type: "button", className: (0, classnames_1.default)(toggleBtnClasses, { error: this.state.hasError }), disabled: this.state.isDisabled, onClick: this.toggleDropdown, onKeyDown: this.closeDropdownOnTabOut, tabIndex: "-1" },
|
|
843
840
|
!this.props.bs4 && react_1.default.createElement("span", { className: "caret" }),
|
|
844
841
|
react_1.default.createElement("span", { className: "sr-only" }, "Toggle Dropdown")),
|
|
845
|
-
this.state.isDropdownOpen && (react_1.default.createElement(dropdown_1.default, { ref: (ref) => (this.dropDown = ref), options: this.state.options, bs4: this.props.bs4, extraClasses: (0, classnames_1.default)({
|
|
842
|
+
this.state.isDropdownOpen && (react_1.default.createElement(dropdown_1.default, { ref: (ref) => (this.dropDown = ref), options: this.state.options, bs4: this.props.bs4, extraClasses: (0, classnames_1.default)({
|
|
843
|
+
'expensify-dropdown': true,
|
|
844
|
+
show: this.props.bs4 && this.state.isDropdownOpen,
|
|
845
|
+
}, this.props.dropDownClasses), onChange: this.handleClick })))));
|
|
846
846
|
}
|
|
847
847
|
}
|
|
848
848
|
Combobox.propTypes = propTypes;
|
|
@@ -10,7 +10,7 @@ declare class Switch extends React.Component<any, any, any> {
|
|
|
10
10
|
* then we need to open a confirm modal with those settings
|
|
11
11
|
*
|
|
12
12
|
* @param {SyntheticEvent} e
|
|
13
|
-
* @
|
|
13
|
+
* @returns {Boolean}
|
|
14
14
|
*/
|
|
15
15
|
showConfirm(e: SyntheticEvent): boolean;
|
|
16
16
|
checkbox: HTMLInputElement | null;
|
|
@@ -19,7 +19,7 @@ declare class Switch extends React.Component<any, any, any> {
|
|
|
19
19
|
/**
|
|
20
20
|
* Gets the value of the field
|
|
21
21
|
*
|
|
22
|
-
* @
|
|
22
|
+
* @returns {boolean}
|
|
23
23
|
*/
|
|
24
24
|
getValue(): boolean;
|
|
25
25
|
render(): React.JSX.Element;
|