sr-npm 3.1.20 → 3.1.23

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.
@@ -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
- richContentObject[sectionTitle] = data.richContent.richContent;
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 &#xa0; (before closing tags)
170
+ if (content.includes('&#xa0;')) {
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 &#xa0; 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 &#xa0;
214
+ return htmlParagraphsWithSpace.some(htmlText => {
215
+ const cleanHtml = htmlText.replace(/&#xa0;/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 &#xa0; 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sr-npm",
3
- "version": "3.1.20",
3
+ "version": "3.1.23",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -54,13 +54,14 @@ async function careersMultiBoxesPageOnReady(_$w,urlParams) {
54
54
  loadSelectedValuesRepeater(_$w);
55
55
  bindSearchInput(_$w);
56
56
  loadPaginationButtons(_$w);
57
- if (await window.formFactor() === "Mobile") {
58
- handleFilterInMobile(_$w);
59
- }
57
+
60
58
  await handleUrlParams(_$w, urlParams);
61
59
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.CLEAR_ALL_BUTTON_ID).onClick(async () => {
62
60
  await clearAll(_$w);
63
61
  });
62
+ if (await window.formFactor() === "Mobile") {
63
+ handleFilterInMobile(_$w);
64
+ }
64
65
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.RESULTS_MULTI_STATE_BOX).changeState("results");
65
66
  }
66
67
 
@@ -113,16 +114,26 @@ function handleFilterInMobile(_$w) {
113
114
  CAREERS_PAGE_SELECTORS.SECTION_3,
114
115
  CAREERS_PAGE_SELECTORS.LINE_3,
115
116
  CAREERS_PAGE_SELECTORS.FILTER_ICON];
117
+
118
+ const mobileFilterBoxSelectors = [
119
+ CAREERS_PAGE_SELECTORS.FILTER_BOX,
120
+ CAREERS_PAGE_SELECTORS.REFINE_SEARCH_BUTTON,
121
+ CAREERS_PAGE_SELECTORS.EXIT_BUTTON,
122
+ ];
116
123
 
117
124
  _$w(CAREERS_PAGE_SELECTORS.FILTER_ICON).onClick(()=>{
118
- _$w(CAREERS_PAGE_SELECTORS.FILTER_BOX).expand();
125
+ mobileFilterBoxSelectors.forEach(selector => {
126
+ _$w(selector).expand();
127
+ });
119
128
  searchResultsSelectors.forEach(selector => {
120
129
  _$w(selector).collapse();
121
130
  });
122
131
  });
123
132
 
124
133
  const exitFilterBox = () => {
125
- _$w(CAREERS_PAGE_SELECTORS.FILTER_BOX).collapse();
134
+ mobileFilterBoxSelectors.forEach(selector => {
135
+ _$w(selector).collapse();
136
+ });
126
137
  searchResultsSelectors.forEach(selector => {
127
138
  _$w(selector).expand();
128
139
  });
@@ -135,6 +146,11 @@ function handleFilterInMobile(_$w) {
135
146
  _$w(CAREERS_PAGE_SELECTORS.REFINE_SEARCH_BUTTON).onClick(()=>{
136
147
  exitFilterBox();
137
148
  });
149
+
150
+ //onmobile we should collapse the filter box and the refine search button by default
151
+ mobileFilterBoxSelectors.forEach(selector => {
152
+ _$w(selector).collapse();
153
+ });
138
154
  }
139
155
 
140
156
 
@@ -237,6 +253,7 @@ async function handleParams(_$w,param,values) {
237
253
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = pagination.currentPage.toString();
238
254
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = nextPageJobs;
239
255
  handlePaginationButtons(_$w);
256
+ await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).scrollTo();
240
257
  });
241
258
 
242
259
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_PREVIOUS).onClick(async () => {
@@ -245,6 +262,7 @@ async function handleParams(_$w,param,values) {
245
262
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = pagination.currentPage.toString();
246
263
  _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = previousPageJobs;
247
264
  handlePaginationButtons(_$w);
265
+ await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).scrollTo();
248
266
  });
