@progress/kendo-vue-editor
Version:
378 lines (377 loc) • 12 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import { defineComponent as V, createVNode as t, isVNode as P } from "vue";
import { Button as f } from "@progress/kendo-vue-buttons";
import { chevronRightIcon as $, chevronLeftIcon as F } from "@progress/kendo-svg-icons";
import { Window as q } from "@progress/kendo-vue-dialogs";
import { TabStrip as H, TabStripTab as E } from "@progress/kendo-vue-layout";
import { provideLocalizationService as G } from "@progress/kendo-vue-intl";
import { messages as l } from "../messages/main.mjs";
import { EditorToolsSettings as J } from "../config/toolsSettings.mjs";
import { formatString as Q } from "../tools/utils.mjs";
import { selectedLineTextOnly as X, textHighlightKey as Y, TextSelection as g, find as Z, replace as ee, replaceAll as te, findAll as ne } from "@progress/kendo-editor-common";
import { Icon as N } from "@progress/kendo-vue-common";
import { Error as se } from "@progress/kendo-vue-labels";
function x(e) {
return typeof e == "function" || Object.prototype.toString.call(e) === "[object Object]" && !P(e);
}
const ae = 13, ce = 27, ie = J.findAndReplace, be = /* @__PURE__ */ V({
name: "KendoFindAndReplaceDialog",
emits: {
close: null
},
props: {
view: Object,
settings: {
type: Object,
default: function() {
return ie;
}
},
dir: String
},
inject: {
kendoLocalizationService: {
default: null
}
},
created() {
this._prevMatch = void 0, this.nextMatch = void 0;
},
data() {
return {
selectedTab: 0,
searchText: X(this.$props.view.state),
replaceText: "",
matchCase: !1,
matchWord: !1,
matchCyclic: !1,
useRegExp: !1,
matches: [],
hasMounted: !1
};
},
mounted() {
this.$el && document.body.append(this.$el), this.setNextState(), this.hasMounted = !0, setTimeout(function() {
const e = document.getElementById("findWhatFind");
e && e.focus();
}, 10);
},
/**
* @hidden
*/
updated() {
const e = this.matches || [], n = this.nextMatch, s = this.$props.view;
if (this._prevMatch !== n) {
const a = s.state, i = a.tr, c = [];
e.forEach((o) => {
c.push({
from: o.from,
to: o.to,
attrs: {
class: n && o.eq(n) ? "k-text-selected" : "k-text-highlighted"
}
});
}), i.setMeta(Y, c), i.setSelection(n || g.create(a.doc, a.selection.from)), s.dispatch(i);
}
},
unmounted() {
this.$el && this.$el.remove();
},
render() {
let e, n;
const s = G(this), {
findReplaceDialogTitle: a,
findReplaceTabFind: i,
findReplaceTabReplace: c,
findReplaceFindWhat: o,
findReplaceReplaceWith: r,
findReplaceReplace: p,
findReplaceReplaceAll: u,
findReplaceMatchCase: k,
findReplaceMatchWord: b,
findReplaceMatchCyclic: S,
findReplaceUseRegExp: C,
findReplacePrevMatch: v,
findReplaceNextMatch: R,
findReplaceMatches: M
} = this.settings.messages, {
matchCase: _,
matchWord: I,
matchCyclic: j,
useRegExp: A,
searchText: B,
replaceText: O,
nextMatch: y,
error: m
} = this, T = t("div", {
class: "k-search-options"
}, [t("span", null, [t("input", {
class: "k-checkbox k-checkbox-md k-rounded-md",
type: "checkbox",
id: "match-case",
checked: _,
onChange: this.onMatchCaseChecked
}, null), t("label", {
for: "match-case",
class: "k-checkbox-label"
}, [s.toLanguageString(k, l[k])])]), t("span", null, [t("input", {
class: "k-checkbox k-checkbox-md k-rounded-md",
type: "checkbox",
id: "match-whole",
checked: I,
onChange: this.onMatchWordChecked
}, null), t("label", {
for: "match-whole",
class: "k-checkbox-label"
}, [s.toLanguageString(b, l[b])])]), t("span", null, [t("input", {
class: "k-checkbox k-checkbox-md k-rounded-md",
type: "checkbox",
id: "match-cyclic",
checked: j,
onChange: this.onMatchCyclicChecked
}, null), t("label", {
for: "match-cyclic",
class: "k-checkbox-label"
}, [s.toLanguageString(S, l[S])])]), t("span", null, [t("input", {
class: "k-checkbox k-checkbox-md k-rounded-md",
type: "checkbox",
id: "regular-expression",
checked: A,
onChange: this.onUseRegExpChecked
}, null), t("label", {
for: "regular-expression",
class: "k-checkbox-label"
}, [s.toLanguageString(C, l[C])])])]), w = function(d) {
const h = this.$props.dir === "rtl", K = t(f, {
fillMode: "flat",
themeColor: "primary",
onClick: this.onFindPrev
}, {
default: () => [t(N, {
name: `chevron-${h ? "right" : "left"}`,
icon: h ? $ : F
}, null), s.toLanguageString(v, l[v])]
}), U = t(f, {
fillMode: "flat",
themeColor: "primary",
onClick: this.onFindNext
}, {
default: () => [s.toLanguageString(R, l[R]), t(N, {
name: `chevron-${h ? "left" : "right"}`,
icon: h ? F : $
}, null)]
});
return t("div", {
class: "k-matches-container"
}, [K, this.hasMounted && t("span", {
ref: d
}, [this.matchesMessage(s.toLanguageString(M, l[M]))]), U]);
}, W = function(d) {
return t("div", {
class: "k-edit-label"
}, [t("label", {
ref: d,
for: d
}, [s.toLanguageString(o, l[o])])]);
}, L = function(d) {
let h;
return t("div", {
class: "k-edit-field"
}, [t("span", {
class: "k-textbox k-input k-input-md k-rounded-md k-input-solid"
}, [t("input", {
id: d,
ref: d,
type: "text",
class: "k-input-inner",
value: B,
onInput: this.onSearchChange,
onFocus: this.onSearchChange,
onKeydown: this.onKeyDown
}, null)]), m && t(se, null, x(h = s.toLanguageString(m, l[m])) ? h : {
default: () => [h]
})]);
}, z = t("div", {
class: "k-edit-label"
}, [t("label", {
for: "replaceWith"
}, [s.toLanguageString(r, l[r])])]), D = t("div", {
class: "k-edit-field"
}, [t("span", {
class: "k-textbox k-input k-input-md k-rounded-md k-input-solid"
}, [t("input", {
id: "replaceWith",
class: "k-input-inner",
type: "text",
value: O,
onInput: this.onReplaceChange
}, null)])]);
return t(q, {
title: s.toLanguageString(a, l[a]),
onClose: this.onClose,
windowStyle: {
width: "auto",
height: "auto",
userSelect: "none"
},
resizable: !1,
minimizeButton: () => null,
maximizeButton: () => null,
dir: this.$props.dir
}, {
default: () => [t(H, {
dir: this.$props.dir,
selected: this.selectedTab,
class: "k-editor-find-replace",
onSelect: this.onTabSelect,
animation: !1
}, {
default: () => [t(E, {
title: s.toLanguageString(i, l[i])
}, {
default: () => [t("div", {
class: "k-edit-form-container"
}, [W.call(this, "findWhatFind"), L.call(this, "findWhatFind")]), t("div", {
class: "k-actions k-hstack k-justify-content-end"
}, null), T, w.call(this, "findWhatFind")]
}), t(E, {
title: s.toLanguageString(c, l[c])
}, {
default: () => [t("div", {
class: "k-edit-form-container"
}, [W.call(this, "findWhatReplace"), L.call(this, "findWhatReplace"), z, D]), t("div", {
class: "k-actions k-hstack k-justify-content-end"
}, [t(f, {
disabled: !y,
onClick: this.onReplace
}, x(e = s.toLanguageString(p, l[p])) ? e : {
default: () => [e]
}), t(f, {
disabled: !y,
onClick: this.onReplaceAll
}, x(n = s.toLanguageString(u, l[u])) ? n : {
default: () => [n]
})]), T, w.call(this, "findWhatReplace")]
})]
})]
});
},
methods: {
onTabSelect(e) {
this.selectedTab = e.selected;
},
onClose() {
const e = this.$props.view, n = e.state, s = n.tr.setSelection(g.create(n.doc, n.selection.from, n.selection.to));
e.updateState(n.apply(s)), e.focus(), this.$emit("close");
},
matchesMessage(e) {
const n = this.matches, s = this.nextMatch;
let a = 0, i = 0;
if (n && s) {
const c = n.findIndex((o) => o.eq(s));
a = c === -1 ? n.length : c + 1, i = n.length;
}
return Q(e, a, i);
},
onFindNext() {
this.onFind();
},
onFindPrev() {
this.onFind(!0);
},
onFind(e = !1) {
const n = this.$props.view, {
searchText: s,
matchCase: a,
matchCyclic: i,
matchWord: c,
useRegExp: o
} = this.$data, r = {
text: s,
matchWord: c,
matchCase: a,
useRegExp: o,
backward: e,
matchCyclic: i
}, p = Z(n.state, r);
if (p) {
const u = n.state.tr.setSelection(p);
u.scrollIntoView(), n.updateState(n.state.apply(u)), this._prevMatch = this.nextMatch, this.nextMatch = p, this._prevMatch !== this.nextMatch && this.$forceUpdate();
}
},
onReplace() {
const e = this.$props.view, n = e.state.selection, {
replaceText: s
} = this.$data;
if (!n.empty) {
const a = n.from, i = a + s.length, c = ee(n, s, e.state.tr);
c.setSelection(g.create(c.doc, a, i)), c.scrollIntoView(), e.dispatch(c), this.onFind(), this.setNextState({});
}
},
onReplaceAll() {
const e = this.$props.view, {
searchText: n,
replaceText: s,
matchCase: a,
matchWord: i,
useRegExp: c
} = this.$data, o = {
text: n,
matchWord: i,
matchCase: a,
useRegExp: c
}, r = te(e.state, s, o);
r && (e.dispatch(r), this.setNextState({}));
},
onKeyDown(e) {
e.keyCode === ae ? this.onFindNext() : e.keyCode === ce && this.onClose();
},
onMatchCaseChecked(e) {
this.matchCase = e.target.checked, this.setNextState();
},
onMatchWordChecked(e) {
this.matchWord = e.target.checked, this.setNextState();
},
onMatchCyclicChecked(e) {
this.matchCyclic = e.target.checked, this.setNextState();
},
onUseRegExpChecked(e) {
this.useRegExp = e.target.checked, this.setNextState();
},
onSearchChange(e) {
this.searchText = e.target.value, this.setNextState();
},
onReplaceChange(e) {
this.replaceText = e.target.value, this.setNextState();
},
setNextState() {
const e = this.$props.view;
if (this.searchText) {
const n = {
text: this.searchText,
matchWord: this.matchWord,
matchCase: this.matchCase,
useRegExp: this.useRegExp
}, s = e.state.selection;
let a = [], i;
try {
a = ne(e.state.doc, n);
} catch (o) {
o instanceof SyntaxError && (i = this.settings.messages.findReplaceInvalidRegExp);
}
const c = !this.searchText && a[0] || a.find((o) => o.from >= s.from) || this.matchCyclic && a[0] || void 0;
this._prevMatch = this.nextMatch, this.matches = a, this.nextMatch = c, this.error = i;
} else
this._prevMatch = this.nextMatch, this.matches = [], this.nextMatch = void 0, this.error = void 0;
}
}
});
export {
be as FindAndReplaceDialog
};