Skip to content

Commit e09e23f

Browse files
authored
Merge pull request #569 from ProgressPlanner/develop
v1.7.1
2 parents f6f7a25 + 2d225e2 commit e09e23f

20 files changed

+546
-378
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
= 1.7.1 =
2+
3+
Bugs we fixed:
4+
5+
* Fix weird interactive task popover behaviour on small screens
6+
* Fix missing pages (page types) from the Settings screen
7+
* Clear WP API model schema cache in session storage
8+
* Make interactive tasks work on WP dashboard screen
9+
* Exclude taxonomies which are marked as not indexable in Yoast SEO
10+
* Improve completed task check for "Unpublished content" task
11+
* Remove awarded point if the golden todo task is set back to pending status
12+
* Fix "Delete the 'Sample Page' page" interactive task
13+
* Remove 3rd party plugin tasks if they are deactivated.
14+
115
= 1.7.0 =
216

317
Added these recommendations from Ravi:

assets/js/recommendations/core-blogdescription.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ prplInteractiveTaskFormListener.siteSettings( {
1515

1616
document
1717
.querySelector( 'input#blogdescription' )
18-
.addEventListener( 'input', function ( e ) {
18+
?.addEventListener( 'input', function ( e ) {
1919
const button = document.querySelector(
2020
'[popover-id="prpl-popover-core-blogdescription"] button[type="submit"]'
2121
);

assets/js/recommendations/interactive-task.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,16 @@ const prplInteractiveTaskFormListener = {
5151
const settings = new wp.api.models.Settings( settingsToPass );
5252

5353
settings.save().then( () => {
54-
// Close popover.
55-
document.getElementById( popoverId ).hidePopover();
5654
const postId = parseInt( taskEl.dataset.postId );
5755
if ( ! postId ) {
5856
return;
5957
}
6058

6159
// This will trigger the celebration event (confetti) as well.
62-
prplSuggestedTask.maybeComplete( postId );
60+
prplSuggestedTask.maybeComplete( postId ).then( () => {
61+
// Close popover.
62+
document.getElementById( popoverId ).hidePopover();
63+
} );
6364
} );
6465
} );
6566
} );
@@ -82,15 +83,16 @@ const prplInteractiveTaskFormListener = {
8283
`.prpl-suggested-task[data-task-id="${ taskId }"]`
8384
);
8485

85-
// Close popover.
86-
document.getElementById( popoverId ).hidePopover();
8786
const postId = parseInt( taskEl.dataset.postId );
8887
if ( ! postId ) {
8988
return;
9089
}
9190

9291
// This will trigger the celebration event (confetti) as well.
93-
prplSuggestedTask.maybeComplete( postId );
92+
prplSuggestedTask.maybeComplete( postId ).then( () => {
93+
// Close popover.
94+
document.getElementById( popoverId ).hidePopover();
95+
} );
9496
} );
9597
},
9698

@@ -136,15 +138,16 @@ const prplInteractiveTaskFormListener = {
136138
return;
137139
}
138140

139-
// Close popover.
140-
document.getElementById( popoverId ).hidePopover();
141141
const postId = parseInt( taskEl.dataset.postId );
142142
if ( ! postId ) {
143143
return;
144144
}
145145

146146
// This will trigger the celebration event (confetti) as well.
147-
prplSuggestedTask.maybeComplete( postId );
147+
prplSuggestedTask.maybeComplete( postId ).then( () => {
148+
// Close popover.
149+
document.getElementById( popoverId ).hidePopover();
150+
} );
148151
} );
149152
} );
150153
},

