@financial-times/n-myft-ui 28.0.7 → 28.1.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.
@@ -4,7 +4,7 @@
4
4
  data-myft-ui="saved"
5
5
  action="/myft/save/{{contentId}}"
6
6
  data-js-action="/__myft/api/core/saved/content/{{contentId}}?method=put"
7
- {{#ifEquals @root.flags.professorLists 'variant'}}data-myft-ui-variant="createListAndSaveArticleVariant"{{/ifEquals}}>
7
+ {{#if @root.flags.manageArticleLists}}data-myft-ui-save-new="manageArticleLists"{{/if}}>
8
8
  {{> n-myft-ui/components/csrf-token/input}}
9
9
  <div
10
10
  class="n-myft-ui__announcement o-normalise-visually-hidden"
package/myft/ui/lists.js CHANGED
@@ -179,8 +179,8 @@ function handleArticleSaved (contentId) {
179
179
  function openCreateListAndAddArticleOverlay (contentId) {
180
180
  return myFtClient.getAll('created', 'list')
181
181
  .then(createdLists => createdLists.filter(list => !list.isRedirect))
182
- .then(createdLists => {
183
- return !createdLists.length ? showCreateListAndAddArticleOverlay(contentId) : showArticleSavedOverlay(contentId);
182
+ .then(() => {
183
+ return showCreateListAndAddArticleOverlay(contentId);
184
184
  });
185
185
  }
186
186
 
@@ -192,8 +192,8 @@ function initialEventListeners () {
192
192
  // Checks if the createListAndSaveArticle variant is active
193
193
  // and will show the variant overlay if the user has no lists,
194
194
  // otherwise it will show the classic overlay
195
- const createListVariant = event.currentTarget.querySelector('[data-myft-ui-variant="createListAndSaveArticleVariant"]');
196
- if (createListVariant) {
195
+ const createNewListDesign = event.currentTarget.querySelector('[data-myft-ui-save-new="manageArticleLists"]');
196
+ if (createNewListDesign) {
197
197
  return openCreateListAndAddArticleOverlay(contentId);
198
198
  }
199
199
 
@@ -5,20 +5,14 @@ import getToken from './lib/get-csrf-token';
5
5
 
6
6
  const csrfToken = getToken();
7
7
 
8
- let lists;
8
+ let lists = [];
9
+ let haveLoadedLists = false;
9
10
 
10
- export default async function showSaveArticleToListVariant (name, contentId) {
11
- try {
12
- await openSaveArticleToListVariant (name, contentId);
13
- } catch(error) {
14
- handleError(error);
15
- }
16
- }
17
-
18
- async function openSaveArticleToListVariant (name, contentId) {
11
+ export default async function openSaveArticleToListVariant (name, contentId) {
19
12
  function createList (list) {
20
13
  if(!list) {
21
- return;
14
+ if (!lists.length) attachDescription();
15
+ return contentElement.addEventListener('click', openFormHandler, { once: true });
22
16
  }
23
17
 
24
18
  myFtClient.add('user', null, 'created', 'list', uuid(), { name: list, token: csrfToken })
@@ -33,6 +27,10 @@ async function openSaveArticleToListVariant (name, contentId) {
33
27
  triggerCreateListEvent(contentId);
34
28
  contentElement.addEventListener('click', openFormHandler, { once: true });
35
29
  });
30
+ })
31
+ .catch(() => {
32
+ if (!lists.length) attachDescription();
33
+ return contentElement.addEventListener('click', openFormHandler, { once: true });
36
34
  });
37
35
  }
38
36
 
@@ -66,8 +64,9 @@ async function openSaveArticleToListVariant (name, contentId) {
66
64
  });
67
65
  }
68
66
 
69
- if (!lists) {
67
+ if (!haveLoadedLists) {
70
68
  lists = await getLists(contentId);
69
+ haveLoadedLists = true;
71
70
  }
72
71
 
73
72
  const overlays = Overlay.getOverlays();
@@ -77,7 +76,7 @@ async function openSaveArticleToListVariant (name, contentId) {
77
76
  }
78
77
 
79
78
  const headingElement = HeadingElement();
80
- let [contentElement, removeDescription] = ContentElement(!lists.length);
79
+ let [contentElement, removeDescription, attachDescription] = ContentElement(!lists.length);
81
80
 
82
81
  const createListOverlay = new Overlay(name, {
83
82
  html: contentElement,
@@ -87,36 +86,37 @@ async function openSaveArticleToListVariant (name, contentId) {
87
86
  class: 'myft-ui-create-list-variant',
88
87
  });
89
88
 
90
- const realignListener = realignOverlay(window.scrollY);
91
-
92
89
  function outsideClickHandler (e) {
93
- try {
94
- const overlayContent = document.querySelector('.o-overlay__content');
95
- if(!overlayContent || !overlayContent.contains(e.target)) {
96
- createListOverlay.close();
97
- }
98
- } catch(error) {
99
- handleError(error);
90
+ const overlayContent = document.querySelector('.o-overlay__content');
91
+ if(createListOverlay.visible && (!overlayContent || !overlayContent.contains(e.target))) {
92
+ createListOverlay.close();
100
93
  }
101
94
  }
102
95
 
103
96
  function openFormHandler () {
104
- try {
105
- const formElement = FormElement(createList);
106
- const overlayContent = document.querySelector('.o-overlay__content');
107
- removeDescription();
108
- overlayContent.insertAdjacentElement('beforeend', formElement);
109
- formElement.elements[0].focus();
110
- } catch(error) {
111
- handleError(error);
112
- }
97
+ const formElement = FormElement(createList);
98
+ const overlayContent = document.querySelector('.o-overlay__content');
99
+ removeDescription();
100
+ overlayContent.insertAdjacentElement('beforeend', formElement);
101
+ formElement.elements[0].focus();
102
+ }
103
+
104
+ function getScrollHandler (target) {
105
+ return realignOverlay(window.scrollY, target);
106
+ }
107
+
108
+ function resizeHandler () {
109
+ positionOverlay(createListOverlay.wrapper);
113
110
  }
114
111
 
115
112
  createListOverlay.open();
113
+
114
+ const scrollHandler = getScrollHandler(createListOverlay.wrapper);
115
+
116
116
  createListOverlay.wrapper.addEventListener('oOverlay.ready', (data) => {
117
- realignListener(data.currentTarget);
117
+ positionOverlay(data.currentTarget);
118
118
 
119
- if (lists && lists.length) {
119
+ if (lists.length) {
120
120
  const listElement = ListsElement(lists, addToList, removeFromList);
121
121
  const overlayContent = document.querySelector('.o-overlay__content');
122
122
  overlayContent.insertAdjacentElement('afterbegin', listElement);
@@ -125,12 +125,16 @@ async function openSaveArticleToListVariant (name, contentId) {
125
125
  contentElement.addEventListener('click', openFormHandler, { once: true });
126
126
 
127
127
  document.querySelector('.article-content').addEventListener('click', outsideClickHandler, { once: true });
128
+
129
+ window.addEventListener('scroll', scrollHandler);
130
+
131
+ window.addEventListener('oViewport.resize', resizeHandler);
128
132
  });
129
133
 
130
- window.addEventListener('scroll', realignListener(createListOverlay.wrapper, window.scrollY));
134
+ createListOverlay.wrapper.addEventListener('oOverlay.destroy', () => {
135
+ window.removeEventListener('scroll', scrollHandler);
131
136
 
132
- window.addEventListener('oViewport.resize', () => {
133
- realignListener(createListOverlay.wrapper);
137
+ window.removeEventListener('oViewport.resize', resizeHandler);
134
138
  });
135
139
  }
136
140
 
@@ -157,16 +161,12 @@ function FormElement (createList) {
157
161
  const formElement = stringToHTMLElement(formString);
158
162
 
159
163
  function handleSubmit (event) {
160
- try {
161
- event.preventDefault();
162
- event.stopPropagation();
163
- const inputListName = formElement.querySelector('input[name="list-name"]');
164
- createList(inputListName.value);
165
- inputListName.value = '';
166
- formElement.remove();
167
- } catch(error) {
168
- handleError(error);
169
- }
164
+ event.preventDefault();
165
+ event.stopPropagation();
166
+ const inputListName = formElement.querySelector('input[name="list-name"]');
167
+ createList(inputListName.value);
168
+ inputListName.value = '';
169
+ formElement.remove();
170
170
  }
171
171
 
172
172
  formElement.querySelector('button[type="submit"]').addEventListener('click', handleSubmit);
@@ -174,12 +174,14 @@ function FormElement (createList) {
174
174
  return formElement;
175
175
  }
176
176
 
177
- function ContentElement (description) {
177
+ function ContentElement (hasDescription) {
178
+ const description = '<p class="myft-ui-create-list-variant-add-description">Lists are a simple way to curate your content</p>';
179
+
178
180
  const content = `
179
181
  <div class="myft-ui-create-list-variant-footer">
180
182
  <button class="myft-ui-create-list-variant-add">Add to a new list</button>
181
- ${description ? `
182
- <p class="myft-ui-create-list-variant-add-description">Lists are a simple way to curate your content</p>
183
+ ${hasDescription ? `
184
+ ${description}
183
185
  ` : ''}
184
186
  </div>
185
187
  `;
@@ -193,7 +195,12 @@ function ContentElement (description) {
193
195
  }
194
196
  }
195
197
 
196
- return [contentElement, removeDescription];
198
+ function attachDescription () {
199
+ const descriptionElement = stringToHTMLElement(description);
200
+ contentElement.insertAdjacentElement('beforeend', descriptionElement);
201
+ }
202
+
203
+ return [contentElement, removeDescription, attachDescription];
197
204
  }
198
205
 
199
206
  function HeadingElement () {
@@ -256,36 +263,41 @@ function ListCheckboxElement (addToList, removeFromList) {
256
263
  };
257
264
  }
258
265
 
259
- function realignOverlay (originalScrollPosition) {
260
- return function (target, currentScrollPosition) {
261
- try {
262
- if(currentScrollPosition && Math.abs(currentScrollPosition - originalScrollPosition) < 120) {
263
- return;
264
- }
265
-
266
- originalScrollPosition = currentScrollPosition;
267
-
268
- target.style['min-width'] = '340px';
269
- target.style['width'] = '100%';
270
- target.style['margin-top'] = '-50px';
271
- target.style['left'] = 0;
272
-
273
- if (isMobile()) {
274
- target.style['position'] = 'absolute';
275
- target.style['margin-left'] = 0;
276
- target.style['margin-top'] = 0;
277
- target.style['top'] = calculateLargerScreenHalf(target) === 'ABOVE' ? '-120px' : '50px';
278
- } else {
279
- target.style['position'] = 'absolute';
280
- target.style['margin-left'] = '45px';
281
- target.style['top'] = '220px';
282
- }
283
- } catch (error) {
284
- handleError(error);
266
+ function realignOverlay (originalScrollPosition, target) {
267
+ return function () {
268
+ const currentScrollPosition = window.scrollY;
269
+
270
+ if(Math.abs(currentScrollPosition - originalScrollPosition) < 120) {
271
+ return;
285
272
  }
273
+
274
+ if (currentScrollPosition) {
275
+ originalScrollPosition = currentScrollPosition;;
276
+ }
277
+
278
+ positionOverlay(target);
286
279
  };
287
280
  }
288
281
 
282
+ function positionOverlay (target) {
283
+ target.style['min-width'] = '340px';
284
+ target.style['width'] = '100%';
285
+ target.style['margin-top'] = '-50px';
286
+ target.style['left'] = 0;
287
+
288
+ if (isMobile()) {
289
+ const shareNavComponent = document.querySelector('.share-nav__horizontal');
290
+ target.style['position'] = 'absolute';
291
+ target.style['margin-left'] = 0;
292
+ target.style['margin-top'] = 0;
293
+ target.style['top'] = calculateLargerScreenHalf(shareNavComponent) === 'ABOVE' ? '-120px' : '50px';
294
+ } else {
295
+ target.style['position'] = 'absolute';
296
+ target.style['margin-left'] = '45px';
297
+ target.style['top'] = '220px';
298
+ }
299
+ }
300
+
289
301
  function isMobile () {
290
302
  const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
291
303
 
@@ -293,6 +305,10 @@ function isMobile () {
293
305
  }
294
306
 
295
307
  function calculateLargerScreenHalf (target) {
308
+ if (!target) {
309
+ return 'BELOW';
310
+ }
311
+
296
312
  const vh = Math.min(document.documentElement.clientHeight || 0, window.innerHeight || 0);
297
313
 
298
314
  const targetBox = target.getBoundingClientRect();
@@ -357,13 +373,3 @@ function triggerCreateListEvent (contentId) {
357
373
  bubbles: true
358
374
  }));
359
375
  }
360
-
361
- function handleError (error) {
362
- document.body.dispatchEvent(new CustomEvent('oErrors.log', {
363
- bubbles: true,
364
- detail: {
365
- error,
366
- info: { component: 'professorLists' },
367
- }
368
- }));
369
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/n-myft-ui",
3
- "version": "28.0.7",
3
+ "version": "28.1.0",
4
4
  "description": "Client side component for interaction with myft",
5
5
  "main": "server.js",
6
6
  "scripts": {