diff --git a/.eslintrc.js b/.eslintrc.js index 37a38ad..0c8fcba 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,5 +18,6 @@ module.exports = { "tenupIscAdminVars": "readonly", "localStorage": "readonly", "jQuery": "readonly", + "Node": "readonly", } }; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ed896bd..4781eb3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,5 @@ -# These owners will be the default owners for everything in the repo. Unless a later match takes precedence, @10up/open-source-practice, as primary maintainers will be requested for review when someone opens a Pull Request. -* @10up/open-source-practice +# These owners will be the default owners for everything in the repo. Unless a later match takes precedence, @jeffpaul and @dkotter, as primary maintainers will be requested for review when someone opens a Pull Request. +* @jeffpaul @dkotter # GitHub and WordPress.org specifics /.github/ @jeffpaul diff --git a/.github/workflows/push-asset-readme-update.yml b/.github/workflows/push-asset-readme-update.yml index 56e3659..652b2b0 100644 --- a/.github/workflows/push-asset-readme-update.yml +++ b/.github/workflows/push-asset-readme-update.yml @@ -1,16 +1,31 @@ name: Plugin asset/readme update + on: push: branches: - trunk + jobs: trunk: name: Push to trunk runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - - name: WordPress.org plugin asset/readme update - uses: 10up/action-wordpress-plugin-asset-update@stable - env: - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup node version + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: npm + + - name: Build + run: | + npm install + npm run build + + - name: WordPress.org plugin asset/readme update + uses: 10up/action-wordpress-plugin-asset-update@stable + env: + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} diff --git a/.wordpress-org/blueprints/blueprint.json b/.wordpress-org/blueprints/blueprint.json new file mode 100644 index 0000000..9516388 --- /dev/null +++ b/.wordpress-org/blueprints/blueprint.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://playground.wordpress.net/blueprint-schema.json", + "landingPage": "\/wp-admin\/post.php?post=1&action=edit", + "preferredVersions": { + "php": "7.4", + "wp": "latest" + }, + "phpExtensionBundles": ["kitchen-sink"], + "steps": [ + { + "step": "login", + "username": "admin", + "password": "password" + }, + { + "step": "installPlugin", + "pluginZipFile": { + "resource": "wordpress.org\/plugins", + "slug": "insert-special-characters" + }, + "options": { + "activate": true + } + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 659a3b6..cf33ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file, per [the Ke ## [Unreleased] - TBD +## [1.1.2] - 2024-01-08 +### Added +- Support for the WordPress.org plugin preview (props [@dkotter](https://github.com/dkotter), [@jeffpaul](https://github.com/jeffpaul) via [#232](https://github.com/10up/insert-special-characters/pull/232)). + +### Fixed +- Issue with blocks crashing due to faux caret (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter), [@ankitguptaindia](https://github.com/ankitguptaindia) via [#225](https://github.com/10up/insert-special-characters/pull/225)). +- Issue with characters added to the beginning trimming text from the end (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter), [@ankitguptaindia](https://github.com/ankitguptaindia) via [#225](https://github.com/10up/insert-special-characters/pull/225)). + +### Changed +- Bump WordPress "tested up to" version to 6.4 (props [@qasumitbagthariya](https://github.com/qasumitbagthariya), [@jeffpaul](https://github.com/jeffpaul), [@QAharshalkadu](https://github.com/QAharshalkadu), [@ankitguptaindia](https://github.com/ankitguptaindia), [@dhanendran](https://github.com/dhanendran), [@iamdharmesh](https://github.com/iamdharmesh) via [#228](https://github.com/10up/insert-special-characters/pull/228)). + ## [1.1.1] - 2023-10-17 ### Fixed - Address an issue where some blocks would crash due to a missing attribute (props [@dkotter](https://github.com/dkotter) via [#221](https://github.com/10up/insert-special-characters/pull/221)). @@ -175,6 +186,7 @@ All notable changes to this project will be documented in this file, per [the Ke - Plugin header and icon images (props [@McCallumDillon](https://github.com/McCallumDillon) via [#28](https://github.com/10up/insert-special-characters/pull/28)) [Unreleased]: https://github.com/10up/insert-special-characters/compare/trunk...develop +[1.1.2]: https://github.com/10up/insert-special-characters/compare/1.1.1...1.1.2 [1.1.1]: https://github.com/10up/insert-special-characters/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/10up/insert-special-characters/compare/1.0.7...1.1.0 [1.0.7]: https://github.com/10up/insert-special-characters/compare/1.0.6...1.0.7 diff --git a/CREDITS.md b/CREDITS.md index 92df137..2bde462 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -10,7 +10,7 @@ The following individuals are responsible for curating the list of issues, respo Thank you to all the people who have already contributed to this repository via bug reports, code, design, ideas, project management, translation, testing, etc. -[Adam Silverstein (@adamsilverstein)](https://github.com/adamsilverstein), [Helen Hou-Sandi (@helen)](https://github.com/helen), [Jeffrey Paul (@jeffpaul)](https://github.com/jeffpaul), [Mark Root-Wiley (@mrwweb)](https://github.com/mrwweb), [Dominik Schilling (@ocean90)](https://github.com/ocean90), [ (@josch87)](https://github.com/josch87), [David Chabbi (@davidchabbi)](https://profiles.wordpress.org/davidchabbi/), [Sami Keijonen (@samikeijonen)](https://github.com/samikeijonen), [John Watkins (@johnwatkins0)](https://github.com/johnwatkins0), [Tung Du (@dinhtungdu)](https://github.com/dinhtungdu), [Pablo Amato (@pabamato)](https://github.com/pabamato), [Ankit K Gupta (@ankitguptaindia)](https://github.com/ankitguptaindia), [Herb Miller (@bobbingwide)](https://github.com/bobbingwide), [Jeffrey Carandang (@phpbits)](https://github.com/phpbits), [Brandon Berg (@BBerg10up)](https://github.com/BBerg10up), [Siddharth Thevaril (@Sidsector9)](https://github.com/Sidsector9), [Pablo Amato (@pabamato)](https://github.com/pabamato), [Evgeny Vlasenko (@mahnunchik)](https://github.com/mahnunchik), [Ajay Maurya (@ajmaurya99)](https://github.com/ajmaurya99), [Dharmesh Patel (@iamdharmesh)](https://github.com/iamdharmesh), [Darin Kotter (@dkotter)](https://github.com/dkotter), [Max Lyuchin (@cadic)](https://github.com/cadic), [Vikram Moparthy (@vikrampm1)](https://github.com/vikrampm1), [Peter Wilson (@peterwilsoncc)](https://github.com/peterwilsoncc), [David Godleman (@cldhmmr)](https://github.com/cldhmmr), [Ulrich Pogson (@grappler)](https://github.com/grappler), [Mathew Payne (@GeekMasher)](https://github.com/GeekMasher), [Faisal Alvi (@faisal-alvi)](https://github.com/faisal-alvi), [Alex Lion (@alexclassroom)](https://github.com/alexclassroom), [GitHub Dependabot (@dependabot)](https://github.com/apps/dependabot), [Jayedul Kabir (@jayedul)](https://github.com/jayedul), [Jerome Duncan (@jrmd)](https://github.com/jrmd), [Garth Gutenberg (@ggutenberg)](https://github.com/ggutenberg), [Ben Marshall (@bmarshall511)](https://github.com/bmarshall511), [Ravinder Kumar (@ravinderk)](https://github.com/ravinderk), [Konstantinos Galanakis (@kmgalanakis)](https://github.com/kmgalanakis). +[Adam Silverstein (@adamsilverstein)](https://github.com/adamsilverstein), [Helen Hou-Sandi (@helen)](https://github.com/helen), [Jeffrey Paul (@jeffpaul)](https://github.com/jeffpaul), [Mark Root-Wiley (@mrwweb)](https://github.com/mrwweb), [Dominik Schilling (@ocean90)](https://github.com/ocean90), [ (@josch87)](https://github.com/josch87), [David Chabbi (@davidchabbi)](https://profiles.wordpress.org/davidchabbi/), [Sami Keijonen (@samikeijonen)](https://github.com/samikeijonen), [John Watkins (@johnwatkins0)](https://github.com/johnwatkins0), [Tung Du (@dinhtungdu)](https://github.com/dinhtungdu), [Pablo Amato (@pabamato)](https://github.com/pabamato), [Ankit K Gupta (@ankitguptaindia)](https://github.com/ankitguptaindia), [Herb Miller (@bobbingwide)](https://github.com/bobbingwide), [Jeffrey Carandang (@phpbits)](https://github.com/phpbits), [Brandon Berg (@BBerg10up)](https://github.com/BBerg10up), [Siddharth Thevaril (@Sidsector9)](https://github.com/Sidsector9), [Pablo Amato (@pabamato)](https://github.com/pabamato), [Evgeny Vlasenko (@mahnunchik)](https://github.com/mahnunchik), [Ajay Maurya (@ajmaurya99)](https://github.com/ajmaurya99), [Dharmesh Patel (@iamdharmesh)](https://github.com/iamdharmesh), [Darin Kotter (@dkotter)](https://github.com/dkotter), [Max Lyuchin (@cadic)](https://github.com/cadic), [Vikram Moparthy (@vikrampm1)](https://github.com/vikrampm1), [Peter Wilson (@peterwilsoncc)](https://github.com/peterwilsoncc), [David Godleman (@cldhmmr)](https://github.com/cldhmmr), [Ulrich Pogson (@grappler)](https://github.com/grappler), [Mathew Payne (@GeekMasher)](https://github.com/GeekMasher), [Faisal Alvi (@faisal-alvi)](https://github.com/faisal-alvi), [Alex Lion (@alexclassroom)](https://github.com/alexclassroom), [GitHub Dependabot (@dependabot)](https://github.com/apps/dependabot), [Jayedul Kabir (@jayedul)](https://github.com/jayedul), [Jerome Duncan (@jrmd)](https://github.com/jrmd), [Garth Gutenberg (@ggutenberg)](https://github.com/ggutenberg), [Ben Marshall (@bmarshall511)](https://github.com/bmarshall511), [Ravinder Kumar (@ravinderk)](https://github.com/ravinderk), [Konstantinos Galanakis (@kmgalanakis)](https://github.com/kmgalanakis), [Sumit Bagthariya (@qasumitbagthariya)](https://github.com/qasumitbagthariya), [Harshal Kadu (@QAharshalkadu)](https://github.com/QAharshalkadu), [Dhanendran Rajagopal (@dhanendran)](https://github.com/dhanendran). ## Libraries diff --git a/insert-special-characters.php b/insert-special-characters.php index c5982cc..98f287e 100644 --- a/insert-special-characters.php +++ b/insert-special-characters.php @@ -3,7 +3,7 @@ * Plugin Name: Insert Special Characters * Plugin URI: https://github.com/10up/insert-special-characters * Description: A Special Character inserter for the WordPress block editor (Gutenberg). - * Version: 1.1.1 + * Version: 1.1.2 * Requires at least: 6.1 * Requires PHP: 7.4 * Author: 10up diff --git a/package-lock.json b/package-lock.json index b87e707..a981ad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "insert-special-characters", - "version": "1.1.1", + "version": "1.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "insert-special-characters", - "version": "1.1.1", + "version": "1.1.2", "license": "GPL-2.0-only", "dependencies": { "@wordpress/components": "^22.1.0", @@ -19,7 +19,8 @@ "cypress": "^13.3.1", "cypress-mochawesome-reporter": "^3.4.0", "husky": "^8.0.1", - "lint-staged": "^10.0.7" + "lint-staged": "^10.0.7", + "mochawesome-json-to-md": "^0.7.2" } }, "node_modules/@10up/cypress-wp-utils": { @@ -13012,6 +13013,19 @@ "mocha": ">=7" } }, + "node_modules/mochawesome-json-to-md": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/mochawesome-json-to-md/-/mochawesome-json-to-md-0.7.2.tgz", + "integrity": "sha512-dxh+o73bhC6nEph6fNky9wy35R+2oK3ueXwAlJ/COAanlFgu8GuvGzQ00VNO4PPYhYGDsO4vbt4QTcMA3lv25g==", + "deprecated": "🙌 Thanks for using it. We recommend upgrading to the newer version, 1.x.x. Check out https://www.npmjs.com/package/mochawesome-json-to-md for details.", + "dev": true, + "dependencies": { + "yargs": "^17.0.1" + }, + "bin": { + "mochawesome-json-to-md": "index.js" + } + }, "node_modules/mochawesome-merge": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mochawesome-merge/-/mochawesome-merge-4.3.0.tgz", @@ -27429,6 +27443,15 @@ "uuid": "^8.3.2" } }, + "mochawesome-json-to-md": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/mochawesome-json-to-md/-/mochawesome-json-to-md-0.7.2.tgz", + "integrity": "sha512-dxh+o73bhC6nEph6fNky9wy35R+2oK3ueXwAlJ/COAanlFgu8GuvGzQ00VNO4PPYhYGDsO4vbt4QTcMA3lv25g==", + "dev": true, + "requires": { + "yargs": "^17.0.1" + } + }, "mochawesome-merge": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mochawesome-merge/-/mochawesome-merge-4.3.0.tgz", diff --git a/package.json b/package.json index 5843abb..5a4c6c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "insert-special-characters", - "version": "1.1.1", + "version": "1.1.2", "description": "A Special Character inserter for the WordPress block editor (Gutenberg).", "homepage": "https://github.com/10up/insert-special-characters#readme", "license": "GPL-2.0-only", @@ -30,7 +30,8 @@ "cypress": "^13.3.1", "cypress-mochawesome-reporter": "^3.4.0", "husky": "^8.0.1", - "lint-staged": "^10.0.7" + "lint-staged": "^10.0.7", + "mochawesome-json-to-md": "^0.7.2" }, "husky": { "hooks": { diff --git a/readme.txt b/readme.txt index ad7362e..e0c3c87 100644 --- a/readme.txt +++ b/readme.txt @@ -1,9 +1,9 @@ === Insert Special Characters === Contributors: 10up, adamsilverstein, johnwatkins0, jeffpaul Tags: Special Characters, Character Map, Omega, Gutenberg, Block, block editor -Stable tag: 1.1.1 +Stable tag: 1.1.2 Requires at least: 6.1 -Tested up to: 6.3 +Tested up to: 6.4 Requires PHP: 7.4 License: GPLv2 License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html @@ -75,6 +75,12 @@ One example of a font with support for wide range of glyphs is the [Noto](https: == Changelog == += 1.1.2 - 2024-01-08 = +* **Added:** Support for the WordPress.org plugin preview (props [@dkotter](https://github.com/dkotter), [@jeffpaul](https://github.com/jeffpaul) via [#232](https://github.com/10up/insert-special-characters/pull/232)). +* **Fixed:** Issue with blocks crashing due to faux caret (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter), [@ankitguptaindia](https://github.com/ankitguptaindia) via [#225](https://github.com/10up/insert-special-characters/pull/225)). +* **Fixed:** Issue with characters added to the beginning trimming text from the end (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter), [@ankitguptaindia](https://github.com/ankitguptaindia) via [#225](https://github.com/10up/insert-special-characters/pull/225)). +* **Changed:** Bump WordPress "tested up to" version to 6.4 (props [@qasumitbagthariya](https://github.com/qasumitbagthariya), [@jeffpaul](https://github.com/jeffpaul), [@QAharshalkadu](https://github.com/QAharshalkadu), [@ankitguptaindia](https://github.com/ankitguptaindia), [@dhanendran](https://github.com/dhanendran), [@iamdharmesh](https://github.com/iamdharmesh) via [#228](https://github.com/10up/insert-special-characters/pull/228)). + = 1.1.1 - 2023-10-17 = * **Fixed:** Address an issue where some blocks would crash due to a missing attribute (props [@dkotter](https://github.com/dkotter) via [#221](https://github.com/10up/insert-special-characters/pull/221)). * **Security:** Bump `@babel/traverse` from 7.20.5 to 7.23.2 (props [@dependabot](https://github.com/apps/dependabot), [@dkotter](https://github.com/dkotter) via [#219](https://github.com/10up/insert-special-characters/pull/219)). diff --git a/src/index.js b/src/index.js index 551ec8d..550f85f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,17 @@ -import { registerFormatType, toggleFormat, insert } from '@wordpress/rich-text'; -import { Fragment } from '@wordpress/element'; +import { + registerFormatType, + create, + insert, + applyFormat, + getActiveFormats, +} from '@wordpress/rich-text'; +import { + Fragment, + useState, + useRef, + useEffect, + useMemo, +} from '@wordpress/element'; import { BlockControls, RichTextShortcut } from '@wordpress/block-editor'; import { Popover, ToolbarButton, ToolbarGroup } from '@wordpress/components'; import { applyFilters } from '@wordpress/hooks'; @@ -21,8 +33,6 @@ const InsertSpecialCharactersOptions = { const { name, title, character } = InsertSpecialCharactersOptions; const type = `special-characters/${ name }`; -let anchorRange; -let anchorRect; /** * Register the "Format Type" to create the character inserter. @@ -37,67 +47,130 @@ registerFormatType( type, { * The `edit` function is called when the Character Map is selected. * * @param {Object} props Props object. - * @param {boolean} props.isActive State of popover. * @param {boolean} props.value State of popover. * @param {Function} props.onChange Event handler to detect range selection. * @param {HTMLElement} props.contentRef The editable element. */ - edit( { isActive, value, onChange, contentRef } ) { - const onToggle = () => { - const selection = contentRef.current.ownerDocument.getSelection(); + edit: function Edit( { value, onChange, contentRef } ) { + const [ isPopoverActive, setIsPopoverActive ] = useState( false ); + const popoverRef = useRef( null ); + const { start, end } = value; - anchorRange = - selection.rangeCount > 0 ? selection.getRangeAt( 0 ) : null; + function insertCharacter( char ) { + let richTextCharacter = create( { + text: char, + } ); - // Pin the Popover to the caret position. - const boundingClientRect = anchorRange - ? anchorRange.getBoundingClientRect() - : null; + for ( const format of getActiveFormats( value ) ) { + richTextCharacter = applyFormat( + richTextCharacter, + format, + 0, + 1 + ); + } + + const modified = insert( value, richTextCharacter, start, end ); + + onChange( modified ); + } + + /** + * Find the text node and its offset within the provided element based on an index. + * + * @param {Node} node The root node to search for the index. + * @param {number} index The index within the text content. + * @return {Array|null} An array containing the text node and its offset, or null if not found. + */ + function findTextNodeAtIndex( node, index ) { + let currentOffset = 0; + + /** + * Recursively traverse DOM to find the text node and offset. + * + * @param {Node} __node The current node. + * @return {Array|null} Array containing the text node and its offset, or null if not found. + */ + function traverseDOM( __node ) { + if ( __node.nodeType === Node.TEXT_NODE ) { + const textLength = __node.textContent.length; + + if ( currentOffset + textLength >= index ) { + return [ __node, index - currentOffset ]; + } + + currentOffset += textLength; + } else { + for ( const childNode of __node.childNodes ) { + const result = traverseDOM( childNode ); + + if ( result ) { + return result; + } + } + } + } + + return traverseDOM( node ); + } + + const memoizedPopoverRef = useMemo( () => popoverRef, [] ); + + useEffect( () => { + const fauxCursor = document.createElement( 'span' ); + + if ( + contentRef.current && + memoizedPopoverRef.current && + isPopoverActive + ) { + fauxCursor.className = 'insert-special-character__faux-caret'; + + const range = document.createRange(); + const [ textNode, offsetWithinText ] = findTextNodeAtIndex( + contentRef.current, + start + ); + + if ( textNode ) { + range.setStart( textNode, offsetWithinText ); + range.collapse( true ); + range.insertNode( fauxCursor ); + range.setStartAfter( fauxCursor ); + range.collapse( true ); + } + } + + return () => { + if ( fauxCursor ) { + fauxCursor.remove(); + } + }; + }, [ isPopoverActive, memoizedPopoverRef ] ); - anchorRect = anchorRange ? () => boundingClientRect : null; - onChange( toggleFormat( value, { type } ) ); - }; const characters = applyFilters( `${ name }-characters`, Chars ); // Display the character map when it is active. - const specialCharsPopover = isActive && ( + const specialCharsPopover = isPopoverActive && ( { - onChange( toggleFormat( value, { type } ) ); - } } + ref={ popoverRef } > { - const newValue = { - ...value, - // grab the format at the start position, - // if it is undefined then use an empty array. - formats: value.formats.at( value.start ) - ? [ value.formats.at( value.start ) ] - : [], - text: char.char, - }; - - onChange( - insert( - value, - newValue, - newValue.start, - newValue.end - ) - ); + ( obj ) => { + insertCharacter( obj.char ); + setIsPopoverActive( false ); } } categoryNames={ { @@ -142,9 +215,11 @@ registerFormatType( type, { + setIsPopoverActive( ! isPopoverActive ) + } shortcut={ displayShortcut.primary( character ) } /> @@ -153,7 +228,7 @@ registerFormatType( type, { setIsPopoverActive( ! isPopoverActive ) } /> { specialCharsPopover } diff --git a/src/insert-special-characters.scss b/src/insert-special-characters.scss index e28b820..d0ab0bc 100644 --- a/src/insert-special-characters.scss +++ b/src/insert-special-characters.scss @@ -1,5 +1,24 @@ $grid-border-color: #c8c8c8; +.insert-special-character__faux-caret { + border-left: 1px solid #000; + animation: 1s caret-blink step-end infinite; + margin-left: -1px; +} + +.insert-special-character__faux-selection { + background-color: rgba(0, 0, 0, 0.2); +} + +@keyframes caret-blink { + from, to { + border-color: black; + } + 50% { + border-color: transparent; + } +} + .character-map-popover { .components-popover__content { border: 1px solid #1e1e1e