From 20f4119f26c8af78b75b48fbcb8294279caa5c28 Mon Sep 17 00:00:00 2001 From: Sbisson Date: Wed, 5 Jun 2024 15:49:14 -0400 Subject: [PATCH 01/15] Popup position based on width --- src/index.js | 8 ++------ src/utils.js | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index c0745494..6dd4df5c 100644 --- a/src/index.js +++ b/src/index.js @@ -194,12 +194,8 @@ function init( { Array.prototype.forEach.call( localRoot.querySelectorAll( selector ), ( node ) => { - if ( isTouch ) { - node.addEventListener( 'click', showPopup ) - } else { - node.addEventListener( 'mouseenter', showPopup ) - } - + node.addEventListener( 'touch', showPopup ) + node.addEventListener( 'mouseenter', showPopup ) foundSelectorLinks.push( { text: node.textContent, title: node.getAttribute( 'data-wp-title' ) || node.textContent, diff --git a/src/utils.js b/src/utils.js index 5c950906..de0bdd1c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -41,8 +41,7 @@ const getWikipediaAttrFromUrl = ( url ) => { return null } -const isTouch = 'ontouchstart' in window || ( navigator.maxTouchPoints > 0 ) || - ( navigator.msMaxTouchPoints > 0 ) +const isTouch = !!window.matchMedia( '( max-width: 768px )' ).matches const isOnline = () => window.navigator.onLine From ad2867ca956e22eaddedf9059d6f146e56798080 Mon Sep 17 00:00:00 2001 From: Sbisson Date: Wed, 5 Jun 2024 16:05:46 -0400 Subject: [PATCH 02/15] Fix tests --- test/setup.js | 8 ++++++++ vite.config.js | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 test/setup.js diff --git a/test/setup.js b/test/setup.js new file mode 100644 index 00000000..4f7d79af --- /dev/null +++ b/test/setup.js @@ -0,0 +1,8 @@ +import { vi } from 'vitest' +/* global window */ +Object.defineProperty( window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation( () => ( { + matches: true + } ) ) +} ) diff --git a/vite.config.js b/vite.config.js index fe471de2..529ae5af 100644 --- a/vite.config.js +++ b/vite.config.js @@ -41,6 +41,7 @@ export default defineConfig({ }, test: { globals: true, - environment: 'jsdom' + environment: 'jsdom', + setupFiles: [ './test/setup.js' ], } }) From f4e1208f0029bf2fcf93f08e9812d92f14fcf811 Mon Sep 17 00:00:00 2001 From: Sbisson Date: Tue, 11 Jun 2024 11:25:24 -0400 Subject: [PATCH 03/15] Split isTouch and isMobile --- .gitignore | 1 + src/event.js | 2 +- src/index.js | 12 +++++------- src/preview.js | 14 +++++++------- src/utils.js | 12 ++++++++++-- style/preview.less | 5 +++++ 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 105b065a..d1f115e4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules/ .DS_Store storybook-static coverage/ +cypress/screenshots diff --git a/src/event.js b/src/event.js index 98aeb9b3..d4757c10 100644 --- a/src/event.js +++ b/src/event.js @@ -203,7 +203,7 @@ export const customEvents = ( popup ) => { if ( isTouch ) { const darkScreen = document.querySelector( '.wp-dark-screen' ) - addEventListener( darkScreen, 'click', popup.hide, true ) + addEventListener( darkScreen, 'touch', popup.hide, true ) applyDragEvent( element ) } else { addEventListener( element, 'mouseleave', onMouseLeave ) diff --git a/src/index.js b/src/index.js index 6dd4df5c..a52140f5 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,7 @@ import { createTouchPopup } from './touchPopup' import { renderPreview, renderLoading, renderError, renderDisambiguation, renderOffline } from './preview' import { getWikipediaAttrFromUrl, buildWikipediaUrl, isTouch, getDir, isOnline, - version, getAnalyticsQueryParam, getElement + version, getAnalyticsQueryParam, getElement, isMobile } from './utils' const invokeCallback = ( events, name, params ) => { @@ -74,7 +74,7 @@ function init( { } ) { popupContainer = getElement( popupContainer ) || document.body const globalLang = lang - const popup = isTouch ? + const popup = isMobile ? createTouchPopup( popupContainer ) : createPopup( popupContainer ) const popupEvents = customEvents( popup ) @@ -85,6 +85,7 @@ function init( { const showPopup = ( e, refresh = false ) => { e.preventDefault() + e.stopPropagation() const popupId = Date.now() const { currentTarget } = refresh ? last : e @@ -214,11 +215,8 @@ function init( { if ( matches ) { node.setAttribute( 'data-wp-title', matches.title ) node.setAttribute( 'data-wp-lang', matches.lang ) - if ( isTouch ) { - node.addEventListener( 'click', showPopup ) - } else { - node.addEventListener( 'mouseenter', showPopup ) - } + node.addEventListener( 'touch', showPopup ) + node.addEventListener( 'mouseenter', showPopup ) foundDetectLinks.push( { text: node.textContent, diff --git a/src/preview.js b/src/preview.js index a1b25cd9..0473e158 100644 --- a/src/preview.js +++ b/src/preview.js @@ -2,12 +2,12 @@ import { msg } from './i18n' import { buildWikipediaUrl } from './utils' import '../style/preview.less' -const getPreviewHeader = ( lang, isTouch, imageUrl = '' ) => { +const getPreviewHeader = ( lang, imageUrl = '' ) => { return `
${ imageUrl ? `
` : '' }
- ${ isTouch ? '
' : '' } +
`.trim() } @@ -60,7 +60,7 @@ const renderPreview = ( lang, data, isTouch, prefersColorScheme ) => { lang, isTouch, data.dir, - getPreviewHeader( lang, isTouch, imageUrl ), + getPreviewHeader( lang, imageUrl ), bodyContent, prefersColorScheme ) @@ -83,28 +83,28 @@ const renderLoading = ( isTouch, lang, dir, prefersColorScheme ) => { `.trim() - return render( lang, isTouch, dir, getPreviewHeader( lang, isTouch ), bodyContent, prefersColorScheme ) + return render( lang, isTouch, dir, getPreviewHeader( lang ), bodyContent, prefersColorScheme ) } const renderError = ( isTouch, lang, title, dir, prefersColorScheme ) => { const message = `${ msg( lang, 'preview-error-message' ) }` const cta = getReadOnWikiCta( lang, title, isTouch ) - return render( lang, isTouch, dir, getPreviewHeader( lang, isTouch ), getPreviewBody( 'error', message, cta ), prefersColorScheme ) + return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'error', message, cta ), prefersColorScheme ) } const renderDisambiguation = ( isTouch, lang, title, dir, prefersColorScheme ) => { const message = `${ msg( lang, 'preview-disambiguation-message', title ) }` const cta = getReadOnWikiCta( lang, title, isTouch ) - return render( lang, isTouch, dir, getPreviewHeader( lang, isTouch ), getPreviewBody( 'disambiguation', message, cta ), prefersColorScheme ) + return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'disambiguation', message, cta ), prefersColorScheme ) } const renderOffline = ( isTouch, lang, dir, prefersColorScheme ) => { const message = `${ msg( lang, 'preview-offline-message' ) }` const cta = `${ msg( lang, 'preview-offline-cta' ) }` - return render( lang, isTouch, dir, getPreviewHeader( lang, isTouch ), getPreviewBody( 'offline', message, cta ), prefersColorScheme ) + return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'offline', message, cta ), prefersColorScheme ) } export { renderPreview, renderLoading, renderError, renderDisambiguation, renderOffline } diff --git a/src/utils.js b/src/utils.js index de0bdd1c..ca6c8f6f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -41,7 +41,15 @@ const getWikipediaAttrFromUrl = ( url ) => { return null } -const isTouch = !!window.matchMedia( '( max-width: 768px )' ).matches +/** + * Check if the device is a mobile device + */ +const isMobile = !!window.matchMedia( '( max-width: 768px )' ).matches + +/** + * Check if the device is a touch device + */ +const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 const isOnline = () => window.navigator.onLine @@ -111,5 +119,5 @@ const getElement = ( nodeOrSelector ) => { export { getWikipediaAttrFromUrl, isTouch, isOnline, getDir, buildMwApiUrl, convertUrlToMobile, strip, sanitizeHTML, getDeviceSize, getAnalyticsQueryParam, - buildWikipediaUrl, version, logError, getElement + buildWikipediaUrl, version, logError, getElement, isMobile } diff --git a/style/preview.less b/style/preview.less index fd3bc270..1e4d99f4 100644 --- a/style/preview.less +++ b/style/preview.less @@ -70,6 +70,7 @@ } &-closebtn { + display: none; background-image: url( '../images/close.svg' ); background-repeat: no-repeat; background-position: center; @@ -289,6 +290,10 @@ &.mobile { width: 100%; + + .wikipediapreview-header-closebtn { + display: block; + } } &.mobile.expanded { From 4ed6bc003b2b577ef614ca5b278006881a5c17fd Mon Sep 17 00:00:00 2001 From: Sbisson Date: Wed, 12 Jun 2024 15:57:57 -0400 Subject: [PATCH 04/15] Use isMobile for layout purposes --- src/event.js | 10 +++++----- src/index.js | 20 ++++++++++---------- src/preview.js | 34 +++++++++++++++++----------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/event.js b/src/event.js index d4757c10..e31d797a 100644 --- a/src/event.js +++ b/src/event.js @@ -1,4 +1,4 @@ -import { isTouch } from './utils' +import { isMobile } from './utils' import { getGalleryRow } from './gallery' import { requestPageMedia } from './api' @@ -82,7 +82,7 @@ export const customEvents = ( popup ) => { popup.element.component.wikipediapreview.classList.add( 'expanded' ) - if ( !isTouch ) { + if ( !isMobile ) { setPreviewMaxHeight( maxHeight ) } @@ -188,12 +188,12 @@ export const customEvents = ( popup ) => { element.component.content.getBoundingClientRect().height < 248 ) { onExpand( element ) } else { - if ( !isTouch ) { + if ( !isMobile ) { setPreviewMaxHeight( 248 ) } } - if ( isTouch ) { + if ( isMobile ) { addEventListener( element.component.closeBtn, 'click', popup.hide ) } @@ -201,7 +201,7 @@ export const customEvents = ( popup ) => { addEventListener( element.component.readMore, 'click', onExpand ) } - if ( isTouch ) { + if ( isMobile ) { const darkScreen = document.querySelector( '.wp-dark-screen' ) addEventListener( darkScreen, 'touch', popup.hide, true ) applyDragEvent( element ) diff --git a/src/index.js b/src/index.js index a52140f5..76ee2917 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ import { createPopup } from './popup' import { createTouchPopup } from './touchPopup' import { renderPreview, renderLoading, renderError, renderDisambiguation, renderOffline } from './preview' import { - getWikipediaAttrFromUrl, buildWikipediaUrl, isTouch, getDir, isOnline, + getWikipediaAttrFromUrl, buildWikipediaUrl, getDir, isOnline, version, getAnalyticsQueryParam, getElement, isMobile } from './utils' @@ -23,7 +23,7 @@ const invokeCallback = ( events, name, params ) => { // getPreviewHtml is meant to be used by the Wordpress plugin only const getPreviewHtml = ( title, lang, callback ) => { requestPagePreview( lang, title, ( data ) => { - callback( renderPreview( lang, data, isTouch ) ) + callback( renderPreview( lang, data, isMobile ) ) } ) } @@ -108,7 +108,7 @@ function init( { popup.loading = true popup.dir = dir popup.show( - renderLoading( isTouch, localLang, dir, currentColorScheme ), + renderLoading( isMobile, localLang, dir, currentColorScheme ), currentTarget, pointerPosition ) @@ -124,17 +124,17 @@ function init( { popup.title = title if ( data.type === 'standard' ) { popup.show( - renderPreview( localLang, data, isTouch, currentColorScheme ), + renderPreview( localLang, data, isMobile, currentColorScheme ), currentTarget, pointerPosition ) invokeCallback( events, 'onShow', [ title, localLang, 'standard' ] ) } else if ( data.type === 'disambiguation' ) { const content = data.extractHtml ? - renderPreview( localLang, data, isTouch, currentColorScheme ) : + renderPreview( localLang, data, isMobile, currentColorScheme ) : // fallback message when no extract is found on disambiguation page renderDisambiguation( - isTouch, + isMobile, localLang, data.title, data.dir, @@ -150,14 +150,14 @@ function init( { } else { if ( isOnline() ) { popup.show( - renderError( isTouch, localLang, title, dir, currentColorScheme ), + renderError( isMobile, localLang, title, dir, currentColorScheme ), currentTarget, pointerPosition ) invokeCallback( events, 'onShow', [ title, localLang, 'error' ] ) } else { popup.show( - renderOffline( isTouch, localLang, dir, currentColorScheme ), + renderOffline( isMobile, localLang, dir, currentColorScheme ), currentTarget, pointerPosition ) @@ -234,13 +234,13 @@ function init( { console.group( 'Wikipedia Preview [debug mode]' ) console.group( `Searching for "${ selector }" inside ${ root }, Total links found: ${ foundSelectorLinks.length }` ) foundSelectorLinks.forEach( ( link, index ) => { - console.log( index + 1, `${ link.text } -> ${ decodeURI( buildWikipediaUrl( link.lang, link.title, isTouch, false ) ) }` ) + console.log( index + 1, `${ link.text } -> ${ decodeURI( buildWikipediaUrl( link.lang, link.title, isMobile, false ) ) }` ) } ) console.groupEnd() if ( detectLinks ) { console.group( `Searching for links to Wikipedia, Total links found: ${ foundDetectLinks.length }` ) foundDetectLinks.forEach( ( link, index ) => { - console.log( index + 1, `${ link.text } -> ${ decodeURI( buildWikipediaUrl( link.lang, link.title, isTouch, false ) ) }` ) + console.log( index + 1, `${ link.text } -> ${ decodeURI( buildWikipediaUrl( link.lang, link.title, isMobile, false ) ) }` ) } ) console.groupEnd() } diff --git a/src/preview.js b/src/preview.js index 0473e158..caaf96e4 100644 --- a/src/preview.js +++ b/src/preview.js @@ -26,23 +26,23 @@ const getPreviewBody = ( type, message, cta ) => { `.trim() } -const getReadOnWikiCta = ( lang, title, isTouch ) => { - return `${ msg( lang, 'read-on-wiki' ) }` +const getReadOnWikiCta = ( lang, title, isMobile ) => { + return `${ msg( lang, 'read-on-wiki' ) }` } const render = ( - lang, isTouch, dir, headerContent, bodyContent, prefersColorScheme + lang, isMobile, dir, headerContent, bodyContent, prefersColorScheme ) => { const colorScheme = prefersColorScheme === 'detect' ? '' : `wikipediapreview-${ prefersColorScheme }-theme` return ` -
+
${ headerContent } ${ bodyContent }
`.trim() } -const renderPreview = ( lang, data, isTouch, prefersColorScheme ) => { +const renderPreview = ( lang, data, isMobile, prefersColorScheme ) => { const imageUrl = data.imgUrl, bodyContent = `
@@ -52,13 +52,13 @@ const renderPreview = ( lang, data, isTouch, prefersColorScheme ) => {
`.trim() return render( lang, - isTouch, + isMobile, data.dir, getPreviewHeader( lang, imageUrl ), bodyContent, @@ -66,7 +66,7 @@ const renderPreview = ( lang, data, isTouch, prefersColorScheme ) => { ) } -const renderLoading = ( isTouch, lang, dir, prefersColorScheme ) => { +const renderLoading = ( isMobile, lang, dir, prefersColorScheme ) => { const bodyContent = `
@@ -83,28 +83,28 @@ const renderLoading = ( isTouch, lang, dir, prefersColorScheme ) => { `.trim() - return render( lang, isTouch, dir, getPreviewHeader( lang ), bodyContent, prefersColorScheme ) + return render( lang, isMobile, dir, getPreviewHeader( lang ), bodyContent, prefersColorScheme ) } -const renderError = ( isTouch, lang, title, dir, prefersColorScheme ) => { +const renderError = ( isMobile, lang, title, dir, prefersColorScheme ) => { const message = `${ msg( lang, 'preview-error-message' ) }` - const cta = getReadOnWikiCta( lang, title, isTouch ) + const cta = getReadOnWikiCta( lang, title, isMobile ) - return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'error', message, cta ), prefersColorScheme ) + return render( lang, isMobile, dir, getPreviewHeader( lang ), getPreviewBody( 'error', message, cta ), prefersColorScheme ) } -const renderDisambiguation = ( isTouch, lang, title, dir, prefersColorScheme ) => { +const renderDisambiguation = ( isMobile, lang, title, dir, prefersColorScheme ) => { const message = `${ msg( lang, 'preview-disambiguation-message', title ) }` - const cta = getReadOnWikiCta( lang, title, isTouch ) + const cta = getReadOnWikiCta( lang, title, isMobile ) - return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'disambiguation', message, cta ), prefersColorScheme ) + return render( lang, isMobile, dir, getPreviewHeader( lang ), getPreviewBody( 'disambiguation', message, cta ), prefersColorScheme ) } -const renderOffline = ( isTouch, lang, dir, prefersColorScheme ) => { +const renderOffline = ( isMobile, lang, dir, prefersColorScheme ) => { const message = `${ msg( lang, 'preview-offline-message' ) }` const cta = `${ msg( lang, 'preview-offline-cta' ) }` - return render( lang, isTouch, dir, getPreviewHeader( lang ), getPreviewBody( 'offline', message, cta ), prefersColorScheme ) + return render( lang, isMobile, dir, getPreviewHeader( lang ), getPreviewBody( 'offline', message, cta ), prefersColorScheme ) } export { renderPreview, renderLoading, renderError, renderDisambiguation, renderOffline } From c0c7485bb883c319c4fd7276a37d25f01f7f43ce Mon Sep 17 00:00:00 2001 From: Sbisson Date: Wed, 12 Jun 2024 16:15:42 -0400 Subject: [PATCH 05/15] fix merge --- src/preview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preview.js b/src/preview.js index c8581a93..5e3fe616 100644 --- a/src/preview.js +++ b/src/preview.js @@ -49,7 +49,7 @@ const renderPreview = ( lang, data, isMobile, prefersColorScheme ) => { ${ data.extractHtml }