Changeset 3481613
- Timestamp:
- 03/13/2026 01:44:59 AM (3 weeks ago)
- Location:
- livedraft-search-replace
- Files:
-
- 10 added
- 3 edited
-
tags/1.5.5 (added)
-
tags/1.5.5/languages (added)
-
tags/1.5.5/languages/livedraft-search-replace-ja.mo (added)
-
tags/1.5.5/languages/livedraft-search-replace-ja.po (added)
-
tags/1.5.5/languages/livedraft-search-replace.pot (added)
-
tags/1.5.5/livedraft-search-replace.js (added)
-
tags/1.5.5/livedraft-search-replace.php (added)
-
tags/1.5.5/readme.txt (added)
-
tags/1.5.5/screenshot-1.png (added)
-
tags/1.5.5/screenshot-2.png (added)
-
trunk/livedraft-search-replace.js (modified) (10 diffs)
-
trunk/livedraft-search-replace.php (modified) (1 diff)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
livedraft-search-replace/trunk/livedraft-search-replace.js
r3480776 r3481613 9 9 * @copyright 2026 Kasuga 10 10 * @license GPL-2.0-or-later 11 * @version 1.8. 011 * @version 1.8.8 12 12 */ 13 13 … … 82 82 if (!autoPopulate) return; 83 83 const handleSelectionChange = () => { 84 if (isInternalUpdating.current) return; 84 85 if (document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA')) return; 85 86 const selection = window.getSelection(); 86 87 if (selection && selection.rangeCount > 0) { 87 88 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 } 89 93 } 90 94 }; … … 124 128 matchesRef.current = []; 125 129 setTotalCount(0); 130 setCurrent(0); 126 131 ticking.current = false; 127 132 return; … … 215 220 216 221 } else { 217 setCurrent(0); currentIndexRef.current = 0; 222 setCurrent(0); 223 currentIndexRef.current = 0; 218 224 } 219 225 ticking.current = false; … … 225 231 226 232 const currentIdx = currentIndexRef.current; 233 const prevTotal = matchesRef.current.length; 227 234 const targetMatch = specificMatch || (all ? null : matchesRef.current[currentIdx - 1]); 228 235 if (!all && !targetMatch) return; … … 324 331 const clientIds = [...new Set(matchesRef.current.map(m => m.clientId))]; 325 332 clientIds.forEach(cid => performUpdate(cid)); 333 // Clear matches immediately on replace all 334 matchesRef.current = []; 326 335 327 336 } else { … … 330 339 } 331 340 341 // After replacement, finalize state if 'all' is true, or force a rescan to sync highlights for individual replacement. 332 342 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]); 338 362 339 363 useEffect(() => { … … 385 409 386 410 useEffect(() => { 411 // Triggered on every block change (including Undo/Redo and after Replace). 387 412 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. 388 424 performScan(currentIndexRef.current || 1, false); 389 }, [blocks, search, useRegex, caseSensitive, performScan , current]);425 }, [blocks, search, useRegex, caseSensitive, performScan]); 390 426 391 427 // Handles keyboard navigation ( Enter: Move to Next match. Shift + Enter: Move to Previous match. ) … … 393 429 if (e.key === 'Enter') { 394 430 e.preventDefault(); 395 if (totalCount === 0) return; 431 if (totalCount === 0) { 432 lastSearchedRef.current = search; 433 performScan(1, true); 434 return; 435 } 396 436 397 437 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 } 401 445 } 402 446 }; … … 427 471 ), 428 472 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 }) 430 474 ), 431 475 wp.element.createElement('div', { style: { marginTop: '15px', padding: '10px', backgroundColor: '#f1f5f9', borderRadius: '4px' } }, -
livedraft-search-replace/trunk/livedraft-search-replace.php
r3480776 r3481613 3 3 * Plugin Name: LiveDraft Search & Replace 4 4 * Description: A high-performance, real-time Search and Replace tool for the Block Editor sidebar. 5 * Version: 1.5. 05 * Version: 1.5.5 6 6 * Author: Kasuga 7 7 * License: GPLv2 or later -
livedraft-search-replace/trunk/readme.txt
r3480776 r3481613 6 6 Tested up to: 6.9 7 7 Requires PHP: 7.4 8 Stable tag: 1.5. 08 Stable tag: 1.5.5 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 25 25 * **Performance First**: Optimized for large documents using virtual highlighting. 26 26 * **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. 28 28 * **Flexible Navigation**: Seamlessly navigate and edit your content with precision as described below. 29 29 … … 101 101 == Changelog == 102 102 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 103 107 = 1.5.0 = 104 108 * 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.