Plugin Directory

Changeset 3481613


Ignore:
Timestamp:
03/13/2026 01:44:59 AM (3 weeks ago)
Author:
kasuga16
Message:

Update 1.5.0 -> 1.5.5

Location:
livedraft-search-replace
Files:
10 added
3 edited

Legend:

Unmodified
Added
Removed
  • livedraft-search-replace/trunk/livedraft-search-replace.js

    r3480776 r3481613  
    99 * @copyright         2026 Kasuga
    1010 * @license           GPL-2.0-or-later
    11  * @version           1.8.0
     11 * @version           1.8.8
    1212 */
    1313
     
    8282            if (!autoPopulate) return;
    8383            const handleSelectionChange = () => {
     84                if (isInternalUpdating.current) return;
    8485                if (document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA')) return;
    8586                const selection = window.getSelection();
    8687                if (selection && selection.rangeCount > 0) {
    8788                    const text = selection.toString();
    88                     if (text && text.trim().length > 0) setSearch(text);
     89                    if (text && text.trim().length > 0) {
     90                        setSearch(text);
     91                        lastSearchedRef.current = text;
     92                    }
    8993                }
    9094            };
     
    124128                        matchesRef.current = [];
    125129                        setTotalCount(0);
     130                        setCurrent(0);
    126131                        ticking.current = false;
    127132                        return;
     
    215220
    216221                } else {
    217                     setCurrent(0); currentIndexRef.current = 0;
     222                    setCurrent(0);
     223                    currentIndexRef.current = 0;
    218224                }
    219225                ticking.current = false;
     
    225231
    226232            const currentIdx = currentIndexRef.current;
     233            const prevTotal = matchesRef.current.length;
    227234            const targetMatch = specificMatch || (all ? null : matchesRef.current[currentIdx - 1]);
    228235            if (!all && !targetMatch) return;
     
    324331                const clientIds = [...new Set(matchesRef.current.map(m => m.clientId))];
    325332                clientIds.forEach(cid => performUpdate(cid));
     333                // Clear matches immediately on replace all
     334                matchesRef.current = [];
    326335
    327336            } else {
     
    330339            }
    331340
     341            // After replacement, finalize state if 'all' is true, or force a rescan to sync highlights for individual replacement.
    332342            setTimeout(() => {
    333                 isInternalUpdating.current = false;
    334                 let nextTargetIdx = all ? 1 : (currentIdx > (matchesRef.current.length - 1) ? 1 : currentIdx);
    335                 performScan(nextTargetIdx, !specificMatch);
    336             }, 150);
    337         }, [blocks, search, replace, useRegex, caseSensitive, editorMode, performScan, updateBlockAttributes]);
     343                if (window.getSelection) window.getSelection().removeAllRanges();
     344                if (all) {
     345                    setCurrent(0);
     346                    setTotalCount(0);
     347                    currentIndexRef.current = 0;
     348                    if (window.CSS && CSS.highlights) {
     349                        CSS.highlights.delete('esr-match');
     350                        CSS.highlights.delete('esr-current');
     351                    }
     352                    isInternalUpdating.current = false;
     353                } else {
     354                    // Force a re-scan to restore highlights for remaining matches.
     355                    isInternalUpdating.current = false;
     356                    // Loop back to start if the last match was replaced.
     357                    const nextIdx = currentIdx > prevTotal - 1 ? 1 : currentIdx;
     358                    performScan(nextIdx, true);
     359                }
     360            }, 50);
     361        }, [blocks, search, replace, useRegex, caseSensitive, editorMode, updateBlockAttributes, performScan]);
    338362
    339363        useEffect(() => {
     
    385409
    386410        useEffect(() => {
     411            // Triggered on every block change (including Undo/Redo and after Replace).
    387412            if (isInternalUpdating.current) return;
     413
     414            // When Undo happens, the DOM nodes are replaced.
     415            if (matchesRef.current.length > 0) {
     416                const isAnyNodeDetached = matchesRef.current.some(m => !m.node || !m.node.isConnected);
     417                if (isAnyNodeDetached) {
     418                    matchesRef.current = [];
     419                    if (window.CSS && CSS.highlights) CSS.highlights.clear();
     420                }
     421            }
     422
     423            // This acts like clicking the "◎" button every time the content changes.
    388424            performScan(currentIndexRef.current || 1, false);
    389         }, [blocks, search, useRegex, caseSensitive, performScan, current]);
     425        }, [blocks, search, useRegex, caseSensitive, performScan]);
    390426
    391427        // Handles keyboard navigation ( Enter: Move to Next match. Shift + Enter: Move to Previous match. )
     
    393429            if (e.key === 'Enter') {
    394430                e.preventDefault();
    395                 if (totalCount === 0) return;
     431                if (totalCount === 0) {
     432                    lastSearchedRef.current = search;
     433                    performScan(1, true);
     434                    return;
     435                }
    396436
    397437                const isNewSearch = search !== lastSearchedRef.current;
    398                 if (isNewSearch) lastSearchedRef.current = search;
    399                 const nextIndex = isNewSearch ? 1 : (e.shiftKey ? (current <= 1 ? totalCount : current - 1) : (current >= totalCount ? 1 : current + 1));
    400                 performScan(nextIndex, true);
     438                if (isNewSearch) {
     439                    lastSearchedRef.current = search;
     440                    performScan(1, true);
     441                } else {
     442                    const nextIndex = e.shiftKey ? (current <= 1 ? totalCount : current - 1) : (current >= totalCount ? 1 : current + 1);
     443                    performScan(nextIndex, true);
     444                }
    401445            }
    402446        };
     
    427471            ),
    428472            wp.element.createElement('div', { style: { marginTop: '5px', border: '1px solid #ddd', padding: '8px', borderRadius: '4px' } },
    429                 wp.element.createElement(CheckboxControl, { label: i18n.autoPopulate || '選択テキストを自動入力', checked: autoPopulate, onChange: setAutoPopulate })
     473                wp.element.createElement(CheckboxControl, { label: i18n.autoPopulate, checked: autoPopulate, onChange: setAutoPopulate })
    430474            ),
    431475            wp.element.createElement('div', { style: { marginTop: '15px', padding: '10px', backgroundColor: '#f1f5f9', borderRadius: '4px' } },
  • livedraft-search-replace/trunk/livedraft-search-replace.php

    r3480776 r3481613  
    33 * Plugin Name: LiveDraft Search & Replace
    44 * Description: A high-performance, real-time Search and Replace tool for the Block Editor sidebar.
    5  * Version: 1.5.0
     5 * Version: 1.5.5
    66 * Author: Kasuga
    77 * License: GPLv2 or later
  • livedraft-search-replace/trunk/readme.txt

    r3480776 r3481613  
    66Tested up to: 6.9
    77Requires PHP: 7.4
    8 Stable tag: 1.5.0
     8Stable tag: 1.5.5
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    2525* **Performance First**: Optimized for large documents using virtual highlighting.
    2626* **Safe & Clean**: Your content is never polluted with temporary HTML tags. Highlighting is virtual and database-safe.
    27 * **Undo/Redo Ready**: Full integration with the WordPress core Undo system. One click to revert, zero risk of data loss.
     27* **Undo/Redo Ready**: Fully integrated with the WordPress core Undo system. You can revert any replacement by clicking the editor's Undo button, ensuring a safe and reliable editing experience.
    2828* **Flexible Navigation**: Seamlessly navigate and edit your content with precision as described below.
    2929
     
    101101== Changelog ==
    102102
     103= 1.5.5 =
     104* Fixed: Resolved a critical issue where the match counter would become inaccurate after repeated "Replace All" and "Undo" actions.
     105* Fixed: Corrected highlight and synchronization issues introduced by recent feature updates and standard editor operations.
     106
    103107= 1.5.0 =
    104108* Added: "Auto-populate from selection" feature. Automatically fills the search field with text selected in the editor.
Note: See TracChangeset for help on using the changeset viewer.