提交 26f3694e 编写于 作者: B baiy 提交者: ninecents

1.9.3 update

上级 434f7dc5
......@@ -12,13 +12,7 @@
## chrome 安装
- 方法1: 在 [Chrome 应用商店](https://chrome.google.com/webstore/detail/ipfcebkfhpkjeikaammlkcnalknjahmh) 安装
- 方法2: [下载 .crx 安装包](https://github.com/baiy/Ctool/releases/latest)
- 方法3: [百度网盘下载](https://pan.baidu.com/s/1mhWbqWC) 安装方法和方法2一致
> 方法2 / 方法3 不定期维护 仅供网络环境特别恶劣的同学使用
>
> [猛戳这里查看手动安装`.crx`教程](http://www.cnplugins.com/tool/outline-install-crx-file.html)
-[Chrome 应用商店](https://chrome.google.com/webstore/detail/ipfcebkfhpkjeikaammlkcnalknjahmh) 安装
## 微软 Edge 安装
......@@ -30,9 +24,7 @@
## utools 安装
### 插件中心安装
> 插件中心搜索 `ctool`
- [utools](https://u.tools/) 插件中心 搜索 `ctool`
## 开发
......@@ -54,15 +46,15 @@ npm run build -adapter=[chrome|edge|utools|firefox|web]
|加密/解密|`AES`,`DES`,`RC4`,`Rabbit`,`TripleDes`,`sm2`|√|
|BASE64编码|`加密`,`解密`,`支持文件`|√|
|URL编码|`编码`,`解码`|√|
|时间戳|双向转换|√|
|时间戳|`双向转换`,`毫秒`|√|
|二维码|`生成`,`解析`|√|
|条形码|`生成`|√|
|汉字转拼音|`声调`,`首字母`,`分隔符`|√|
|IP地址查询|`运营商`,`城市`|×|
|代码格式化|`js`, `ts`, `html`, `css`, `less`, `scss`, `graphql`, `vue`, `angular`, `markdown`, `json5`, `xml`, `yaml`, `sql`, `压缩`|√|
|Unicode|`双向转换`,`emoji`,`html 实体`,`css 实体`|√|
|进制转换|2-64进制互转|√|
|正则表达式|字符匹配|√|
|进制转换|`2-64进制`|√|
|正则表达式|`匹配`,`查找`,`替换`|√|
|随机字符生成器|`批量`,`特殊字符`|√|
|序列化转换|`json`, `xml`, `yaml`, `phpArray`, `phpSerialize`, `properties`|√|
|文本差异化对比|`行`,`单词`,`css`|√|
......@@ -78,8 +70,9 @@ npm run build -adapter=[chrome|edge|utools|firefox|web]
|jwt解码|`header`, `payload`|√|
|Hex/String转换|`hex to string`, `string to hex`, `十六进制转字符串`, `字符串转十六进制`|√|
|文本处理|`大小写转换`, `中英文标点转换`, `简繁转换`, `替换`, `字符统计`, `行去重`, `添加行号`, `行排序`, `过滤行首尾不可见字符`,`过滤空行`|√|
|html编码|`html编码`|√|
|签名/验签|`签名`,`验签`,`RSA`|√|
|html编码|-|√|
|原码/反码/补码|`生成`|√|
|ARM/HEX|`互转`|×|
## 第三方开源库
......
此差异已折叠。
{
"name": "c-tool",
"version": "1.9.2",
"version": "1.9.3",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 8081",
......@@ -17,14 +17,15 @@
"babel-runtime": "^6.26.0",
"bignumber.js": "^9.0.1",
"code-formatter": "0.0.1",
"codemirror": "^5.63.3",
"codemirror-graphql": "^1.1.0",
"codemirror": "^5.64.0",
"codemirror-graphql": "^1.2.4",
"cosmiconfig": "^7.0.1",
"cron-parser": "^2.16.3",
"cronstrue": "^1.122.0",
"crypto-js": "^3.3.0",
"diff-match-patch": "^1.0.5",
"file": "^0.2.2",
"graphql": "15.5.0",
"graphql": "15.7.2",
"ipinyinjs": "^1.0.0",
"jian_fan": "^1.0.3",
"jimp": "^0.16.1",
......@@ -35,7 +36,7 @@
"json-to-properties": "^1.1.3",
"json5": "^2.2.0",
"jsonlint": "^1.6.3",
"jsrsasign": "^10.4.1",
"jsrsasign": "^10.5.0",
"jsrsasign-util": "^1.0.5",
"jwt-decode": "^3.1.2",
"lodash": "^4.17.21",
......@@ -43,13 +44,13 @@
"moment": "^2.29.1",
"php-array-reader": "^1.3.2",
"phparr": "^0.2.0",
"postcss": "^8.3.11",
"postcss": "^8.4.4",
"postcss-less": "^5.0.0",
"postcss-scss": "^4.0.2",
"prettier": "^2.4.1",
"prettier": "^2.5.0",
"prettier-plugin-sql": "^0.3.0",
"properties-to-json": "^0.1.7",
"qrcode": "^1.4.4",
"qrcode": "^1.5.0",
"qrcode-parser": "^1.2.0",
"query-string": "^6.14.1",
"serialize-php": "^1.1.2",
......
......@@ -70,5 +70,6 @@
"tool_binary": "trueForm/inverse/complement",
"tool_armConverter": "ARM/HEX",
// other
"css_main_category_item_style": "padding: 0 10px"
"css_main_category_item_style": "padding: 0 10px",
"editor_line_wrapping": "Line Wrapping"
}
......@@ -54,15 +54,15 @@
"tool_regex": "正则表达式",
"tool_randomString": "随机字符生成",
"tool_serializeConversion": "序列化转换",
"tool_diffs": "文本差异化对比",
"tool_crontab": "crontab校验",
"tool_websocket": "websocket调试",
"tool_diffs": "文本比对",
"tool_crontab": "crontab",
"tool_websocket": "websocket",
"tool_unit": "单位换算",
"tool_time": "时间计算器",
"tool_uuid": "UUID生成",
"tool_jsonToObject": "JSON转实体类",
"tool_ascii": "ASCII转换",
"tool_variableConversion": "变量名转换",
"tool_ascii": "ASCII",
"tool_variableConversion": "变量名",
"tool_jwt": "JWT解码",
"tool_hexString": "Hex/String",
"tool_text": "文本处理",
......@@ -70,5 +70,6 @@
"tool_binary": "原码/反码/补码",
"tool_armConverter": "ARM/HEX",
// 其他
"css_main_category_item_style": "padding: 0 20px"
"css_main_category_item_style": "padding: 0 20px",
"editor_line_wrapping": "自动换行"
}
......@@ -3,6 +3,7 @@ import clipboard from './clipboard'
import setting from './setting'
import cache from './cache'
import history from './history.js'
import _ from "lodash";
let fixeInputData;
let toolCurrentFeature = "";
......@@ -44,40 +45,107 @@ const model = {
}
}
// 保存历史记录防抖
let debounceSaveToolData = {};
const debounceSaveToolDataMethod = _.debounce(function () {
return history(debounceSaveToolData['tool']).push(debounceSaveToolData['data'])
}, 1000)
const appendData = async function (check = "") {
const result = (data = "") => {
if (data) {
if (
!check
|| (_.isFunction(check) && check(data)) // 函数校验
) {
return data
}
}
return ""
}
return new Promise(async (resolve) => {
try {
// 使用固定输入数据
if (fixeInputData) {
let temp = fixeInputData
fixeInputData = ""
return resolve(result(temp))
}
if (setting.autoReadCopy()) {
let paste = (await clipboard.paste()).trim()
if (paste) {
resolve(result(paste))
}
}
resolve(result())
} catch {
resolve(result())
}
});
}
export const plugin = {
install: function (Vue) {
Vue.prototype.$getToolData = function (clipboardField = '') {
let data = history(model.getCurrentTool()).current()
if (clipboardField) {
if (fixeInputData) { // 使用固定输入数据
data[clipboardField] = fixeInputData
fixeInputData = ""
} else if (setting.autoReadCopy()) {
let paste = clipboard.paste()
if (!data[clipboardField] && paste) {
if (setting.autoReadCopyFilter()){
paste = paste.trim()
}
data[clipboardField] = paste
}
Vue.prototype.$initToolData = function (input = "", inputCheck = "", field = "current", isLoadHistory = true) {
let current = _.cloneDeep(this[field])
let inputHistory = ""
let inputDefault = ""
let inputAppend = ""
// 默认数据
if (input && (input in current) && current[input]) {
inputDefault = current[input];
}
// 历史数据
if (isLoadHistory) {
let history = this.$getToolData()
if (input && (input in history)) {
inputHistory = history[input]
delete history[input]
}
Object.assign(current, this.$getToolData())
}
if (!input) {
this[field] = current
return;
}
return data
// 追加剪贴板等数据
appendData(inputCheck).then((append) => {
inputAppend = append
this[field] = Object.assign(
current,
{
// 历史数据 > 追加数据 > 默认数据
[input]: inputHistory ? inputHistory : (inputAppend ? inputAppend : inputDefault)
}
)
})
}
Vue.prototype.$saveToolData = function (data) {
return history(model.getCurrentTool()).push(data)
Vue.prototype.$getToolData = function () {
return _.cloneDeep(history(model.getCurrentTool()).current())
}
Vue.prototype.$clipboardCopy = function (data) {
if (!setting.autoSaveCopy() || !data) return
clipboard.copy(data,()=>{
this.$Message.success('结果已复制 ^o^')
})
Vue.prototype.$saveToolData = function (data, ignoreDebounce = false) {
if (ignoreDebounce) {
return history(model.getCurrentTool()).push(_.cloneDeep(data))
}
debounceSaveToolData = {tool: model.getCurrentTool(), data: _.cloneDeep(data)}
debounceSaveToolDataMethod()
}
Vue.prototype.$clipboardCopyImages = function (data) {
if (!setting.autoSaveCopy() || !data) return
clipboard.copyImage(data,()=>{
this.$Message.success('图片已复制 ^o^')
})
Vue.prototype.$clipboardCopy = function (data, force = false) {
if ((setting.autoSaveCopy() || force) && data) {
clipboard.copy(data, () => {
this.$Message.success(this.$t('main_ui_copy_text_ok').toString())
})
}
}
Vue.prototype.$clipboardCopyImages = function (data, force = false) {
if ((setting.autoSaveCopy() || force) && data) {
clipboard.copyImage(data, () => {
this.$Message.success(this.$t('main_ui_copy_image_ok').toString())
})
}
}
},
}
......
<template>
<div>
<div style="border: 1px solid #dcdee2; border-radius: 4px">
<code-editor ref="editor" v-model="current.content" :auto-height="220" :language="this.current.lang"></code-editor>
</div>
<option-block>
<heightResize :append="['.page-option-block']">
<code-editor ref="editor" showLineWrappingSet="no" v-model="current.content" :language="this.current.lang"></code-editor>
</heightResize>
<option-block class="page-option-block">
<FormItem>
<ButtonGroup>
<Button
......@@ -16,53 +16,63 @@
</ButtonGroup>
</FormItem>
<FormItem>
<Select placeholder="更多语言" @on-change="(value)=>{handle(value)}">
<Select :placeholder="$t('code_more')" @on-change="(value)=>{handle(value)}">
<Option v-for="item in lang" :value="item" :key="item">{{ item }}</Option>
</Select>
</FormItem>
<FormItem>
<Select placeholder="代码缩进" v-model="current.tab">
<Option :value="2">缩进 Tab 2</Option>
<Option :value="4">缩进 Tab 4</Option>
<Option :value="6">缩进 Tab 6</Option>
<Option :value="8">缩进 Tab 8</Option>
<Select :placeholder="$t('code_indent')" v-model="current.tab">
<Option :value="2">{{ $t('code_indent_width',[2]) }}</Option>
<Option :value="4">{{ $t('code_indent_width',[4]) }}</Option>
<Option :value="6">{{ $t('code_indent_width',[6]) }}</Option>
<Option :value="8">{{ $t('code_indent_width',[8]) }}</Option>
</Select>
</FormItem>
<FormItem>
<Checkbox v-model="current.isCompress">{{ $t('code_compress') }}</Checkbox>
</FormItem>
</option-block>
</div>
</template>
<script>
import _ from "lodash";
import codeEditor from "./components/codeEditor";
import heightResize from "./components/heightResize";
export default {
components: {
codeEditor,
heightResize
},
computed:{
buttonLang(){
let data = _.slice(this.lang,0,8)
if (this.current.lang && !data.includes(this.current.lang)){
computed: {
buttonLang() {
let data = _.slice(this.lang, 0, 7)
if (this.current.lang && !data.includes(this.current.lang)) {
data.push(this.current.lang)
}
return data
}
},
created() {
this.current = Object.assign(this.current, this.$getToolData("content"))
this.$initToolData('content')
},
methods: {
handle(language) {
if (this.current.content) {
try {
this.current.lang = language;
this.$refs.editor.format(language,{tab:this.current.tab});
if (!this.current.isCompress) {
let option = {tab: this.current.tab}
this.$refs.editor.format(language, option);
} else {
this.$refs.editor.compress(language);
}
this.$saveToolData(this.current);
return this.$Message.success('格式化完成');
}
catch (e) {
return this.$Message.success(this.$t('code_complete').toString());
} catch (e) {
console.log(e)
return this.$Modal.error({
title:"格式化错误",
content:`${e.message}`
title: this.$t('code_error_prompt').toString(),
content: `${e.message}`
});
}
}
......@@ -72,19 +82,20 @@ export default {
return {
current: {
content: "",
isCompress: false,
lang: "",
tab:4,
tab: 4,
},
lang: [
"html",
"js",
"css",
"xml",
"json",
"sql",
"yaml",
"php",
"xml",
"sql",
"javascript",
"css",
"typescript",
"ts",
"java",
"scss",
"less",
......
<template>
<div ref="container" class="code-editor" :style="`height:${containerHeight};width:${width}`"></div>
<input-block right="5px" bottom="5px" :style="style">
<div ref="container" class="code-editor" :style="`height:100%;width:${width}`"></div>
<template slot="extra">
<Checkbox v-if="showLineWrappingSet !== 'null'" v-model="lineWrapping">{{ $t('main_editor_line_wrapping') }}</Checkbox>
</template>
</input-block>
</template>
<script>
import formatter from "../library/formatter";
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
const allowFormatterLanguage = {
html: "html",
typescript: "ts",
javascript: "js",
json: "json",
graphql: "graphql",
java: "java",
markdown: "markdown",
php: "php",
css: "css",
scss: "scss",
less: "less",
sql: "sql",
xml: "xml",
yaml: "yaml",
vue: "vue",
angular: "angular",
}
import {format} from "../library/formatter";
import {create} from "../library/editor";
export default {
name: 'codeEditor',
......@@ -34,97 +20,109 @@ export default {
type: String,
default: ""
},
autoHeight: {
type: Number,
default: 0
enableBorder: {
type: Boolean,
default: true
},
theme: {
placeholder: {
type: String,
default: 'vs'
default: ""
},
roundedSelection: {
type: Boolean,
default: true
showLineWrappingSet: {
type: String,
default: "null"
},
height: {
type: String,
default: "350px"
default: "100%"
},
hideLineNumbers: {
type: Boolean,
default: false
},
width: {
type: String,
default: "100%"
},
},
computed: {
style() {
let css = [`height:${this.height}`];
if (this.enableBorder) {
css.push("border: 1px solid #dcdee2")
css.push("border-radius: 4px")
}
return css.join(";")
}
},
watch: {
value(newValue) {
if (this.editor !== null && this.editor.getValue() !== newValue) {
this.editor.pushUndoStop();
this.editor.getModel().pushEditOperations(
[],
[
{
range: this.editor.getModel().getFullModelRange(),
text: newValue,
},
]
);
this.editor.pushUndoStop();
this.editor.setValue(newValue)
}
},
language(newValue) {
if (this.editor !== null) {
monaco.editor.setModelLanguage(this.editor.getModel(), newValue)
this.editor.customSetEditorLanguage(newValue);
}
},
theme(newValue) {
lineWrapping(newValue) {
if (this.editor !== null) {
monaco.editor.setTheme(newValue)
this.editor.setOption("lineWrapping", newValue);
}
}
},
created() {
if (this.autoHeight > 0) {
this.containerHeight = (window.innerHeight - this.autoHeight) + "px"
} else {
this.containerHeight = this.height
}
},
mounted() {
this.initEditor()
},
data() {
return {
editor: null,
containerHeight: ""
lineWrapping: true,
}
},
created() {
if (this.showLineWrappingSet !== 'null') {
this.lineWrapping = this.showLineWrappingSet === 'yes'
}
},
methods: {
initEditor() {
this.$refs.container.innerHTML = ''
this.editor = monaco.editor.create(this.$refs.container, {
value: this.value,
language: this.language,
theme: this.theme,
roundedSelection: this.roundedSelection,
automaticLayout: true
})
this.editor.onDidChangeModelContent(() => {
if (this.value !== this.editor.getValue()){
this.$emit('input', this.editor.getValue())
this.editor = create(
this.$refs.container,
this.language,
{
lineNumbers: !this.hideLineNumbers,
lineWrapping: this.lineWrapping,
placeholder: this.placeholder
}
);
this.editor.setValue(this.value)
this.editor.on('change', editor => {
if (this.value !== editor.getValue()) {
this.$emit('input', editor.getValue())
}
})
},
/** @return monaco.editor.IStandaloneCodeEditor*/
getEditor() {
return this.editor
},
format(lang,option = {}) {
if (!(lang in allowFormatterLanguage)){
throw new Error("当前代码无法格式化");
}
this.$emit('input', formatter(this.editor.getValue(), allowFormatterLanguage[lang],option))
format(lang, option = {}) {
this.$emit('input', format(this.editor.getValue(), lang, false, option))
},
compress(lang) {
this.$emit('input', format(this.editor.getValue(), lang, true))
}
}
};
</script>
<style>
.CodeMirror {
height: 100%;
}
.CodeMirror pre.CodeMirror-placeholder {
color: #999;
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册