mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-17 22:08:25 +08:00
161 lines
4.1 KiB
JavaScript
161 lines
4.1 KiB
JavaScript
import { bfsWalk, getTextFromHtml, isUndef } from '../utils/index'
|
|
|
|
// 搜索插件
|
|
class Search {
|
|
// 构造函数
|
|
constructor({ mindMap }) {
|
|
this.mindMap = mindMap
|
|
// 是否正在搜索
|
|
this.isSearching = false
|
|
// 搜索文本
|
|
this.searchText = ''
|
|
// 匹配的节点列表
|
|
this.matchNodeList = []
|
|
// 当前所在的节点列表索引
|
|
this.currentIndex = -1
|
|
// 不要复位搜索文本
|
|
this.notResetSearchText = false
|
|
this.onDataChange = this.onDataChange.bind(this)
|
|
this.mindMap.on('data_change', this.onDataChange)
|
|
}
|
|
|
|
// 节点数据改变了,需要重新搜索
|
|
onDataChange() {
|
|
if (this.notResetSearchText) {
|
|
this.notResetSearchText = false
|
|
return
|
|
}
|
|
this.searchText = ''
|
|
}
|
|
|
|
// 搜索
|
|
search(text, callback) {
|
|
if (isUndef(text)) return this.endSearch()
|
|
text = String(text)
|
|
this.isSearching = true
|
|
if (this.searchText === text) {
|
|
// 和上一次搜索文本一样,那么搜索下一个
|
|
this.searchNext(callback)
|
|
} else {
|
|
// 和上次搜索文本不一样,那么重新开始
|
|
this.searchText = text
|
|
this.doSearch()
|
|
this.searchNext(callback)
|
|
}
|
|
this.emitEvent()
|
|
}
|
|
|
|
// 结束搜索
|
|
endSearch() {
|
|
if (!this.isSearching) return
|
|
this.searchText = ''
|
|
this.matchNodeList = []
|
|
this.currentIndex = -1
|
|
this.notResetSearchText = false
|
|
this.isSearching = false
|
|
this.emitEvent()
|
|
}
|
|
|
|
// 搜索匹配的节点
|
|
doSearch() {
|
|
this.matchNodeList = []
|
|
this.currentIndex = -1
|
|
bfsWalk(this.mindMap.renderer.root, node => {
|
|
let { richText, text } = node.nodeData.data
|
|
if (richText) {
|
|
text = getTextFromHtml(text)
|
|
}
|
|
if (text.includes(this.searchText)) {
|
|
this.matchNodeList.push(node)
|
|
}
|
|
})
|
|
}
|
|
|
|
// 搜索下一个,定位到下一个匹配节点
|
|
searchNext(callback) {
|
|
if (!this.isSearching || this.matchNodeList.length <= 0) return
|
|
if (this.currentIndex < this.matchNodeList.length - 1) {
|
|
this.currentIndex++
|
|
} else {
|
|
this.currentIndex = 0
|
|
}
|
|
let currentNode = this.matchNodeList[this.currentIndex]
|
|
this.notResetSearchText = true
|
|
this.mindMap.execCommand('GO_TARGET_NODE', currentNode, () => {
|
|
this.notResetSearchText = false
|
|
callback()
|
|
})
|
|
}
|
|
|
|
// 替换当前节点
|
|
replace(replaceText) {
|
|
if (
|
|
isUndef(replaceText) ||
|
|
!this.isSearching ||
|
|
this.matchNodeList.length <= 0
|
|
)
|
|
return
|
|
replaceText = String(replaceText)
|
|
let currentNode = this.matchNodeList[this.currentIndex]
|
|
if (!currentNode) return
|
|
let text = this.getReplacedText(currentNode, this.searchText, replaceText)
|
|
this.notResetSearchText = true
|
|
currentNode.setText(text, currentNode.nodeData.data.richText, true)
|
|
this.matchNodeList = this.matchNodeList.filter(node => {
|
|
return currentNode !== node
|
|
})
|
|
if (this.currentIndex > this.matchNodeList.length - 1) {
|
|
this.currentIndex = -1
|
|
} else {
|
|
this.currentIndex--
|
|
}
|
|
this.emitEvent()
|
|
}
|
|
|
|
// 替换所有
|
|
replaceAll(replaceText) {
|
|
if (
|
|
isUndef(replaceText) ||
|
|
!this.isSearching ||
|
|
this.matchNodeList.length <= 0
|
|
)
|
|
return
|
|
replaceText = String(replaceText)
|
|
this.matchNodeList.forEach(node => {
|
|
let text = this.getReplacedText(node, this.searchText, replaceText)
|
|
this.mindMap.renderer.setNodeDataRender(
|
|
node,
|
|
{
|
|
text,
|
|
resetRichText: !!node.nodeData.data.richText
|
|
},
|
|
true
|
|
)
|
|
})
|
|
this.mindMap.render()
|
|
this.mindMap.command.addHistory()
|
|
this.endSearch()
|
|
}
|
|
|
|
// 获取某个节点替换后的文本
|
|
getReplacedText(node, searchText, replaceText) {
|
|
let { richText, text } = node.nodeData.data
|
|
if (richText) {
|
|
text = getTextFromHtml(text)
|
|
}
|
|
return text.replaceAll(searchText, replaceText)
|
|
}
|
|
|
|
// 发送事件
|
|
emitEvent() {
|
|
this.mindMap.emit('search_info_change', {
|
|
currentIndex: this.currentIndex,
|
|
total: this.matchNodeList.length
|
|
})
|
|
}
|
|
}
|
|
|
|
Search.instanceName = 'search'
|
|
|
|
export default Search
|