const clipboard = require(Editor.url('packages://console-pro/node_modules/clipboard/dist/clipboard.js')) const axios = require(Editor.url('packages://console-pro/node_modules/axios/dist/axios.js')) const packageJSON = require(Editor.url('packages://console-pro/package.json')) const childProcess = require('child_process') const path = require('path') const fs = require('fs') const os = require('os') const translate = (key) => Editor.T(`${packageJSON.name}.${key}`) var vm = null // panel/index.js, this filename needs to match the one registered in package.json Editor.Panel.extend({ // css style for panel style: fs.readFileSync(Editor.url('packages://console-pro/static/style/default/index.css', 'utf8')), // html template for panel template: fs.readFileSync(Editor.url('packages://console-pro/static/template/default/index.html', 'utf8')), // element and variable binding $: { app: '#app', logDetail: '#log-detail' }, close() { }, // method executed when template and styles are successfully loaded and initialized ready () { vm = new window.Vue({ el: this.shadowRoot, data() { return { openSettingsI18n: translate('openSettings'), clearLogI18n: translate('clearLog'), openLogI18n: translate('openLog'), searchPlaceholderI18n: translate('searchPlaceholder'), iconI18n: translate('icon'), timeI18n: translate('time'), typeI18n: translate('type'), contentI18n: translate('content'), copyI18n: translate('copy'), deleteI18n: translate('delete'), expandI18n: translate('expand'), collapseI18n: translate('collapse'), developI18n: translate('develop'), backI18n: translate('back'), currentPage: 'log', settingsImgPath: Editor.url('packages://console-pro/static/images/settings.png'), clearImgPath: Editor.url('packages://console-pro/static/images/clear.png'), openLogImgPath: Editor.url('packages://console-pro/static/images/log.png'), searchImgPath: Editor.url('packages://console-pro/static/images/search.png'), matchCaseImgPath: Editor.url('packages://console-pro/static/images/match-case.png'), matchWholeImgPath: Editor.url('packages://console-pro/static/images/match-whole.png'), matchRegImgPath: Editor.url('packages://console-pro/static/images/match-reg.png'), logNumImgPath: Editor.url('packages://console-pro/static/images/log-color.png'), infoNumImgPath: Editor.url('packages://console-pro/static/images/info-color.png'), warnNumImgPath: Editor.url('packages://console-pro/static/images/warn-color.png'), errorNumImgPath: Editor.url('packages://console-pro/static/images/error-color.png'), copyImgPath: Editor.url('packages://console-pro/static/images/copy.png'), deleteImgPath: Editor.url('packages://console-pro/static/images/delete.png'), expandImgPath: Editor.url('packages://console-pro/static/images/expand.png'), collapseImgPath: Editor.url('packages://console-pro/static/images/collapse.png'), isMatchCase: false, isMatchWhole: false, isMatchReg: false, matchCaseBtnClass: 'transparent', matchWholeBtnClass: 'transparent', matchRegBtnClass: 'transparent', logNum: 0, infoNum: 0, warnNum: 0, errorNum: 0, isLogTypeShown: true, isInfoTypeShown: true, isWarnTypeShown: true, isErrorTypeShown: true, currentLogDataArray: [], searchResultArray: [], keyword: '', isClearLogOnPreview: false, isCurrentItemExpanded: false, currentLogIndex: 0, isSearching: false, logDetailHTML: null, menuHTML: null } }, created() { // 如果不需要更新提示,注释这行代码即可 // this.checkUpdate() }, computed: { currentLogDataArrayComputed() { return this.currentLogDataArray } }, methods: { checkUpdate() { // 检查是否有更新 axios.get('https://la-vie.gitee.io/console-pro2x/package.json', {headers: {'Cache-Control': 'no-cache'}}) .then(function(response) { let remoteVersion = response.data.version; if (packageJSON.version != remoteVersion) { Editor.warn(`[v${remoteVersion}] ${translate('updateWarn')}`); } }); }, storeELements(event) { // v-el和v-ref都获取不到,只能通过这种方式获取先 // 获取id为log-detail的元素 this.logDetailHTML = event.currentTarget // 获取右键菜单元素 this.menuHTML = event.currentTarget.parentElement.parentElement.getElementsByClassName('menu')[0] }, back() { this.currentPage = 'log' }, setClearOnPreview() { this.isClearLogOnPreview = !this.isClearLogOnPreview }, escape(str) { return str.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&') }, search(keyword) { // 关键词搜索 this.keyword = keyword // 没有关键词则直接返回 if (!keyword.length) { this.isSearching = false return } // 构造正则表达式 this.isSearching = true this.searchResultArray = [] let matchCaseRegPart = 'i' let matchWholeRegPart1 = '' let matchWholeRegPart2 = '' let regStr = keyword if (!this.isMatchReg) { regStr = this.escape(regStr) } if (this.isMatchCase) { matchCaseRegPart = '' } if (this.isMatchWhole) { matchWholeRegPart1 = '\\b' matchWholeRegPart2 = '\\b' } regStr = `${matchWholeRegPart1}${regStr}${matchWholeRegPart2}` let regExp = new RegExp(regStr, matchCaseRegPart+'g') // 将符合条件的日志放入searchResultArray中 for (let i=0; i -1) { this.searchResultArray.push(this.currentLogDataArray[i]) } } }, showContextMenu(event, index) { // 显示右键菜单 event.preventDefault() let logDetailLeft = this.logDetailHTML.getBoundingClientRect().left let logDetailTop = this.logDetailHTML.getBoundingClientRect().top let x = event.clientX - logDetailLeft let y = event.clientY - logDetailTop if (y > this.logDetailHTML.clientHeight/2) { this.menuHTML.style.top = y - 30 + 'px' } else { this.menuHTML.style.top = y + 30 + 'px' } this.menuHTML.style.left = x + 10+ 'px' this.currentLogIndex = index this.isCurrentItemExpanded = this.currentLogDataArray[index].isExpanded }, hideContextMenu(event) { if (this.menuHTML) { this.menuHTML.style.top = '-1000px' } }, copyLog(index) { clipboard.copy(this.currentLogDataArray[index].message) }, deleteLog(index) { let logType = this.currentLogDataArray[index].type this.currentLogDataArray.splice(index, 1) if (logType == 'log') { this.logNum -= 1 } else if (logType == 'info') { this.infoNum -= 1 } else if (logType == 'warn') { this.warnNum -= 1 } else if (logType == 'error') { this.errorNum -= 1 } }, truncate(item) { // 截断 // 若处于展开状态,则不截断 if (item.isExpanded) { return item.message } // 若大于100个字符,则截断 if (item.message.length > 100) { return item.message.substring(0, 100) + '...' } return item.message }, clearLog() { // 清空当前显示的日志 Editor.Ipc.sendToMain('console-pro:clear-log') this.currentLogDataArray = [] this.previousLogDataArray = JSON.stringify([]) this.logNum = 0 this.infoNum = 0 this.warnNum = 0 this.errorNum = 0 }, openSettings() { // 进入到设置页面 this.currentPage = 'settings' }, openLog() { // 打开日志文件 let logFilePath = path.join(os.homedir(), '.CocosCreator/logs/CocosCreator.log') if (fs.existsSync(logFilePath)) { if (os.type() == "Windows_NT") { childProcess.exec(`explorer.exe ${logFilePath}`) } else if (os.type() == "Darwin") { childProcess.exec(`open ${logFilePath}`) } } else { Editor.Dialog.messageBox({ message: translate('noLogFile'), buttons: ['Ok'], title: 'Cocos Console Pro', }) } }, onMatchCaseBtnClicked() { // 当点击了大小写匹配按钮 this.isMatchCase = !this.isMatchCase this.matchCaseBtnClass = this.isMatchCase ? 'blue transparent' : 'transparent' this.search(this.keyword) }, onMatchWholeBtnClicked() { // 当点击了全字符匹配按钮 this.isMatchWhole = !this.isMatchWhole this.matchWholeBtnClass = this.isMatchWhole ? 'blue transparent' : 'transparent' this.search(this.keyword) }, onMatchRegBtnClicked() { // 当点击了正则匹配按钮 this.isMatchReg = !this.isMatchReg this.matchRegBtnClass = this.isMatchReg ? 'blue transparent' : 'transparent' this.search(this.keyword) }, showHideCertainTypeOfLog(logType) { // 当点击了右上角某个类型日志,可显示或隐藏对应类型的所有日志 if (logType == 'log') { this.isLogTypeShown = !this.isLogTypeShown this.logNumImgPath = this.isLogTypeShown ? Editor.url('packages://console-pro/static/images/log-color.png') : Editor.url('packages://console-pro/static/images/log-gray.png') for (let i=0; i{ if (this.isScrollAtBottom()) { this.logDetailHTML.scrollTop = Number.MAX_SAFE_INTEGER } }) }, expandLog(index) { // 展开日志 this.currentLogDataArray[index].isExpanded = !this.currentLogDataArray[index].isExpanded }, logTypeTologPath(logType) { // 将日志类型转换为日志图标 return Editor.url(`packages://console-pro/static/images/${logType}-color.png`) }, timeStampToDateTime(timestamp) { // 将时间戳转换为日期时间 let date = new Date(timestamp) let year = date.getFullYear() let month = date.getMonth() + 1 let day = date.getDate() let hour = date.getHours() let minute = date.getMinutes() let second = date.getSeconds() // 小于10的话,前面补齐'0' let monthStr = month < 10 ? '0'+month : month.toString() let dayStr = day < 10 ? '0'+day : day.toString() let hourStr = hour < 10 ? '0'+hour : hour.toString() let minuteStr = minute < 10 ? '0'+minute : minute.toString() let secondStr = second < 10 ? '0'+second : second.toString() return `${year}-${monthStr}-${dayStr} ${hourStr}:${minuteStr}:${secondStr}` }, isScrollAtBottom() { // 判断滚动条是否在底部 if (!this.logDetailHTML) { return false } let clientHeight = this.logDetailHTML.clientHeight let scrollTop = this.logDetailHTML.scrollTop let scrollHeight = this.logDetailHTML.scrollHeight if (clientHeight + scrollTop >= scrollHeight * 0.98) { return true } return false }, updateLog(logType, msg) { let item = { 'type': logType, 'message': msg, 'time': new Date().valueOf(), 'isExpanded': false } if (logType == 'log') { this.logNum += 1 item.isShown = this.isLogTypeShown } else if (logType == 'info') { this.infoNum += 1 item.isShown = this.isInfoTypeShown } else if (logType == 'warn') { this.warnNum += 1 item.isShown = this.isWarnTypeShown } else if (logType == 'error') { this.errorNum += 1 item.isShown = this.isErrorTypeShown } this.currentLogDataArray.push(item) // 滑动条下滑 this.$nextTick(()=>{ if (this.isScrollAtBottom()) { this.logDetailHTML.scrollTop = Number.MAX_SAFE_INTEGER } }) } } }) }, // register your ipc messages here messages: { 'editor:console-log': (event, msg)=>{ vm.updateLog('log', msg) }, 'editor:console-success': (event, msg)=>{ vm.updateLog('log', msg) }, 'editor:console-failed': (event, msg)=>{ vm.updateLog('error', msg) }, 'editor:console-info': (event, msg)=>{ vm.updateLog('info', msg) }, 'editor:console-warn': (event, msg)=>{ vm.updateLog('warn', msg) }, 'editor:console-error': (event, msg)=>{ vm.updateLog('error', msg) }, 'scene:play-on-device': (event)=>{ if (vm.isClearLogOnPreview) { vm.clearLog() } }, } });