249
267
  } catch (error) {
250
268
  console.error('Failed to load pagination buttons:', error);
@@ -466,6 +484,8 @@ function getValueFromValueId(valueIds, value) {
466
484
  ? withCounts.filter(o => (o.label || '').toLowerCase().includes(searchQuery))
467
485
  : withCounts;
468
486
 
487
+ // Sort alphabetically by label
488
+ filtered.sort((a, b) => (a.label || '').localeCompare(b.label || ''));
469
489
  // Preserve currently selected values that are still visible
470
490
  // let prevSelected=[]
471
491
  // clearAll? prevSelected=[]:prevSelected= _$w(`#${FiltersIds[fieldTitle]}CheckBox`).value;
@@ -192,18 +192,18 @@ function init(_$w) {
192
192
  searchInputBlurredFirstTime=false;
193
193
  }
194
194
  });
195
- _$w(CAREERS_PAGE_SELECTORS.DROPDOWN_DEPARTMENT, CAREERS_PAGE_SELECTORS.DROPDOWN_LOCATION, CAREERS_PAGE_SELECTORS.DROPDOWN_JOB_TYPE, CAREERS_PAGE_SELECTORS.DROPDOWN_BRAND).onChange(()=>{
195
+ _$w(CAREERS_PAGE_SELECTORS.DROPDOWN_DEPARTMENT+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_LOCATION+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_JOB_TYPE+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_BRAND).onChange(()=>{
196
196
  console.log("dropdown onChange is triggered");
197
197
  applyFilters(_$w);
198
198
  });
199
- _$w(CAREERS_PAGE_SELECTORS.RESET_FILTERS_BUTTON, CAREERS_PAGE_SELECTORS.CLEAR_SEARCH).onClick(()=>resetFilters(_$w));
199
+ _$w(CAREERS_PAGE_SELECTORS.RESET_FILTERS_BUTTON+', '+ CAREERS_PAGE_SELECTORS.CLEAR_SEARCH).onClick(()=>resetFilters(_$w));
200
200
 
201
201
  _$w(CAREERS_PAGE_SELECTORS.OPEN_FILTERS_BUTTON).onClick(()=>{
202
- _$w(CAREERS_PAGE_SELECTORS.DROPDOWN_CONTAINER, CAREERS_PAGE_SELECTORS.CLOSE_FILTERS_BUTTON).expand();
202
+ _$w(CAREERS_PAGE_SELECTORS.DROPDOWN_CONTAINER+', '+ CAREERS_PAGE_SELECTORS.CLOSE_FILTERS_BUTTON).expand();
203
203
  });
204
204
 
205
205
  _$w(CAREERS_PAGE_SELECTORS.CLOSE_FILTERS_BUTTON).onClick(()=>{
206
- _$w(CAREERS_PAGE_SELECTORS.DROPDOWN_CONTAINER, CAREERS_PAGE_SELECTORS.CLOSE_FILTERS_BUTTON).collapse();
206
+ _$w(CAREERS_PAGE_SELECTORS.DROPDOWN_CONTAINER+', '+ CAREERS_PAGE_SELECTORS.CLOSE_FILTERS_BUTTON).collapse();
207
207
  });
208
208
 
209
209
  //URL onChange
@@ -355,7 +355,7 @@ async function applyFilters(_$w, skipUrlUpdate = false) {
355
355
  }
356
356
 
357
357
  async function resetFilters(_$w) {
358
- _$w(CAREERS_PAGE_SELECTORS.SEARCH_INPUT, CAREERS_PAGE_SELECTORS.DROPDOWN_DEPARTMENT, CAREERS_PAGE_SELECTORS.DROPDOWN_LOCATION, CAREERS_PAGE_SELECTORS.DROPDOWN_JOB_TYPE, CAREERS_PAGE_SELECTORS.DROPDOWN_BRAND).value = '';
358
+ _$w(CAREERS_PAGE_SELECTORS.SEARCH_INPUT+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_DEPARTMENT+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_LOCATION+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_JOB_TYPE+', '+ CAREERS_PAGE_SELECTORS.DROPDOWN_BRAND).value = '';
359
359
 
360
360
  await _$w(GLOBAL_SECTIONS_SELECTORS.JOBS_DATASET).setFilter(wixData.filter());
361
361
  await _$w(GLOBAL_SECTIONS_SELECTORS.JOBS_DATASET).refresh();
@@ -404,8 +404,7 @@ async function handleDepartmentParam(_$w,department) {
404
404
  queryParams.remove(["department" ]);
405
405
 
406
406
  }
407
-
408
-
407
+
409
408
 
410
409
  }
411
410
 
package/pages/homePage.js CHANGED
@@ -7,6 +7,7 @@ const { COLLECTIONS } = require('../backend/collectionConsts');
7
7
  const { getAllRecords } = require('./pagesUtils');
8
8
  const { handlePrimarySearch } = require('../public/primarySearchUtils');
9
9
  const { GLOBAL_SECTIONS_SELECTORS } = require('../public/selectors');
10
+ const { isElementExistOnPage } = require('psdev-utils');
10
11
 
11
12
  let thisObjectVar;
12
13
  let searchByCityFlag=false;
@@ -65,35 +66,22 @@ function bind(_$w) {
65
66
  function bindTeamRepeater(_$w) {
66
67
  _$w('#teamRepeater').onItemReady(($item, itemData) => {
67
68
  $item('#teamButton').label = `View ${itemData.count} Open Positions`;
68
- // const department = encodeURIComponent(itemData.title);
69
- // if (itemData.customField) {
70
- // [$item('#teamButton'), $item('#teamButton2')].forEach(btn => {
71
- // btn.onClick(() => {
72
- // location.to(`/search?category=${department}`);
73
- // });
74
- // });
75
-
76
- // }
77
- // else{
78
- // $item('#teamButton').onClick(()=>{
79
- // location.to(`/positions?department=${department}`);
80
- // });
81
- // }
82
69
  });
83
70
 
84
71
  _$w("#teamRepeaterItem").onClick((event) => {
85
72
 
86
73
  const $item = _$w.at(event.context);
87
74
 
88
- if(_$w("#categoriesDataset")) {
75
+ if(isElementExistOnPage(_$w("#categoriesDataset"))) {
89
76
  const clickedItemData = $item("#categoriesDataset").getCurrentItem();
90
77
  const department = encodeURIComponent(clickedItemData.title);
91
78
  location.to(`/search?category=${department}`);
92
79
  }
93
80
  else
94
81
  {
95
- console.log("check SR templates and do this ")
96
-
82
+ const clickedItemData = $item("#dataset1").getCurrentItem()
83
+ const department = encodeURIComponent(clickedItemData.title);
84
+ location.to(`/positions?department=${department}`);
97
85
  }
98
86
  });
99
87
 
@@ -10,8 +10,6 @@ const {
10
10
  } = require('../public/utils');
11
11
 
12
12
 
13
-
14
-
15
13
  async function positionPageOnReady(_$w) {
16
14
  console.log("positionPageOnReady called");
17
15
  await bind(_$w);
@@ -90,8 +88,14 @@ async function getCategoryValue(customValues) {
90
88
  }
91
89
 
92
90
  function handleReferFriendButton(_$w,item) {
93
- if(!item.referFriendLink && isElementExistOnPage(_$w('#referFriendButton'))){
94
- _$w('#referFriendButton').hide();
91
+ if(isElementExistOnPage(_$w('#referFriendButton'))){
92
+ if(!item.referFriendLink){
93
+ _$w('#referFriendButton').hide();
94
+ }
95
+ else {
96
+ _$w('#referFriendButton').target="_blank";
97
+ _$w('#referFriendButton').link=item.referFriendLink;
98
+ }
95
99
  }
96
100
  }
97
101
 
@@ -153,4 +153,5 @@ return count > 0;
153
153
 
154
154
  module.exports = {
155
155
  handlePrimarySearch,
156
+ queryPrimarySearchResults
156
157
  }