forTeam/view/tool/Tool.js

623 lines
25 KiB
JavaScript
Raw Normal View History

2021-11-23 11:14:33 +08:00
const {shakeDom, shakeDomFocus, log} = require('../../js/Utility')
const {IS_IN_DEVELOP} = require('../../js/Global')
const path = require('path')
const Dict = require('../../js/Dict')
const DictOther = require('../../js/DictOther')
const DictMap = require('../../js/DictMap')
const Word = require('../../js/Word')
const Vue = require('../../node_modules/vue/dist/vue.common.prod')
const {ipcRenderer} = require('electron')
const VirtualScroller = require('vue-virtual-scroller')
// Vue 2
const app = {
el: '#app',
components: {RecycleScroller: VirtualScroller.RecycleScroller},
data() {
return {
IS_IN_DEVELOP: IS_IN_DEVELOP, // 是否为开发模式html 使用
tip: '', // 提示信息
dict: {
deep: true
}, // 当前词库对象 Dict
dictMain: {}, // 主码表 Dict
keyword: '', // 搜索关键字
code: '',
word: '',
activeGroupId: -1, // 组 index
keywordUnwatch: null, // keyword watch 方法的撤消方法
labelOfSaveBtn: '保存', // 保存按钮的文本
heightContent: 0, // content 高度
words: [], // 显示的 words
chosenWordIds: new Set(),
chosenWordIdArray: [], // 对应上面的 set 内容
lastChosenWordIndex: null, // 最后一次选中的 index
filePath: '', // 选择的文件路径
fileName: '', // 选择的文件名
targetDict: {}, // 要移动到的码表
showDropdown: false, // 显示移动词条窗口
dropdownFileList: [
// {name: '拼音词库', path: 'pinyin_simp.dict.yaml'}
],
dropdownActiveFileIndex: -1, // 选中的
dropdownActiveGroupIndex: -1, // 选中的分组 ID
config: {}, // 全局配置
// 码表配置
seperatorRead: '\t', // 分隔符
seperatorSave: '\t', // 分隔符
seperatorArray: [
{name: '空格', value: ' ',},
{name: 'Tab', value: '\t',}
], // 分隔符 数组
dictFormatRead: 'wc', // 码表格式默认值
dictFormatSave: 'wc', // 码表格式默认值
dictFormatArray: [
{name: '一码多词', value: 'cww',},
{name: '一码一词', value: 'cw',},
{name: '一词一码', value: 'wc',},
{name: '纯词', value: 'w',}
], // 码表格式数组
filterCharacterLength: 0, // 筛选词条字数默认值
filterCharacterLengthArray: [
{name: '无', value: 0,},
{name: '一', value: 1,},
{name: '二', value: 2,},
{name: '三', value: 3,},
{name: '四', value: 4,},
{name: '五+', value: 5,}
], // 筛选词条字数数组
fileNameSave: '', // 显示的保存文件名
dictMap: null, // main 返回的 dictMap用于解码词条
wordEditing: null, // 正在编辑的词条
}
},
mounted() {
if(IS_IN_DEVELOP) this.filePath = 'C:\\Users\\Administrator\\AppData\\Roaming\\Rime\\origin.txt'
this.heightContent = innerHeight - 47 - 20 - 10 + 3
// 载入主要操作码表文件
ipcRenderer.on('showFileContent', (event, fileName, filePath, fileContent) => {
// 过滤移动到的文件列表,不显示正在显示的这个码表
this.dropdownFileList = this.dropdownFileList.filter(item => item.path !== fileName)
this.filePath = filePath
this.fileName = fileName
this.dict = new DictOther(fileContent, fileName, filePath, this.seperatorRead, this.dictFormatRead)
this.fileNameSave = this.filePathSave()
this.tipNotice('载入完成')
// 载入新码表时,清除 word 保存 code
this.word = ''
this.refreshShowingWords()
// this.search() // 配置项:切换码表是否自动搜索
ipcRenderer.send('loadMainDict') // 请求主码表文件
})
ipcRenderer.on('saveFileSuccess', () => {
this.labelOfSaveBtn = '保存成功'
this.tipNotice('保存成功')
this.$refs.domBtnSave.classList.add('btn-green')
setTimeout(()=>{
this.$refs.domBtnSave.classList.remove('btn-green')
this.labelOfSaveBtn = '保存'
}, 2000)
})
// 由 window 触发获取文件目录的请求,不然无法实现适时的获取到 主进程返回的数据
ipcRenderer.on('ToolWindow:FileList', (event, fileList) => {
log(fileList)
this.dropdownFileList = fileList
})
ipcRenderer.send('ToolWindow:GetFileList')
// 载入目标码表
ipcRenderer.on('ToolWindow:SetTargetDict', (event, filename, filePath, res) => {
this.targetDict = new Dict(res, filename, filePath)
})
// 载入主码表
ipcRenderer.on('setMainDict', (event, filename, res) => {
this.dictMain = new Dict(res, filename)
})
// 配置相关
ipcRenderer.on('ToolWindow:ResponseConfigFile', (event, config) => {
this.config = config
log('窗口载入时获取到的 config 文件:', config)
})
ipcRenderer.send('ToolWindow:RequestConfigFile')
// 配置文件保存后,向主窗口更新配置文件内容
ipcRenderer.on('updateConfigFile', (event, config) => {
this.config = config
})
// 获取并设置字典文件
ipcRenderer.on('setDictMap', (event, fileContent, fileName, filePath) => {
this.dictMap = new DictMap(fileContent, fileName, filePath)
})
ipcRenderer.send('getDictMap')
this.addKeyboardListener()
onresize = ()=>{
this.heightContent = innerHeight - 47 - 20 - 10 + 3
}
},
computed: {
// 当前显示的 words 数量
wordsCount(){
if (this.dict.isGroupMode){
let countCurrent = 0
this.words.forEach(group => {
countCurrent = countCurrent + group.dict.length
})
return countCurrent
} else {
return this.words.length
}
},
// 当前载入的是否为 主 码表
isInMainDict(){
return this.dict.fileName === 'wubi86_jidian.dict.yaml'
}
},
methods: {
tipNotice(msg){
this.tip = msg
setTimeout(()=>{this.tip = ''}, 3000)
},
// 确定编辑词条
confirmEditWord(){
this.wordEditing = null
},
// 生成编辑词条的编码
generateCodeForWordEdit(){
if (this.wordEditing){
this.wordEditing.code = this.dictMap.decodeWord(this.wordEditing.word)
} else {
shakeDomFocus(this.$refs.editInputWord)
}
},
// 编辑词条
editWord(word){
this.wordEditing = word
},
generateCodeForAllWords(){
this.dict.wordsOrigin.forEach(word => {
word.setCode(this.dictMap.decodeWord(word.word))
})
this.refreshShowingWords()
this.tipNotice('编码生成完成')
},
// 生成保存文件的文件名
filePathSave(withFullPath){
let filePathObject = path.parse(this.filePath)
let type = ''
switch (this.dictFormatSave){
case 'cww': type = '一码多词';break;
case 'wc': type = '一词一码';break;
case 'cw': type = '一码一词';break;
case 'w': type = '纯词';break;
}
let seperater = ''
switch (this.seperatorSave){
case ' ': seperater = '空格分隔';break;
case '\t': seperater = 'Tab分隔';break;
}
if (withFullPath){
return path.join(
filePathObject.dir,
filePathObject.name + '_' + type + '_' + seperater + filePathObject.ext
)
} else {
return filePathObject.name + '_' + type + '_' + seperater + filePathObject.ext
}
},
checkRepetitionInOrder(characterMode){
this.words = this.dict.getRepetition(characterMode)
},
// 根据码表的一些参数,重新载入当前文件
reloadCurrentFile(){
ipcRenderer.send('ToolWindow:loadFileContent', this.filePath)
},
// 筛选词条字数
changeFilterWordLength(length){
this.filterCharacterLength = parseInt(length)
this.words = this.dict.getWordsLengthOf(length)
},
checkRepetition(includeCharacter){
this.words = this.dict.getRepetitionWords(includeCharacter)
},
// 载入码表文件
loadDictFile(){
ipcRenderer.send('ToolWindow:chooseDictFile')
},
select(index, wordId, event){
if (event.shiftKey){
if (this.lastChosenWordIndex !== null){
let a,b // 判断大小,调整大小顺序
if (index > this.lastChosenWordIndex){
a = this.lastChosenWordIndex
b = index
} else {
b = this.lastChosenWordIndex
a = index
}
for (let i=a; i<=b; i++){
this.chosenWordIds.add(this.words[i].id)
}
}
this.lastChosenWordIndex = null // shift 选择后最后一个id定义为没有
} else {
if (this.chosenWordIds.has(wordId)){
this.chosenWordIds.delete(wordId)
this.lastChosenWordIndex = null
} else {
this.chosenWordIds.add(wordId)
this.lastChosenWordIndex = index
}
}
this.chosenWordIdArray = [...this.chosenWordIds.values()]
},
// 选择移动到的分组 index
setDropdownActiveGroupIndex(index){
this.dropdownActiveGroupIndex = index
},
// 选择移动到的文件 index
setDropdownActiveIndex(fileIndex){
this.dropdownActiveFileIndex = fileIndex
this.dropdownActiveGroupIndex = -1 // 切换文件列表时,复位分组 fileIndex
// this.dictSecond = {} // 立即清空次码表,分组列表也会立即消失,不会等下面的码表加载完成再清空
ipcRenderer.send('ToolWindow:LoadTargetDict', this.dropdownFileList[fileIndex].path) // 载入当前 index 的文件内容
},
sort(){
let startPoint = new Date().getTime()
this.words.sort((a,b) => a.code < b.code ? -1: 1)
this.tipNotice('排序完成')
log(`排序用时 ${new Date().getTime() - startPoint} ms`)
},
enterKeyPressed(){
switch (this.config.enterKeyBehavior){
case "add":this.addNewWord(); break;
case "search": this.search(); break;
default: break;
}
},
// 通过 code, word 筛选词条
search(){
this.chosenWordIds.clear()
this.chosenWordIdArray = []
this.activeGroupId = -1 // 切到【全部】标签页,展示所有搜索结果
let startPoint = new Date().getTime()
if (this.code || this.word){
this.words = this.dict.wordsOrigin.filter(item => { // 获取包含 code 的记录
switch (this.config.searchMethod){
case "code": return item.code.includes(this.code);
case "phrase": return item.word.includes(this.word);
case "both": return item.code.includes(this.code) && item.word.includes(this.word)
case "any": return item.code.includes(this.code) || item.word.includes(this.word)
}
})
log(`${this.code} ${this.word}: ` ,'搜索出', this.words.length, '条,', '用时: ', new Date().getTime() - startPoint, 'ms')
} else { // 如果 code, word 为空,恢复原有数据
this.refreshShowingWords()
}
},
// 刷新 this.words
refreshShowingWords(){
this.chosenWordIds.clear()
this.chosenWordIdArray = []
this.words = [...this.dict.wordsOrigin]
},
addNewWord(){
if (!this.word){
shakeDomFocus(this.$refs.domInputWord)
} else if (!this.code){
shakeDomFocus(this.$refs.domInputCode)
} else {
this.dict.addWordToDictInOrder(new Word(this.dict.lastIndex++, this.code, this.word))
this.refreshShowingWords()
log(this.code, this.word)
}
},
// 保存内容到文件
saveToFile(dict, isSaveToOriginalFilePath){
if (this.dict.lastIndex >= 1){ // 以 dict 的 lastIndex 作为判断有没有加载码表的依据
if (isSaveToOriginalFilePath){ // 保存到原来文件,针对工具里打开的文件,和词条移动的目标文件
log('保存文件路径: ', dict.filePath)
ipcRenderer.send(
'ToolWindow:SaveFile',
dict.filePath,
dict.toYamlString())
} else { // 保存成新文件,新文件名,只针对工具里打开的码表
log('保存文件路径: ', this.filePathSave(true))
ipcRenderer.send(
'ToolWindow:SaveFile',
this.filePathSave(true),
this.dict.toExportString(this.seperatorSave, this.dictFormatSave))
}
} else {
log('未加载任何码表文件')
}
},
// 选中全部展示的词条
selectAll(){
if(this.wordsCount < 100000){ // 最多同时选择 10w 条数据
if (this.dict.isGroupMode){
this.chosenWordIds.clear()
this.chosenWordIdArray = []
this.words.forEach(group => {
group.forEach( item => {
this.chosenWordIds.add(item.id)
})
})
} else {
this.words.forEach(item => {this.chosenWordIds.add(item.id)})
}
this.chosenWordIdArray = [...this.chosenWordIds.values()]
} else {
// 提示不能同时选择太多内容
this.tip = '不能同时选择大于 1000条 的词条内容'
shakeDom(this.$refs.domBtnSelectAll)
}
},
// 清除内容
resetInputs(){
this.chosenWordIds.clear()
this.chosenWordIdArray = []
this.code = ''
this.word = ''
this.search()
this.tip = ''
},
// 删除词条:单
deleteWord(wordId){
this.chosenWordIds.delete(wordId)
this.chosenWordIdArray = [...this.chosenWordIds.values()]
this.dict.deleteWords(new Set([wordId]))
this.refreshShowingWords()
},
// 删除词条:多
deleteWords(){
this.dict.deleteWords(this.chosenWordIds)
this.refreshShowingWords()
this.chosenWordIds.clear() // 清空选中 wordID
this.chosenWordIdArray = []
},
// 词条位置移动
move(wordId, direction){
if (this.dict.isGroupMode){
// group 时,移动 调换 word 位置,是直接调动的 wordsOrigin 中的word
// 因为 group 时数据为: [{word, word},{word,word}],是 wordGroup 的索引
for(let i=0; i<this.words.length; i++){
let group = this.words[i]
for(let j=0; j<group.dict.length; j++){
if (wordId === group.dict[j].id){
let tempItem = group.dict[j]
if (direction === 'up'){
if (j !==0){
group.dict[j] = group.dict[j - 1]
group.dict[j - 1] = tempItem
return ''
} else {
log('已到顶')
return '已到顶'
}
} else if (direction === 'down'){
if (j+1 !== group.dict.length){
group.dict[j] = group.dict[j + 1]
group.dict[j + 1] = tempItem
return ''
} else {
log('已到底')
return '已到底'
}
}
}
}
}
} else {
// 非分组模式时,调换位置并不能直接改变 wordsOrigin 因为 与 words 已经断开连接
// [word, word]
for(let i=0; i<this.words.length; i++){
if (wordId === this.words[i].id){
let tempItem = this.words[i]
if (direction === 'up'){
if (i !==0) {
this.dict.exchangePositionInOrigin(tempItem, this.words[i-1]) // 调换 wordsOrigin 中的词条位置
this.words[i] = this.words[i - 1]
this.words[i - 1] = tempItem
return ''
} else {
log('已到顶')
return '已到顶'
}
} else if (direction === 'down'){
if (i+1 !== this.words.length) {
this.dict.exchangePositionInOrigin(tempItem, this.words[i+1]) // 调换 wordsOrigin 中的词条位置
this.words[i] = this.words[i + 1]
this.words[i + 1] = tempItem
return ''
} else {
log('已到底')
return '已到底'
}
}
}
}
}
},
// 上移词条
moveUp(id){
this.tip = this.move(id, 'up')
let temp = this.words.pop()
this.words.push(temp)
},
// 下移词条
moveDown(id){
this.tip = this.move(id, 'down')
let temp = this.words.pop()
this.words.push(temp)
},
// 判断是否为第一个元素
isFirstItem(id){
if (this.dict.isGroupMode){ // 分组时的第一个元素
for (let i=0; i<this.words.length; i++) {
for (let j = 0; j < this.words[i].dict.length; j++) {
if (this.words[i].dict[j].id === id){
return j === 0 // 使用 array.forEach() 无法跳出循环
}
}
}
return false
} else {
for (let i = 0; i < this.words.length; i++) {
if (this.words[i].id === id){
return i === 0 // 使用 array.forEach() 无法跳出循环
}
}
return false
}
},
// 判断是否为最后一个元素
isLastItem(id){
if (this.dict.isGroupMode){ // 分组时的最后一个元素
for (let i=0; i<this.words.length; i++) {
for (let j = 0; j < this.words[i].dict.length; j++) {
if (this.words[i].id === id){
return j + 1 === this.words.length
}
}
}
return false
} else {
for (let i = 0; i < this.words.length; i++) {
if (this.words[i].id === id){
return i + 1 === this.words.length
}
}
return false
}
},
// 绑定键盘事件: 键盘上下控制词条上下移动
addKeyboardListener(){
window.addEventListener('keydown', event => {
// log(event)
switch( event.key) {
case 's':
if (event.ctrlKey || event.metaKey){ // metaKey 是 macOS 的 Ctrl
this.saveToFile(this.dict)
event.preventDefault()
} else {
}
break
case 'ArrowDown':
if(this.chosenWordIds.size === 1) { // 只有一个元素时,键盘才起作用
let id = [...this.chosenWordIds.values()][0]
this.moveDown(id)
}
event.preventDefault()
break
case 'ArrowUp':
if(this.chosenWordIds.size === 1) { // 只有一个元素时,键盘才起作用
let id = [...this.chosenWordIds.values()][0]
this.moveUp(id)
}
event.preventDefault()
break
}
})
},
// 将选中的词条移动到指定码表
moveWordsToTargetDict(){
let wordsTransferring = this.dict.wordsOrigin.filter(item => this.chosenWordIds.has(item.id)) // 被转移的 [Word]
log('words transferring', JSON.stringify(wordsTransferring))
this.targetDict.addWordsInOrder(wordsTransferring, this.dropdownActiveGroupIndex)
this.words = [...this.dict.wordsOrigin]
log('after insert:( main:wordOrigin ):\n ', JSON.stringify(this.targetDict.wordsOrigin))
this.deleteWords() // 删除当前词库已移动的词条
this.saveToFile(this.targetDict, true)
this.saveToFile(this.dict, true)
this.tipNotice('移动成功')
this.resetDropList()
},
// 复制 dropdown
resetDropList(){
this.showDropdown = false
this.dropdownActiveFileIndex = -1
this.dropdownActiveGroupIndex = -1
this.targetDict = {} // 清空次码表
},
// 打开当前码表源文件
openCurrentYaml(){
ipcRenderer.send('openFileOutside', this.dict.fileName)
},
},
watch: {
code(newValue){
this.code = newValue.replaceAll(/[^A-Za-z ]/g, '') // input.code 只允许输入字母
},
word(newValue, oldValue){
if (newValue.length < oldValue.length){
// 删除或清空时,不清空编码
} else {
if (this.dictMap){
this.code = this.dictMap.decodeWord(newValue)
}
}
},
seperatorSave(){
this.fileNameSave = this.filePathSave()
},
dictFormatSave(){
this.fileNameSave = this.filePathSave()
},
chosenWordIdArray(newValue){
if (newValue.length === 0){
this.showDropdown = false
}
log('已选词条id: ', JSON.stringify(newValue))
},
showDropdown(newValue){
if (!newValue){ // 窗口关闭时,重置 index
this.resetDropList()
}
},
config: (newValue) => {
switch (newValue.theme){
case "auto":
document.documentElement.classList.add('auto-mode');
document.documentElement.classList.remove('dark-mode');
break;
case "black":
document.documentElement.classList.add('dark-mode');
document.documentElement.classList.remove('auto-mode');
break;
}
}
},
}
new Vue(app)