sr-npm 3.1.22 → 3.1.24
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/backend/data.js
CHANGED
|
@@ -463,14 +463,18 @@ function fetchJobLocation(jobDetails) {
|
|
|
463
463
|
|
|
464
464
|
async function createCollections() {
|
|
465
465
|
console.log("Creating collections");
|
|
466
|
+
if(siteconfig===undefined) {
|
|
467
|
+
await getSiteConfig();
|
|
468
|
+
}
|
|
469
|
+
|
|
466
470
|
await Promise.all(
|
|
467
471
|
[createCollectionIfMissing(COLLECTIONS.JOBS, COLLECTIONS_FIELDS.JOBS,{ insert: 'ADMIN', update: 'ADMIN', remove: 'ADMIN', read: 'ANYONE' }),
|
|
468
472
|
createCollectionIfMissing(COLLECTIONS.CITIES, COLLECTIONS_FIELDS.CITIES),
|
|
469
473
|
createCollectionIfMissing(COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT, COLLECTIONS_FIELDS.AMOUNT_OF_JOBS_PER_DEPARTMENT),
|
|
470
474
|
createCollectionIfMissing(COLLECTIONS.SECRET_MANAGER_MIRROR, COLLECTIONS_FIELDS.SECRET_MANAGER_MIRROR),
|
|
471
475
|
createCollectionIfMissing(COLLECTIONS.BRANDS, COLLECTIONS_FIELDS.BRANDS),
|
|
472
|
-
createCollectionIfMissing(COLLECTIONS.CUSTOM_VALUES, COLLECTIONS_FIELDS.CUSTOM_VALUES),
|
|
473
|
-
createCollectionIfMissing(COLLECTIONS.CUSTOM_FIELDS, COLLECTIONS_FIELDS.CUSTOM_FIELDS)
|
|
476
|
+
siteconfig.customFields==="true" ? createCollectionIfMissing(COLLECTIONS.CUSTOM_VALUES, COLLECTIONS_FIELDS.CUSTOM_VALUES) : null,
|
|
477
|
+
siteconfig.customFields==="true" ? createCollectionIfMissing(COLLECTIONS.CUSTOM_FIELDS, COLLECTIONS_FIELDS.CUSTOM_FIELDS) : null
|
|
474
478
|
]);
|
|
475
479
|
console.log("finished creating Collections");
|
|
476
480
|
}
|
|
@@ -528,13 +532,16 @@ async function syncJobsFast() {
|
|
|
528
532
|
|
|
529
533
|
async function clearCollections() {
|
|
530
534
|
console.log("clearing collections");
|
|
535
|
+
if(siteconfig===undefined) {
|
|
536
|
+
await getSiteConfig();
|
|
537
|
+
}
|
|
531
538
|
await Promise.all([
|
|
532
539
|
wixData.truncate(COLLECTIONS.CITIES),
|
|
533
540
|
wixData.truncate(COLLECTIONS.AMOUNT_OF_JOBS_PER_DEPARTMENT),
|
|
534
541
|
wixData.truncate(COLLECTIONS.JOBS),
|
|
535
542
|
wixData.truncate(COLLECTIONS.BRANDS),
|
|
536
|
-
wixData.truncate(COLLECTIONS.CUSTOM_VALUES),
|
|
537
|
-
wixData.truncate(COLLECTIONS.CUSTOM_FIELDS),
|
|
543
|
+
siteconfig.customFields==="true" ? wixData.truncate(COLLECTIONS.CUSTOM_VALUES) : null,
|
|
544
|
+
siteconfig.customFields==="true" ? wixData.truncate(COLLECTIONS.CUSTOM_FIELDS) : null,
|
|
538
545
|
]);
|
|
539
546
|
console.log("cleared collections successfully");
|
|
540
547
|
}
|
|
@@ -115,6 +115,7 @@ async function fetchJobDescription(jobId,testObject=undefined) {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
async function htmlRichContentConverter(sections,richContentConverterToken) {
|
|
118
|
+
|
|
118
119
|
const richContentObject = {}
|
|
119
120
|
for (const [sectionTitle, sectionData] of Object.entries(sections)) {
|
|
120
121
|
if (sectionData.text) {
|
|
@@ -136,7 +137,8 @@ async function htmlRichContentConverter(sections,richContentConverterToken) {
|
|
|
136
137
|
);
|
|
137
138
|
if (response.ok) {
|
|
138
139
|
const data = await response.json();
|
|
139
|
-
|
|
140
|
+
const richContentWithSpacing=addSpacingToRichContent(sectionData.text,data.richContent.richContent);
|
|
141
|
+
richContentObject[sectionTitle] = richContentWithSpacing
|
|
140
142
|
}
|
|
141
143
|
else {
|
|
142
144
|
throw new Error("Error converting html to rich content response: "+response);
|
|
@@ -146,6 +148,178 @@ async function htmlRichContentConverter(sections,richContentConverterToken) {
|
|
|
146
148
|
return richContentObject;
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
//Adds empty paragraph nodes between sections in rich content
|
|
152
|
+
// to create visual spacing that the Wix RICOS converter strips out
|
|
153
|
+
function addSpacingToRichContent(html, richContent) {
|
|
154
|
+
if (!richContent || !richContent.nodes) {
|
|
155
|
+
return richContent;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Extract paragraph texts from HTML that end with  
|
|
159
|
+
const htmlParagraphsWithSpace = [];
|
|
160
|
+
// Extract paragraphs with <br> tags
|
|
161
|
+
const htmlParagraphsWithBr = new Map(); // text -> array of parts split by <br>
|
|
162
|
+
|
|
163
|
+
const pTagRegex = /<p>(.*?)<\/p>/gi;
|
|
164
|
+
let match;
|
|
165
|
+
|
|
166
|
+
while ((match = pTagRegex.exec(html)) !== null) {
|
|
167
|
+
const content = match[1];
|
|
168
|
+
|
|
169
|
+
// Check if this paragraph ends with   (before closing tags)
|
|
170
|
+
if (content.includes(' ')) {
|
|
171
|
+
const textOnly = content.replace(/<[^>]+>/g, '').trim();
|
|
172
|
+
htmlParagraphsWithSpace.push(textOnly);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check if this paragraph contains <br> tags
|
|
176
|
+
if (content.includes('<br>') || content.includes('<br/>') || content.includes('<br />')) {
|
|
177
|
+
// Split by <br> tags and extract text parts
|
|
178
|
+
const parts = content.split(/<br\s*\/?>/i).map(part =>
|
|
179
|
+
part.replace(/<[^>]+>/g, '').trim()
|
|
180
|
+
).filter(part => part.length > 0);
|
|
181
|
+
|
|
182
|
+
if (parts.length > 1) {
|
|
183
|
+
// Store the parts for this paragraph
|
|
184
|
+
const fullText = content.replace(/<[^>]+>/g, '').replace(/\s+/g, '').trim();
|
|
185
|
+
htmlParagraphsWithBr.set(fullText, parts);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const nodes = richContent.nodes;
|
|
191
|
+
const newNodes = [];
|
|
192
|
+
let nodeIdCounter = 0;
|
|
193
|
+
|
|
194
|
+
// Check if a paragraph is bold (has BOLD decoration)
|
|
195
|
+
const isBoldParagraph = (node) => {
|
|
196
|
+
if (node.type !== 'PARAGRAPH') return false;
|
|
197
|
+
const decorations = node.nodes?.[0]?.textData?.decorations || [];
|
|
198
|
+
return decorations.some(d => d.type === 'BOLD');
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Check if a paragraph node's text matches one with   in HTML
|
|
202
|
+
const needsSpacingAfter = (node) => {
|
|
203
|
+
if (node.type !== 'PARAGRAPH') return false;
|
|
204
|
+
|
|
205
|
+
// Add spacing after bold paragraphs
|
|
206
|
+
if (isBoldParagraph(node)) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const text = node.nodes?.[0]?.textData?.text || '';
|
|
211
|
+
const trimmedText = text.trim();
|
|
212
|
+
|
|
213
|
+
// Check if this text matches any HTML paragraph that had  
|
|
214
|
+
return htmlParagraphsWithSpace.some(htmlText => {
|
|
215
|
+
const cleanHtml = htmlText.replace(/ /g, ' ').trim();
|
|
216
|
+
return trimmedText.includes(cleanHtml) || cleanHtml.includes(trimmedText);
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// Check if a paragraph contains text that should be split by <br>
|
|
221
|
+
const shouldSplitByBr = (node) => {
|
|
222
|
+
if (node.type !== 'PARAGRAPH') return null;
|
|
223
|
+
|
|
224
|
+
const text = node.nodes?.[0]?.textData?.text || '';
|
|
225
|
+
const normalizedText = text.replace(/\s+/g, '').trim();
|
|
226
|
+
|
|
227
|
+
// Find matching HTML paragraph with <br>
|
|
228
|
+
for (const [htmlText, parts] of htmlParagraphsWithBr.entries()) {
|
|
229
|
+
if (normalizedText.includes(htmlText) || htmlText.includes(normalizedText)) {
|
|
230
|
+
return parts;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// Add spacing after bulleted lists
|
|
237
|
+
const isListEnd = (currentNode, nextNode) => {
|
|
238
|
+
return currentNode.type === 'BULLETED_LIST' &&
|
|
239
|
+
nextNode &&
|
|
240
|
+
nextNode.type === 'PARAGRAPH';
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
244
|
+
const currentNode = nodes[i];
|
|
245
|
+
const nextNode = nodes[i + 1];
|
|
246
|
+
|
|
247
|
+
// Check if this paragraph should be split by <br>
|
|
248
|
+
const brParts = shouldSplitByBr(currentNode);
|
|
249
|
+
if (brParts && brParts.length > 1) {
|
|
250
|
+
// Split into multiple paragraphs and add spacing between them
|
|
251
|
+
const decorations = currentNode.nodes?.[0]?.textData?.decorations || [];
|
|
252
|
+
|
|
253
|
+
brParts.forEach((part, idx) => {
|
|
254
|
+
newNodes.push({
|
|
255
|
+
...currentNode,
|
|
256
|
+
id: `${currentNode.id}_split_${idx}`,
|
|
257
|
+
nodes: [{
|
|
258
|
+
type: "TEXT",
|
|
259
|
+
id: "",
|
|
260
|
+
nodes: [],
|
|
261
|
+
textData: {
|
|
262
|
+
text: part,
|
|
263
|
+
decorations: decorations
|
|
264
|
+
}
|
|
265
|
+
}]
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Add empty paragraph after each split part except the last
|
|
269
|
+
if (idx < brParts.length - 1) {
|
|
270
|
+
newNodes.push(createEmptyParagraph(`empty_br_${nodeIdCounter++}`));
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Add spacing after the split paragraphs if there's a next node
|
|
275
|
+
if (nextNode) {
|
|
276
|
+
newNodes.push(createEmptyParagraph(`empty_${nodeIdCounter++}`));
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
newNodes.push(currentNode);
|
|
280
|
+
|
|
281
|
+
// Add empty paragraph ONLY after paragraphs with   or after lists
|
|
282
|
+
if ((needsSpacingAfter(currentNode) || isListEnd(currentNode, nextNode)) && nextNode) {
|
|
283
|
+
newNodes.push(createEmptyParagraph(`empty_${nodeIdCounter++}`));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
...richContent,
|
|
290
|
+
nodes: newNodes
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function createEmptyParagraph(id) {
|
|
295
|
+
return {
|
|
296
|
+
type: "PARAGRAPH",
|
|
297
|
+
id: id,
|
|
298
|
+
nodes: [
|
|
299
|
+
{
|
|
300
|
+
type: "TEXT",
|
|
301
|
+
id: "",
|
|
302
|
+
nodes: [],
|
|
303
|
+
textData: {
|
|
304
|
+
text: "",
|
|
305
|
+
decorations: []
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
paragraphData: {
|
|
310
|
+
textStyle: {
|
|
311
|
+
textAlignment: "AUTO"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
149
323
|
|
|
150
324
|
|
|
151
325
|
|
package/package.json
CHANGED
|
@@ -253,6 +253,7 @@ async function handleParams(_$w,param,values) {
|
|
|
253
253
|
_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = pagination.currentPage.toString();
|
|
254
254
|
_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = nextPageJobs;
|
|
255
255
|
handlePaginationButtons(_$w);
|
|
256
|
+
await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).scrollTo();
|
|
256
257
|
});
|
|
257
258
|
|
|
258
259
|
_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_PREVIOUS).onClick(async () => {
|
|
@@ -261,6 +262,7 @@ async function handleParams(_$w,param,values) {
|
|
|
261
262
|
_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = pagination.currentPage.toString();
|
|
262
263
|
_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = previousPageJobs;
|
|
263
264
|
handlePaginationButtons(_$w);
|
|
265
|
+
await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).scrollTo();
|
|
264
266
|
});
|
|
265
267
|
} catch (error) {
|
|
266
268
|
console.error('Failed to load pagination buttons:', error);
|
|
@@ -482,6 +484,8 @@ function getValueFromValueId(valueIds, value) {
|
|
|
482
484
|
? withCounts.filter(o => (o.label || '').toLowerCase().includes(searchQuery))
|
|
483
485
|
: withCounts;
|
|
484
486
|
|
|
487
|
+
// Sort alphabetically by label
|
|
488
|
+
filtered.sort((a, b) => (a.label || '').localeCompare(b.label || ''));
|
|
485
489
|
// Preserve currently selected values that are still visible
|
|
486
490
|
// let prevSelected=[]
|
|
487
491
|
// clearAll? prevSelected=[]:prevSelected= _$w(`#${FiltersIds[fieldTitle]}CheckBox`).value;
|