Skip to content

Commit 87a0028

Browse files
authored
Merge pull request #91 from DLXPlugins/feature/mobile-selection-safari
Fix mobile rendering on Safari and Add WP Fonts to Block
2 parents ed53f69 + 3bc972a commit 87a0028

File tree

10 files changed

+178
-23
lines changed

10 files changed

+178
-23
lines changed

build/has-click-to-share.asset.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('react', 'wp-a11y', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '218cc8ffaf44f794c30a');
1+
<?php return array('dependencies' => array('react', 'wp-a11y', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '3e1eb88b9d5efb8f9137');

build/has-click-to-share.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/has-click-to-share.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/highlight-and-share.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

highlight-and-share.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Plugin URI: https://dlxplugins.com/plugins/highlight-and-share/
66
* Description: Select text, inline highlight, or use a Click to Share block and show social networks.
77
* Author: DLX Plugins
8-
* Version: 4.6.0
8+
* Version: 4.7.0
99
* Requires at least: 5.1
1010
* Requires PHP: 7.2
1111
* Author URI: https://dlxplugins.com/plugins/highlight-and-share/
@@ -17,7 +17,7 @@
1717

1818
namespace DLXPlugins\HAS;
1919

20-
define( 'HIGHLIGHT_AND_SHARE_VERSION', '4.6.0' );
20+
define( 'HIGHLIGHT_AND_SHARE_VERSION', '4.7.0' );
2121
define( 'HIGHLIGHT_AND_SHARE_FILE', __FILE__ );
2222

2323
// Support for site-level autoloading.

readme.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Contributors: ronalfy
33
Tags: highlight, social media, click share, select text, highlight text
44
Requires at least: 5.1
55
Tested up to: 6.4
6-
Stable tag: 4.6.0
6+
Stable tag: 4.7.0
77
License: GPLv2 or later
88
License URI: http://www.gnu.org/licenses/gpl-2.0.html
99
Donate link: https://github.com/sponsors/DLXPlugins
@@ -112,6 +112,11 @@ So far, the latest versions of Chrome, Firefox, Safari, Edge, and IE9+.
112112

113113
== Changelog ==
114114

115+
= 4.7.0 =
116+
* Released 2024-04-13
117+
* Huge bug fix: Highlight and Share now works great on mobile browsers including Safari.
118+
* Re-worked selection JS to integrate <a href="https://github.com/MaxArt2501/share-this">Share This</a> script.
119+
115120
= 4.6.0 =
116121
* Released 2023-12-10
117122
* Added Mastodon social network.
@@ -498,5 +503,5 @@ So far, the latest versions of Chrome, Firefox, Safari, Edge, and IE9+.
498503

499504
== Upgrade Notice ==
500505

501-
= 4.6.0 =
502-
Added Mastodon social network. Fixed popup in the Support tab for demo video. Fixed deprecation notices.
506+
= 4.7.0 =
507+
Text selection works great on mobile browsers now.

src/frontendjs/dom.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
export function getOffsetScroll(_window) {
2+
const body = _window.document.body;
3+
const scrollReference = _window.getComputedStyle(body).position === "static" ? body.parentNode : body;
4+
return scrollReference.getBoundingClientRect();
5+
}
6+
7+
let matchFunc;
8+
export function matches(element, selector) {
9+
if (!matchFunc) matchFunc = getMatchFunctionName(element);
10+
return element[matchFunc](selector);
11+
}
12+
13+
export function closest(element, selector) {
14+
let target = element;
15+
while (target && (target.nodeType !== 1 /* === Node.ELEMENT_NODE */ || !matches(target, selector))) {
16+
target = target.parentNode;
17+
}
18+
19+
return target;
20+
}
21+
22+
// `contains` in IE doesn't work with text nodes
23+
export function contains(ancestor, target) {
24+
const comparedPositions = ancestor.compareDocumentPosition(target);
25+
// eslint-disable-next-line no-bitwise
26+
return !comparedPositions || (comparedPositions & 16 /* === Node.DOCUMENT_POSITION_CONTAINED_BY */) > 0;
27+
}
28+
29+
// eslint-disable-next-line consistent-return
30+
function getMatchFunctionName(element) {
31+
const suffix = "atchesSelector";
32+
for (const name of [ "matches", `m${suffix}`, `webkitM${suffix}`, `mozM${suffix}`, `msM${suffix}`, `oM${suffix}` ]) {
33+
if (element[name]) return name;
34+
}
35+
}

src/frontendjs/highlight-and-share.js

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { constrainRange } from './selection';
12
( function() {
23
'use strict';
34

@@ -200,7 +201,7 @@
200201
switch ( type ) {
201202
case 'selection':
202203
// Position the interface.
203-
setHasContainerPositionSelection( hasClone );
204+
setHasContainerPositionSelection( hasClone, triggerElement );
204205
break;
205206
case 'inline':
206207
// Position the interface.
@@ -336,8 +337,8 @@
336337
el.addEventListener( 'click', ( event ) => {
337338
event.preventDefault();
338339
const url = event.target.closest( 'a' ).getAttribute( 'href' );
339-
340-
//
340+
341+
//
341342
if ( 'undefined' !== typeof Fancybox ) {
342343
// eslint-disable-next-line no-undef
343344
hasRemoveVisibleElements();
@@ -428,18 +429,16 @@
428429
/**
429430
* Set the Social Sharer container position for the current selection. This needs to run after cloned element has been appended to the dom.
430431
*
431-
* @param {element} element The cloned social sharer element.
432+
* @param {element} element The cloned social sharer element.
433+
* @param {element} triggerElement The event initiator (null if no trigger element).
432434
*/
433-
const setHasContainerPositionSelection = ( element ) => {
435+
const setHasContainerPositionSelection = ( element, triggerElement ) => {
434436
// Get the dimensions of the window.
435437
const windowWidth = window.innerWidth;
436438
const windowHeight = window.innerHeight;
437439

438440
// Get the dimensions and location of the selection.
439-
const selectionRect = window
440-
.getSelection()
441-
.getRangeAt( 0 )
442-
.getBoundingClientRect();
441+
const selectionRect = getConstrainedRange( triggerElement ).getBoundingClientRect();
443442
const selectionTop = selectionRect.top; // top position relative to view port.
444443
const selectionLeft = selectionRect.left; // left position relative to view port.
445444
const selectionWidth = selectionRect.width;
@@ -650,6 +649,30 @@
650649
}
651650
};
652651

652+
/**
653+
* Get the constrained range.
654+
*
655+
* @param {Element} element The element to constrain the range to.
656+
* @return {Range} The constrained range.
657+
* @see https://github.com/MaxArt2501/share-this/tree/master
658+
*/
659+
const getConstrainedRange = ( element ) => {
660+
const _window = document.defaultView;
661+
const selection = _window.getSelection();
662+
const range = selection.rangeCount && selection.getRangeAt( 0 );
663+
if ( ! range ) {
664+
return;
665+
}
666+
667+
const constrainedRange = constrainRange( range, element );
668+
if ( constrainedRange.collapsed || ! constrainedRange.getClientRects().length ) {
669+
return;
670+
}
671+
672+
// eslint-disable-next-line consistent-return
673+
return constrainedRange;
674+
};
675+
653676
/**
654677
* Set the Social Sharer container position for the inline highlighter. This needs to run after cloned element has been appended to the dom.
655678
*
@@ -824,7 +847,7 @@
824847

825848
const element = parentElement.querySelector( '.has-social-placeholder' );
826849

827-
// Get the highlight and share params.
850+
// Get the highlight and share params.
828851
const { href, title, hashtags } = getPageParams( element );
829852

830853
// Display Highlight and Share.
@@ -838,8 +861,11 @@
838861

839862
// Check if element has class `has-content-area` and if so, it's flush with the content. Select its parent, and add the event to that.
840863
if ( element.classList.contains( 'has-content-area' ) && ! isLegacyContentMode ) {
841-
element.parentElement.addEventListener( 'mouseup', ( event ) => {
842-
hasHandleSelectEvents( event, element.parentElement );
864+
const eventTypes = [ 'selectionchange', 'mouseup', 'touchend', 'touchcancel' ];
865+
eventTypes.forEach( ( eventType ) => {
866+
element.parentElement.addEventListener( eventType, ( event ) => {
867+
hasHandleSelectEvents( event, element.parentElement );
868+
} );
843869
} );
844870
return;
845871
}

src/frontendjs/selection.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { closest, contains } from './dom.js';
2+
3+
export function isSelectionForward( selection ) {
4+
if ( selection.isCollapsed ) {
5+
return true;
6+
}
7+
8+
const comparedPositions = selection.anchorNode.compareDocumentPosition( selection.focusNode );
9+
if ( ! comparedPositions ) {
10+
// It's the same node
11+
return selection.anchorOffset < selection.focusOffset;
12+
}
13+
14+
// eslint-disable-next-line no-bitwise
15+
return ( comparedPositions & 4 /* === Node.DOCUMENT_POSITION_FOLLOWING */ ) > 0;
16+
}
17+
18+
export function getEndLineRect( range, isForward ) {
19+
let endLineRects;
20+
const rangeRects = range.getClientRects();
21+
const sliceRects = [].slice.bind( rangeRects );
22+
23+
if ( isForward ) {
24+
let lastLeft = Infinity;
25+
let i = rangeRects.length;
26+
while ( i-- ) {
27+
const rect = rangeRects[ i ];
28+
if ( rect.left > lastLeft ) {
29+
break;
30+
}
31+
lastLeft = rect.left;
32+
}
33+
endLineRects = sliceRects( i + 1 );
34+
} else {
35+
let lastRight = -Infinity;
36+
let i = 0;
37+
for ( ; i < rangeRects.length; i++ ) {
38+
const rect = rangeRects[ i ];
39+
if ( rect.right < lastRight ) {
40+
break;
41+
}
42+
lastRight = rect.right;
43+
}
44+
endLineRects = sliceRects( 0, i );
45+
}
46+
47+
return {
48+
top: Math.min( ...endLineRects.map( ( rect ) => rect.top ) ),
49+
bottom: Math.max( ...endLineRects.map( ( rect ) => rect.bottom ) ),
50+
left: endLineRects[ 0 ].left,
51+
right: endLineRects[ endLineRects.length - 1 ].right,
52+
};
53+
}
54+
55+
export function constrainRange( range, selector ) {
56+
const constrainedRange = range.cloneRange();
57+
if ( range.collapsed || ! selector ) {
58+
return constrainedRange;
59+
}
60+
61+
let ancestor = closest( range.startContainer, selector );
62+
if ( ancestor ) {
63+
if ( ! contains( ancestor, range.endContainer ) ) {
64+
constrainedRange.setEnd( ancestor, ancestor.childNodes.length );
65+
}
66+
} else {
67+
ancestor = closest( range.endContainer, selector );
68+
if ( ancestor ) {
69+
constrainedRange.setStart( ancestor, 0 );
70+
} else {
71+
constrainedRange.collapse();
72+
}
73+
}
74+
75+
return constrainedRange;
76+
}

src/react/Components/Typography/index.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useState, useEffect } from 'react';
22
import fontFamilies from '../../../fonts/fonts';
33
import { __ } from '@wordpress/i18n';
4+
import { useSettings } from '@wordpress/block-editor';
45
import { ButtonGroup, Button, Tooltip, SelectControl, BaseControl, TextControl, Popover } from '@wordpress/components';
56
import { useForm, Controller, useWatch } from 'react-hook-form';
67
import { geHierarchicalPlaceholderValue } from '../../Utils/TypographyHelper';
@@ -73,6 +74,8 @@ const Typography = ( props ) => {
7374
defaultValues: getDefaultValues(),
7475
} );
7576

77+
const [ blockLevelFontFamilies ] = useSettings( 'typography.fontFamilies' );
78+
7679
const formValues = useWatch( { control } );
7780

7881
const { label } = props;
@@ -105,8 +108,18 @@ const Typography = ( props ) => {
105108
const mergedFamilies = [];
106109
families.forEach( ( fontFamily ) => {
107110
fonts.push( { label: fontFamily.name, value: fontFamily.slug } );
108-
mergedFamilies.push( { family: fontFamily.family, slug: fontFamily.slug, fallback: fontFamily.fallback, type: fontFamily.type } );
111+
mergedFamilies.push( { family: fontFamily.family, slug: fontFamily.slug, fallback: fontFamily.fallback, type: fontFamily.type } );
109112
} );
113+
if ( blockLevelFontFamilies ) {
114+
const { theme } = blockLevelFontFamilies;
115+
116+
if ( theme ) {
117+
theme.forEach( ( fontFamily ) => {
118+
fonts.push( { label: fontFamily.name, value: fontFamily.slug } );
119+
mergedFamilies.push( { family: fontFamily.name, slug: fontFamily.slug, fallback: fontFamily.fallback, type: 'web' } );
120+
} );
121+
}
122+
}
110123
// Push adobe fonts to the front.
111124
adobeFonts.forEach( ( font ) => {
112125
fonts.unshift( { label: font.name, value: font.slug } );

0 commit comments

Comments
 (0)