Merge pull request #28 from Hufe921/feature/search-replace
Feature/search replace
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import Editor, { ElementType } from '../../../src/editor'
|
||||
|
||||
describe('菜单-搜索', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit('http://localhost:3000/canvas-editor/')
|
||||
|
||||
cy.get('canvas').first().as('canvas').should('have.length', 1)
|
||||
})
|
||||
|
||||
const searchText = 'canvas-editor'
|
||||
const replaceText = 'replace'
|
||||
const type: ElementType = <ElementType>'table'
|
||||
|
||||
it('搜索', () => {
|
||||
cy.getEditor().then((editor: Editor) => {
|
||||
editor.listener.saved = function (payload) {
|
||||
const data = payload.data
|
||||
|
||||
// 普通文本
|
||||
expect(data[0].value).to.be.eq(replaceText)
|
||||
|
||||
// 表格内文本
|
||||
expect(data[1].trList![0].tdList[0].value[0].value).to.be.eq(replaceText)
|
||||
expect(data[1].trList![1].tdList[1].value[0].value).to.be.eq(replaceText)
|
||||
}
|
||||
|
||||
editor.command.executeSelectAll()
|
||||
|
||||
editor.command.executeBackspace()
|
||||
|
||||
editor.command.executeInsertElementList([
|
||||
{
|
||||
value: searchText
|
||||
},
|
||||
{
|
||||
value: "\n",
|
||||
type,
|
||||
trList: [
|
||||
{
|
||||
height: 42,
|
||||
tdList: [
|
||||
{
|
||||
colspan: 1,
|
||||
rowspan: 1,
|
||||
value: [
|
||||
{
|
||||
value: searchText
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
colspan: 1,
|
||||
rowspan: 1,
|
||||
value: []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
height: 42,
|
||||
tdList: [
|
||||
{
|
||||
colspan: 1,
|
||||
rowspan: 1,
|
||||
value: []
|
||||
},
|
||||
{
|
||||
colspan: 1,
|
||||
rowspan: 1,
|
||||
value: [
|
||||
{
|
||||
value: searchText
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
colgroup: [
|
||||
{
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
width: 200
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
cy.get('.menu-item__search').click()
|
||||
|
||||
cy.get('.menu-item__search__collapse input').eq(0).type(searchText)
|
||||
|
||||
cy.get('.menu-item__search__collapse__replace').as('replace')
|
||||
|
||||
cy.get('@replace').find('input').type(replaceText)
|
||||
|
||||
cy.get('@replace').find('button').click()
|
||||
|
||||
cy.get('@canvas').type('{ctrl}s')
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
@@ -171,6 +171,10 @@
|
||||
<input type="text" />
|
||||
<span>×</span>
|
||||
</div>
|
||||
<div class="menu-item__search__collapse__replace">
|
||||
<input type="text">
|
||||
<button>替换</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-item__print" data-menu="print">
|
||||
<i></i>
|
||||
|
||||
@@ -51,6 +51,7 @@ export class Command {
|
||||
private static addWatermark: Function
|
||||
private static deleteWatermark: Function
|
||||
private static search: Function
|
||||
private static replace: Function
|
||||
private static print: Function
|
||||
private static pageScaleRecovery: Function
|
||||
private static pageScaleMinus: Function
|
||||
@@ -102,6 +103,7 @@ export class Command {
|
||||
Command.addWatermark = adapt.addWatermark.bind(adapt)
|
||||
Command.deleteWatermark = adapt.deleteWatermark.bind(adapt)
|
||||
Command.search = adapt.search.bind(adapt)
|
||||
Command.replace = adapt.replace.bind(adapt)
|
||||
Command.print = adapt.print.bind(adapt)
|
||||
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
|
||||
Command.pageScaleMinus = adapt.pageScaleMinus.bind(adapt)
|
||||
@@ -289,6 +291,10 @@ export class Command {
|
||||
return Command.search(payload)
|
||||
}
|
||||
|
||||
public executeReplace(payload: string) {
|
||||
return Command.replace(payload)
|
||||
}
|
||||
|
||||
public executePrint() {
|
||||
return Command.print()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WRAP, ZERO } from "../../dataset/constant/Common"
|
||||
import { EDITOR_ELEMENT_STYLE_ATTR, TEXTLIKE_ELEMENT_TYPE } from "../../dataset/constant/Element"
|
||||
import { EDITOR_ELEMENT_STYLE_ATTR } from "../../dataset/constant/Element"
|
||||
import { defaultWatermarkOption } from "../../dataset/constant/Watermark"
|
||||
import { EditorContext, EditorMode } from "../../dataset/enum/Editor"
|
||||
import { ElementType } from "../../dataset/enum/Element"
|
||||
@@ -8,7 +8,6 @@ import { RowFlex } from "../../dataset/enum/Row"
|
||||
import { IDrawImagePayload } from "../../interface/Draw"
|
||||
import { IEditorOption } from "../../interface/Editor"
|
||||
import { IElement, IElementStyle } from "../../interface/Element"
|
||||
import { ISearchResult, ISearchResultRestArgs } from "../../interface/Search"
|
||||
import { IColgroup } from "../../interface/table/Colgroup"
|
||||
import { ITd } from "../../interface/table/Td"
|
||||
import { ITr } from "../../interface/table/Tr"
|
||||
@@ -1091,94 +1090,104 @@ export class CommandAdapt {
|
||||
}
|
||||
|
||||
public search(payload: string | null) {
|
||||
if (payload) {
|
||||
let searchMatchList: ISearchResult[] = []
|
||||
// 分组
|
||||
const elementListGroup: { type: EditorContext, elementList: IElement[], index: number }[] = []
|
||||
const originalElementList = this.draw.getOriginalElementList()
|
||||
const originalElementListLength = originalElementList.length
|
||||
// 查找表格所在位置
|
||||
const tableIndexList = []
|
||||
for (let e = 0; e < originalElementListLength; e++) {
|
||||
const element = originalElementList[e]
|
||||
if (element.type === ElementType.TABLE) {
|
||||
tableIndexList.push(e)
|
||||
}
|
||||
}
|
||||
let i = 0
|
||||
let elementIndex = 0
|
||||
while (elementIndex < originalElementListLength - 1) {
|
||||
const endIndex = tableIndexList.length ? tableIndexList[i] : originalElementListLength
|
||||
const pageElement = originalElementList.slice(elementIndex, endIndex)
|
||||
if (pageElement.length) {
|
||||
elementListGroup.push({
|
||||
index: elementIndex,
|
||||
type: EditorContext.PAGE,
|
||||
elementList: pageElement
|
||||
this.draw.setSearchKeyword(payload)
|
||||
this.draw.render({
|
||||
isSetCursor: false,
|
||||
isSubmitHistory: false
|
||||
})
|
||||
}
|
||||
const tableElement = originalElementList[endIndex]
|
||||
if (tableElement) {
|
||||
elementListGroup.push({
|
||||
index: endIndex,
|
||||
type: EditorContext.TABLE,
|
||||
elementList: [tableElement]
|
||||
|
||||
public replace(payload: string) {
|
||||
if (!payload || new RegExp(`${ZERO}`, 'g').test(payload)) return
|
||||
const matchList = this.draw.getSearch().getSearchMatchList()
|
||||
if (!matchList.length) return
|
||||
// 匹配index变化的差值
|
||||
let pageDiffCount = 0
|
||||
let tableDiffCount = 0
|
||||
// 匹配搜索词的组标识
|
||||
let curGroupId = ''
|
||||
// 表格上下文
|
||||
let curTdId = ''
|
||||
// 搜索值 > 替换值:增加元素;搜索值 < 替换值:减少元素
|
||||
const elementList = this.draw.getOriginalElementList()
|
||||
for (let m = 0; m < matchList.length; m++) {
|
||||
const match = matchList[m]
|
||||
if (match.type === EditorContext.TABLE) {
|
||||
const { tableIndex, trIndex, tdIndex, index, tdId } = match
|
||||
if (curTdId && tdId !== curTdId) {
|
||||
tableDiffCount = 0
|
||||
}
|
||||
curTdId = tdId!
|
||||
const curTableIndex = tableIndex! + pageDiffCount
|
||||
const tableElementList = elementList[curTableIndex].trList![trIndex!].tdList[tdIndex!].value
|
||||
// 表格内元素
|
||||
const curIndex = index + tableDiffCount
|
||||
const tableElement = tableElementList[curIndex]
|
||||
if (curGroupId === match.groupId) {
|
||||
tableElementList.splice(curIndex, 1)
|
||||
tableDiffCount--
|
||||
continue
|
||||
}
|
||||
for (let p = 0; p < payload.length; p++) {
|
||||
const value = payload[p]
|
||||
if (p === 0) {
|
||||
tableElement.value = value
|
||||
} else {
|
||||
tableElementList.splice(curIndex + p, 0, {
|
||||
...tableElement,
|
||||
value
|
||||
})
|
||||
}
|
||||
elementIndex = endIndex + 1
|
||||
i++
|
||||
}
|
||||
// 搜索文本
|
||||
function searchClosure(payload: string | null, type: EditorContext, elementList: IElement[], restArgs?: ISearchResultRestArgs) {
|
||||
if (!payload) return
|
||||
const text = elementList.map(e => !e.type || TEXTLIKE_ELEMENT_TYPE.includes(e.type) ? e.value : ZERO)
|
||||
.filter(Boolean)
|
||||
.join('')
|
||||
const matchStartIndexList = []
|
||||
let index = text.indexOf(payload)
|
||||
while (index !== -1) {
|
||||
matchStartIndexList.push(index)
|
||||
index = text.indexOf(payload, index + 1)
|
||||
}
|
||||
for (let m = 0; m < matchStartIndexList.length; m++) {
|
||||
const startIndex = matchStartIndexList[m]
|
||||
for (let i = 0; i < payload.length; i++) {
|
||||
const index = startIndex + i + (restArgs?.startIndex || 0)
|
||||
searchMatchList.push({
|
||||
type,
|
||||
index,
|
||||
...restArgs
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let e = 0; e < elementListGroup.length; e++) {
|
||||
const group = elementListGroup[e]
|
||||
if (group.type === EditorContext.TABLE) {
|
||||
const tableElement = group.elementList[0]
|
||||
for (let t = 0; t < tableElement.trList!.length; t++) {
|
||||
const tr = tableElement.trList![t]
|
||||
for (let d = 0; d < tr.tdList.length; d++) {
|
||||
const td = tr.tdList[d]
|
||||
const restArgs: ISearchResultRestArgs = {
|
||||
tableIndex: group.index,
|
||||
trIndex: t,
|
||||
tdIndex: d
|
||||
}
|
||||
searchClosure(payload, group.type, td.value, restArgs)
|
||||
tableDiffCount++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
searchClosure(payload, group.type, group.elementList, {
|
||||
startIndex: group.index
|
||||
const curIndex = match.index + pageDiffCount
|
||||
const element = elementList[curIndex]
|
||||
if (curGroupId === match.groupId) {
|
||||
elementList.splice(curIndex, 1)
|
||||
pageDiffCount--
|
||||
continue
|
||||
}
|
||||
for (let p = 0; p < payload.length; p++) {
|
||||
const value = payload[p]
|
||||
if (p === 0) {
|
||||
element.value = value
|
||||
} else {
|
||||
elementList.splice(curIndex + p, 0, {
|
||||
...element,
|
||||
value
|
||||
})
|
||||
pageDiffCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
curGroupId = match.groupId
|
||||
}
|
||||
// 定位-首个被匹配关键词后
|
||||
const firstMatch = matchList[0]
|
||||
const firstIndex = firstMatch.index + (payload.length - 1)
|
||||
if (firstMatch.type === EditorContext.TABLE) {
|
||||
const { tableIndex, trIndex, tdIndex, index } = firstMatch
|
||||
const element = elementList[tableIndex!].trList![trIndex!].tdList[tdIndex!].value[index]
|
||||
this.position.setPositionContext({
|
||||
isTable: true,
|
||||
index: tableIndex,
|
||||
trIndex,
|
||||
tdIndex,
|
||||
tdId: element.tdId,
|
||||
trId: element.trId,
|
||||
tableId: element.tableId
|
||||
})
|
||||
} else {
|
||||
this.position.setPositionContext({
|
||||
isTable: false
|
||||
})
|
||||
}
|
||||
}
|
||||
this.draw.setSearchMatch(searchMatchList)
|
||||
} else {
|
||||
this.draw.setSearchMatch(null)
|
||||
}
|
||||
this.draw.render({ isSetCursor: false, isSubmitHistory: false })
|
||||
this.range.setRange(firstIndex, firstIndex)
|
||||
// 重新渲染
|
||||
this.draw.render({
|
||||
curIndex: firstIndex
|
||||
})
|
||||
}
|
||||
|
||||
public print() {
|
||||
|
||||
@@ -24,7 +24,6 @@ import { TextParticle } from "./particle/TextParticle"
|
||||
import { PageNumber } from "./frame/PageNumber"
|
||||
import { GlobalObserver } from "../observer/GlobalObserver"
|
||||
import { TableParticle } from "./particle/table/TableParticle"
|
||||
import { ISearchResult } from "../../interface/Search"
|
||||
import { TableTool } from "./particle/table/TableTool"
|
||||
import { HyperlinkParticle } from "./particle/HyperlinkParticle"
|
||||
import { Header } from "./frame/Header"
|
||||
@@ -73,7 +72,7 @@ export class Draw {
|
||||
|
||||
private rowList: IRow[]
|
||||
private painterStyle: IElementStyle | null
|
||||
private searchMatchList: ISearchResult[] | null
|
||||
private searchKeyword: string | null
|
||||
private visiblePageNoList: number[]
|
||||
private intersectionPageNo: number
|
||||
|
||||
@@ -127,7 +126,7 @@ export class Draw {
|
||||
|
||||
this.rowList = []
|
||||
this.painterStyle = null
|
||||
this.searchMatchList = null
|
||||
this.searchKeyword = null
|
||||
this.visiblePageNoList = []
|
||||
this.intersectionPageNo = 0
|
||||
|
||||
@@ -247,6 +246,10 @@ export class Draw {
|
||||
return this.options
|
||||
}
|
||||
|
||||
public getSearch(): Search {
|
||||
return this.search
|
||||
}
|
||||
|
||||
public getHistoryManager(): HistoryManager {
|
||||
return this.historyManager
|
||||
}
|
||||
@@ -315,12 +318,12 @@ export class Draw {
|
||||
}
|
||||
}
|
||||
|
||||
public getSearchMatch(): ISearchResult[] | null {
|
||||
return this.searchMatchList
|
||||
public getSearchKeyword(): string | null {
|
||||
return this.searchKeyword
|
||||
}
|
||||
|
||||
public setSearchMatch(payload: ISearchResult[] | null) {
|
||||
this.searchMatchList = payload
|
||||
public setSearchKeyword(payload: string | null) {
|
||||
this.searchKeyword = payload
|
||||
}
|
||||
|
||||
public setDefaultRange() {
|
||||
@@ -781,7 +784,7 @@ export class Draw {
|
||||
// 绘制页码
|
||||
this.pageNumber.render(ctx, pageNo)
|
||||
// 搜索匹配绘制
|
||||
if (this.searchMatchList) {
|
||||
if (this.searchKeyword) {
|
||||
this.search.render(ctx, pageNo)
|
||||
}
|
||||
// 绘制水印
|
||||
@@ -802,6 +805,9 @@ export class Draw {
|
||||
// 计算行信息
|
||||
if (isComputeRowList) {
|
||||
this.rowList = this._computeRowList(innerWidth, this.elementList)
|
||||
if (this.searchKeyword) {
|
||||
this.search.compute(this.searchKeyword)
|
||||
}
|
||||
}
|
||||
// 清除光标等副作用
|
||||
this.cursor.recoveryCursor()
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { ZERO } from "../../../dataset/constant/Common"
|
||||
import { TEXTLIKE_ELEMENT_TYPE } from "../../../dataset/constant/Element"
|
||||
import { EditorContext } from "../../../dataset/enum/Editor"
|
||||
import { ElementType } from "../../../dataset/enum/Element"
|
||||
import { IEditorOption } from "../../../interface/Editor"
|
||||
import { IElementPosition } from "../../../interface/Element"
|
||||
import { IElement, IElementPosition } from "../../../interface/Element"
|
||||
import { ISearchResult, ISearchResultRestArgs } from "../../../interface/Search"
|
||||
import { getUUID } from "../../../utils"
|
||||
import { Position } from "../../position/Position"
|
||||
import { Draw } from "../Draw"
|
||||
|
||||
@@ -9,24 +14,118 @@ export class Search {
|
||||
private draw: Draw
|
||||
private options: Required<IEditorOption>
|
||||
private position: Position
|
||||
private searchMatchList: ISearchResult[]
|
||||
|
||||
constructor(draw: Draw) {
|
||||
this.draw = draw
|
||||
this.options = draw.getOptions()
|
||||
this.position = draw.getPosition()
|
||||
this.searchMatchList = []
|
||||
}
|
||||
|
||||
public getSearchMatchList(): ISearchResult[] {
|
||||
return this.searchMatchList
|
||||
}
|
||||
|
||||
public compute(payload: string) {
|
||||
let searchMatchList: ISearchResult[] = []
|
||||
// 分组
|
||||
const elementListGroup: { type: EditorContext, elementList: IElement[], index: number }[] = []
|
||||
const originalElementList = this.draw.getOriginalElementList()
|
||||
const originalElementListLength = originalElementList.length
|
||||
// 查找表格所在位置
|
||||
const tableIndexList = []
|
||||
for (let e = 0; e < originalElementListLength; e++) {
|
||||
const element = originalElementList[e]
|
||||
if (element.type === ElementType.TABLE) {
|
||||
tableIndexList.push(e)
|
||||
}
|
||||
}
|
||||
let i = 0
|
||||
let elementIndex = 0
|
||||
while (elementIndex < originalElementListLength - 1) {
|
||||
const endIndex = tableIndexList.length ? tableIndexList[i] : originalElementListLength
|
||||
const pageElement = originalElementList.slice(elementIndex, endIndex)
|
||||
if (pageElement.length) {
|
||||
elementListGroup.push({
|
||||
index: elementIndex,
|
||||
type: EditorContext.PAGE,
|
||||
elementList: pageElement
|
||||
})
|
||||
}
|
||||
const tableElement = originalElementList[endIndex]
|
||||
if (tableElement) {
|
||||
elementListGroup.push({
|
||||
index: endIndex,
|
||||
type: EditorContext.TABLE,
|
||||
elementList: [tableElement]
|
||||
})
|
||||
}
|
||||
elementIndex = endIndex + 1
|
||||
i++
|
||||
}
|
||||
// 搜索文本
|
||||
function searchClosure(payload: string | null, type: EditorContext, elementList: IElement[], restArgs?: ISearchResultRestArgs) {
|
||||
if (!payload) return
|
||||
const text = elementList.map(e => !e.type || TEXTLIKE_ELEMENT_TYPE.includes(e.type) ? e.value : ZERO)
|
||||
.filter(Boolean)
|
||||
.join('')
|
||||
const matchStartIndexList = []
|
||||
let index = text.indexOf(payload)
|
||||
while (index !== -1) {
|
||||
matchStartIndexList.push(index)
|
||||
index = text.indexOf(payload, index + 1)
|
||||
}
|
||||
for (let m = 0; m < matchStartIndexList.length; m++) {
|
||||
const startIndex = matchStartIndexList[m]
|
||||
const groupId = getUUID()
|
||||
for (let i = 0; i < payload.length; i++) {
|
||||
const index = startIndex + i + (restArgs?.startIndex || 0)
|
||||
searchMatchList.push({
|
||||
type,
|
||||
index,
|
||||
groupId,
|
||||
...restArgs
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let e = 0; e < elementListGroup.length; e++) {
|
||||
const group = elementListGroup[e]
|
||||
if (group.type === EditorContext.TABLE) {
|
||||
const tableElement = group.elementList[0]
|
||||
for (let t = 0; t < tableElement.trList!.length; t++) {
|
||||
const tr = tableElement.trList![t]
|
||||
for (let d = 0; d < tr.tdList.length; d++) {
|
||||
const td = tr.tdList[d]
|
||||
const restArgs: ISearchResultRestArgs = {
|
||||
tableIndex: group.index,
|
||||
trIndex: t,
|
||||
tdIndex: d,
|
||||
tdId: td.id
|
||||
}
|
||||
searchClosure(payload, group.type, td.value, restArgs)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
searchClosure(payload, group.type, group.elementList, {
|
||||
startIndex: group.index
|
||||
})
|
||||
}
|
||||
}
|
||||
this.searchMatchList = searchMatchList
|
||||
}
|
||||
|
||||
public render(ctx: CanvasRenderingContext2D, pageIndex: number) {
|
||||
const searchMatchList = this.draw.getSearchMatch()
|
||||
if (!searchMatchList || !searchMatchList.length) return
|
||||
if (!this.searchMatchList || !this.searchMatchList.length) return
|
||||
const { searchMatchAlpha, searchMatchColor } = this.options
|
||||
const positionList = this.position.getOriginalPositionList()
|
||||
const elementList = this.draw.getOriginalElementList()
|
||||
ctx.save()
|
||||
ctx.globalAlpha = searchMatchAlpha
|
||||
ctx.fillStyle = searchMatchColor
|
||||
for (let s = 0; s < searchMatchList.length; s++) {
|
||||
const searchMatch = searchMatchList[s]
|
||||
for (let s = 0; s < this.searchMatchList.length; s++) {
|
||||
const searchMatch = this.searchMatchList[s]
|
||||
let position: IElementPosition | null = null
|
||||
if (searchMatch.type === EditorContext.TABLE) {
|
||||
const { tableIndex, trIndex, tdIndex, index } = searchMatch
|
||||
|
||||
@@ -3,12 +3,14 @@ import { EditorContext } from "../dataset/enum/Editor"
|
||||
export interface ISearchResultBasic {
|
||||
type: EditorContext;
|
||||
index: number;
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
export interface ISearchResultRestArgs {
|
||||
tableIndex?: number;
|
||||
trIndex?: number;
|
||||
tdIndex?: number;
|
||||
tdId?: string;
|
||||
startIndex?: number;
|
||||
}
|
||||
|
||||
|
||||
+31
-12
@@ -402,24 +402,43 @@ window.onload = function () {
|
||||
})
|
||||
}
|
||||
|
||||
// 5. | 搜索 | 打印 |
|
||||
const searchCollapseDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')
|
||||
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')
|
||||
document.querySelector<HTMLDivElement>('.menu-item__search')!.onclick = function () {
|
||||
// 5. | 搜索&替换 | 打印 |
|
||||
const searchCollapseDom = document.querySelector<HTMLDivElement>('.menu-item__search__collapse')!
|
||||
const searchInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__search input')!
|
||||
const replaceInputDom = document.querySelector<HTMLInputElement>('.menu-item__search__collapse__replace input')!
|
||||
const searchDom = document.querySelector<HTMLDivElement>('.menu-item__search')!
|
||||
searchDom.onclick = function () {
|
||||
console.log('search')
|
||||
searchCollapseDom!.style.display = 'block'
|
||||
searchCollapseDom.style.display = 'block'
|
||||
const bodyRect = document.body.getBoundingClientRect()
|
||||
const searchRect = searchDom.getBoundingClientRect()
|
||||
const searchCollapseRect = searchCollapseDom.getBoundingClientRect()
|
||||
if (searchRect.left + searchCollapseRect.width > bodyRect.width) {
|
||||
searchCollapseDom.style.right = '0px'
|
||||
searchCollapseDom.style.left = 'unset'
|
||||
} else {
|
||||
searchCollapseDom.style.right = 'unset'
|
||||
}
|
||||
document.querySelector<HTMLDivElement>('.menu-item__search__collapse span')!.onclick = function () {
|
||||
searchCollapseDom!.style.display = 'none'
|
||||
searchInputDom!.value = ''
|
||||
}
|
||||
searchCollapseDom.querySelector<HTMLSpanElement>('span')!.onclick = function () {
|
||||
searchCollapseDom.style.display = 'none'
|
||||
searchInputDom.value = ''
|
||||
replaceInputDom.value = ''
|
||||
instance.command.executeSearch(null)
|
||||
}
|
||||
searchInputDom!.oninput = function () {
|
||||
instance.command.executeSearch(searchInputDom?.value || null)
|
||||
searchInputDom.oninput = function () {
|
||||
instance.command.executeSearch(searchInputDom.value || null)
|
||||
}
|
||||
searchInputDom!.onkeydown = function (evt) {
|
||||
searchInputDom.onkeydown = function (evt) {
|
||||
if (evt.key === 'Enter') {
|
||||
instance.command.executeSearch(searchInputDom?.value || null)
|
||||
instance.command.executeSearch(searchInputDom.value || null)
|
||||
}
|
||||
}
|
||||
searchCollapseDom.querySelector<HTMLButtonElement>('button')!.onclick = function () {
|
||||
const searchValue = searchInputDom.value
|
||||
const replaceValue = replaceInputDom.value
|
||||
if (searchValue && replaceValue && searchValue !== replaceValue) {
|
||||
instance.command.executeReplace(replaceValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-7
@@ -439,30 +439,34 @@ ul {
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse {
|
||||
width: 215px;
|
||||
height: 36px;
|
||||
width: 235px;
|
||||
height: 72px;
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
display: none;
|
||||
z-index: 99;
|
||||
top: 25px;
|
||||
left: 0;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 5px 5px #e3dfdf;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse__search {
|
||||
width: 205px;
|
||||
.menu-item .menu-item__search__collapse:hover {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse>div {
|
||||
width: 225px;
|
||||
height: 36px;
|
||||
padding: 0 5px;
|
||||
line-height: 36px;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse__search input {
|
||||
.menu-item .menu-item__search__collapse>div input {
|
||||
height: 27px;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
@@ -477,12 +481,30 @@ ul {
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse__search span {
|
||||
.menu-item .menu-item__search__collapse>div span {
|
||||
height: 100%;
|
||||
color: #dcdfe6;
|
||||
font-size: 25px;
|
||||
display: inline-block;
|
||||
border: 0;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse__replace button {
|
||||
display: inline-block;
|
||||
border: 1px solid #e2e6ed;
|
||||
border-radius: 2px;
|
||||
background: #fff;
|
||||
line-height: 22px;
|
||||
padding: 0 6px;
|
||||
white-space: nowrap;
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.menu-item .menu-item__search__collapse__replace button:hover {
|
||||
background: rgba(25, 55, 88, .04);
|
||||
}
|
||||
|
||||
.menu-item__print i {
|
||||
|
||||
Reference in New Issue
Block a user