diff --git a/examples/Components/Routes/Search/index.vue b/examples/Components/Routes/Search/index.vue index 6c2bd4a70..2cb1f3c26 100644 --- a/examples/Components/Routes/Search/index.vue +++ b/examples/Components/Routes/Search/index.vue @@ -121,9 +121,16 @@ placeholder="Search..." type="text" v-model="searchTerm" - > + > + + @@ -168,6 +175,7 @@ export default { return { searching: false, searchTerm: null, + replaceWith: null, editor: new Editor({ extensions: [ new Blockquote(), diff --git a/packages/tiptap-extensions/src/extensions/Search.js b/packages/tiptap-extensions/src/extensions/Search.js index ab85ffec0..2fe57f35d 100644 --- a/packages/tiptap-extensions/src/extensions/Search.js +++ b/packages/tiptap-extensions/src/extensions/Search.js @@ -47,6 +47,8 @@ export default class Search extends Extension { commands() { return { find: attrs => this.find(attrs), + replace: attrs => this.replace(attrs), + replaceAll: attrs => this.replaceAll(attrs), clearSearch: () => this.clear(), toggleSearch: () => this.toggleSearch(), } @@ -104,6 +106,40 @@ export default class Search extends Extension { }) } + replace(replace) { + return (state, dispatch) => { + const { from, to } = this.results[0] + + dispatch(state.tr.insertText(replace, from, to)) + } + } + + rebaseNextResult(replace, index) { + const nextIndex = index + 1 + if (!this.results[nextIndex]) return + + const nextStep = this.results[nextIndex] + const { from, to } = nextStep + const offset = (to - from - replace.length) * nextIndex + + this.results[nextIndex] = { + to: to - offset, + from: from - offset, + } + } + + replaceAll(replace) { + return ({ tr }, dispatch) => { + this.results.forEach(({ from, to }, index) => { + tr.insertText(replace, from, to) + + this.rebaseNextResult(replace, index) + }) + + dispatch(tr) + } + } + find(searchTerm) { return (state, dispatch) => { this.searchTerm = (this.options.disableRegex) ? searchTerm.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&') : searchTerm