assets/js/recommendations/sample-page.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ prplInteractiveTaskFormListener.customSubmit( {
1010
taskId: 'sample-page',
1111
popoverId: 'prpl-popover-sample-page',
1212
callback: () => {
13-
const post = new wp.api.models.Post( {
13+
const post = new wp.api.models.Page( {
1414
id: samplePageData.postId,
1515
} );
1616
post.fetch().then( () => {

assets/js/suggested-task.js

Lines changed: 143 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -242,59 +242,148 @@ prplSuggestedTask = {
242242
* @param {number} postId The post ID.
243243
*/
244244
maybeComplete: ( postId ) => {
245-
// Get the task.
246-
const post = new wp.api.models.Prpl_recommendations( { id: postId } );
247-
post.fetch().then( ( postData ) => {
248-
const taskProviderId = prplTerms.getTerm(
249-
postData?.[ prplTerms.provider ],
250-
prplTerms.provider
251-
).slug;
252-
const taskCategorySlug = prplTerms.getTerm(
253-
postData?.[ prplTerms.category ],
254-
prplTerms.category
255-
).slug;
256-
257-
const el = prplSuggestedTask.getTaskElement( postId );
245+
// Return the promise chain so callers can wait for completion
246+
return new Promise( ( resolve, reject ) => {
247+
// Get the task.
248+
const post = new wp.api.models.Prpl_recommendations( {
249+
id: postId,
250+
} );
251+
post.fetch()
252+
.then( ( postData ) => {
253+
const taskProviderId = prplTerms.getTerm(
254+
postData?.[ prplTerms.provider ],
255+
prplTerms.provider
256+
).slug;
257+
const taskCategorySlug = prplTerms.getTerm(
258+
postData?.[ prplTerms.category ],
259+
prplTerms.category
260+
).slug;
261+
262+
const el = prplSuggestedTask.getTaskElement( postId );
263+
264+
// Dismissable tasks don't have pending status, it's either publish or trash.
265+
const newStatus =
266+
'publish' === postData.status ? 'trash' : 'publish';
267+
268+
// Disable the checkbox for RR tasks, to prevent multiple clicks.
269+
el.querySelector(
270+
'.prpl-suggested-task-checkbox'
271+
).setAttribute( 'disabled', 'disabled' );
272+
273+
post.set( 'status', newStatus )
274+
.save()
275+
.then( () => {
276+
prplSuggestedTask.runTaskAction(
277+
postId,
278+
'trash' === newStatus ? 'complete' : 'pending'
279+
);
280+
const eventPoints = parseInt(
281+
postData?.meta?.prpl_points
282+
);
258283

259-
// Dismissable tasks don't have pending status, it's either publish or trash.
260-
const newStatus =
261-
'publish' === postData.status ? 'trash' : 'publish';
284+
// Task is trashed, check if we need to celebrate.
285+
if ( 'trash' === newStatus ) {
286+
el.setAttribute(
287+
'data-task-action',
288+
'celebrate'
289+
);
290+
if ( 'user' === taskProviderId ) {
291+
// Set class to trigger strike through animation.
292+
el.classList.add(
293+
'prpl-suggested-task-celebrated'
294+
);
295+
296+
setTimeout( () => {
297+
// Move task from published to trash.
298+
document
299+
.getElementById(
300+
'todo-list-completed'
301+
)
302+
.insertAdjacentElement(
303+
'beforeend',
304+
el
305+
);
306+
307+
// Remove the class to trigger the strike through animation.
308+
el.classList.remove(
309+
'prpl-suggested-task-celebrated'
310+
);
311+
312+
window.dispatchEvent(
313+
new CustomEvent(
314+
'prpl/grid/resize'
315+
)
316+
);
317+
318+
// Remove the disabled attribute for user tasks, so they can be clicked again.
319+
el.querySelector(
320+
'.prpl-suggested-task-checkbox'
321+
).removeAttribute( 'disabled' );
322+
323+
// Resolve the promise after the timeout completes
324+
resolve( {
325+
postId,
326+
newStatus,
327+
eventPoints,
328+
} );
329+
}, 2000 );
330+
} else {
331+
/**
332+
* Strike completed tasks and remove them from the DOM.
333+
*/
334+
document.dispatchEvent(
335+
new CustomEvent(
336+
'prpl/removeCelebratedTasks'
337+
)
338+
);
339+
340+
// Inject more tasks from the same category.
341+
prplSuggestedTask.injectItemsFromCategory( {
342+
category: taskCategorySlug,
343+
status: [ 'publish' ],
344+
} );
345+
346+
// Resolve immediately for non-user tasks
347+
resolve( {
348+
postId,
349+
newStatus,
350+
eventPoints,
351+
} );
352+
}
353+
354+
// We trigger celebration only if the task has points.
355+
if ( 0 < eventPoints ) {
356+
prplUpdateRaviGauge( eventPoints );
357+
358+
// Trigger the celebration event (confetti).
359+
document.dispatchEvent(
360+
new CustomEvent(
361+
'prpl/celebrateTasks',
362+
{
363+
detail: { element: el },
364+
}
365+
)
366+
);
367+
}
368+
} else if (
369+
'publish' === newStatus &&
370+
'user' === taskProviderId
371+
) {
372+
// This is only possible for user tasks.
373+
// Set the task action to publish.
374+
el.setAttribute(
375+
'data-task-action',
376+
'publish'
377+
);
262378

263-
// Disable the checkbox for RR tasks, to prevent multiple clicks.
264-
el.querySelector( '.prpl-suggested-task-checkbox' ).setAttribute(
265-
'disabled',
266-
'disabled'
267-
);
379+
// Update the Ravi gauge.
380+
prplUpdateRaviGauge( 0 - eventPoints );
268381

269-
post.set( 'status', newStatus )
270-
.save()
271-
.then( () => {
272-
prplSuggestedTask.runTaskAction(
273-
postId,
274-
'trash' === newStatus ? 'complete' : 'pending'
275-
);
276-
const eventPoints = parseInt( postData?.meta?.prpl_points );
277-
278-
// Task is trashed, check if we need to celebrate.
279-
if ( 'trash' === newStatus ) {
280-
el.setAttribute( 'data-task-action', 'celebrate' );
281-
if ( 'user' === taskProviderId ) {
282-
// Set class to trigger strike through animation.
283-
el.classList.add(
284-
'prpl-suggested-task-celebrated'
285-
);
286-
287-
setTimeout( () => {
288-
// Move task from published to trash.
382+
// Move task from trash to published.
289383
document
290-
.getElementById( 'todo-list-completed' )
384+
.getElementById( 'todo-list' )
291385
.insertAdjacentElement( 'beforeend', el );
292386

293-
// Remove the class to trigger the strike through animation.
294-
el.classList.remove(
295-
'prpl-suggested-task-celebrated'
296-
);
297-
298387
window.dispatchEvent(
299388
new CustomEvent( 'prpl/grid/resize' )
300389
);
@@ -303,59 +392,14 @@ prplSuggestedTask = {
303392
el.querySelector(
304393
'.prpl-suggested-task-checkbox'
305394
).removeAttribute( 'disabled' );
306-
}, 2000 );
307-
} else {
308-
/**
309-
* Strike completed tasks and remove them from the DOM.
310-
*/
311-
document.dispatchEvent(
312-
new CustomEvent( 'prpl/removeCelebratedTasks' )
313-
);
314-
315-
// Inject more tasks from the same category.
316-
prplSuggestedTask.injectItemsFromCategory( {
317-
category: taskCategorySlug,
318-
status: [ 'publish' ],
319-
} );
320-
}
321-
322-
// We trigger celebration only if the task has points.
323-
if ( 0 < eventPoints ) {
324-
prplUpdateRaviGauge( eventPoints );
325-
326-
// Trigger the celebration event (confetti).
327-
document.dispatchEvent(
328-
new CustomEvent( 'prpl/celebrateTasks', {
329-
detail: { element: el },
330-
} )
331-
);
332-
}
333-
} else if (
334-
'publish' === newStatus &&
335-
'user' === taskProviderId
336-
) {
337-
// This is only possible for user tasks.
338-
// Set the task action to publish.
339-
el.setAttribute( 'data-task-action', 'publish' );
340-
341-
// Update the Ravi gauge.
342-
prplUpdateRaviGauge( 0 - eventPoints );
343-
344-
// Move task from trash to published.
345-
document
346-
.getElementById( 'todo-list' )
347-
.insertAdjacentElement( 'beforeend', el );
348-
349-
window.dispatchEvent(
350-
new CustomEvent( 'prpl/grid/resize' )
351-
);
352395

353-
// Remove the disabled attribute for user tasks, so they can be clicked again.
354-
el.querySelector(
355-
'.prpl-suggested-task-checkbox'
356-
).removeAttribute( 'disabled' );
357-
}
358-
} );
396+
// Resolve immediately for publish actions
397+
resolve( { postId, newStatus, eventPoints } );
398+
}
399+
} )
400+
.catch( reject );
401+
} )
402+
.catch( reject );
359403
} );
360404
},
361405

assets/js/web-components/prpl-interactive-task.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,34 @@ class PrplInteractiveTask extends HTMLElement {
135135
const horizontalTargetCenter =
136136
horizontalRect.left + horizontalRect.width / 2;
137137

138+
// Ensure that the popover is not too far from the top of the screen on small screens.
139+
const MARGIN_TOP = 12; // minimum gap from top
140+
const MARGIN_BOTTOM = 12; // minimum gap from bottom
141+
const MOBILE_TOP_CAP = 100; // max starting offset on small screens
142+
const isSmallScreen = window.matchMedia( '(max-width: 768px)' ).matches;
143+
const MAX_TOP_CAP = isSmallScreen
144+
? MOBILE_TOP_CAP
145+
: Number.POSITIVE_INFINITY;
146+
147+
const desiredTop = Math.round( verticalRect.top );
148+
149+
const clampedTop = Math.max(
150+
MARGIN_TOP,
151+
Math.min( desiredTop, MAX_TOP_CAP )
152+
);
153+
138154
// Apply the position.
139155
popover.style.position = 'fixed';
140156
popover.style.left = `${ horizontalTargetCenter }px`;
141-
popover.style.top = `${ Math.round( Math.abs( verticalRect.top ) ) }px`;
157+
popover.style.top = `${ Math.round( clampedTop ) }px`;
142158
popover.style.transform = 'translateX(-50%)';
159+
160+
// Make sure popover content can scroll if needed
161+
popover.style.maxHeight = '80vh'; // adjustable
162+
popover.style.overflowY = 'auto';
163+
popover.style.maxHeight = `calc(100vh - ${
164+
clampedTop + MARGIN_BOTTOM
165+
}px)`;
143166
}
144167
}
145168

0 commit comments

Comments
 (0)