mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-06 16:16:42 +08:00
feat: implement custom Jinja2 syntax highlighting for rename templates and notification templates using VAceEditor
This commit is contained in:
+484
-1
@@ -44,6 +44,488 @@ import snippertsIniUrl from 'ace-builds/src-noconflict/snippets/ini?url'
|
|||||||
|
|
||||||
import 'ace-builds/src-noconflict/ext-language_tools'
|
import 'ace-builds/src-noconflict/ext-language_tools'
|
||||||
|
|
||||||
|
const aceModule = ace as typeof ace & {
|
||||||
|
define?: (moduleName: string, deps: string[], payload: (...args: any[]) => void) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerJinja2Mode() {
|
||||||
|
aceModule.define?.(
|
||||||
|
'ace/mode/jinja2_highlight_rules',
|
||||||
|
['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
|
||||||
|
(require: any, exports: any) => {
|
||||||
|
const oop = require('../lib/oop')
|
||||||
|
const TextHighlightRules = require('./text_highlight_rules').TextHighlightRules
|
||||||
|
|
||||||
|
const Jinja2HighlightRules = function (this: any) {
|
||||||
|
const tags =
|
||||||
|
'autoescape|block|call|do|elif|else|endautoescape|endblock|endcall|endfilter|endfor|endif|endmacro|endraw|endset|endtrans|endwith|extends|filter|for|from|if|import|include|macro|raw|set|trans|with'
|
||||||
|
const filters =
|
||||||
|
'abs|attr|batch|capitalize|center|count|d|default|dictsort|e|escape|filesizeformat|first|float|forceescape|format|groupby|indent|int|items|join|last|length|list|lower|map|max|min|pprint|random|reject|rejectattr|replace|reverse|round|safe|select|selectattr|slice|sort|string|striptags|sum|title|tojson|trim|truncate|unique|upper|urlencode|urlize|wordcount|wordwrap|xmlattr'
|
||||||
|
const functions = 'cycler|dict|joiner|lipsum|namespace|range'
|
||||||
|
const tests =
|
||||||
|
'boolean|defined|divisibleby|eq|escaped|even|false|filter|float|ge|gt|in|integer|iterable|le|lower|lt|mapping|ne|none|number|odd|sameas|sequence|string|test|true|undefined|upper'
|
||||||
|
const operators = 'and|in|is|not|or'
|
||||||
|
const contextVariables =
|
||||||
|
'title|en_title|original_title|season|season_fmt|year|title_year|type|category|vote_average|poster|backdrop|season_year|actors|overview|tmdbid|imdbid|doubanid|episode_title|episode_date|original_name|name|en_name|episode|season_episode|part|customization|fps|resourceType|effect|edition|videoFormat|resource_term|releaseGroup|videoCodec|audioCodec|webSource|torrent_title|pubdate|freedate|seeders|volume_factor|hit_and_run|labels|description|site_name|size|transfer_type|file_count|total_size|err_msg|fileExt|__meta__|__mediainfo__|__torrentinfo__|__transferinfo__|__episodes_info__'
|
||||||
|
|
||||||
|
const keywordMapper = this.createKeywordMapper(
|
||||||
|
{
|
||||||
|
'keyword.control.jinja2': tags,
|
||||||
|
'keyword.operator.jinja2': operators,
|
||||||
|
'support.function.jinja2': [filters, functions, tests].join('|'),
|
||||||
|
'constant.language.jinja2': 'false|False|none|None|null|true|True',
|
||||||
|
},
|
||||||
|
'identifier',
|
||||||
|
)
|
||||||
|
|
||||||
|
const jinjaExpressionRules = [
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: "'",
|
||||||
|
push: 'jinja2-qstring',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: '"',
|
||||||
|
push: 'jinja2-qqstring',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.numeric',
|
||||||
|
regex: /[+-]?(?:0[xX][0-9a-fA-F]+|\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: ['keyword.operator.other.jinja2', 'text', 'support.function.jinja2'],
|
||||||
|
regex: `(\\|)(\\s*)(${filters})\\b`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: ['keyword.operator.jinja2', 'text', 'support.function.jinja2'],
|
||||||
|
regex: `(\\bis\\b)(\\s*)(${tests})\\b`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: ['support.function.jinja2', 'text', 'paren.lparen'],
|
||||||
|
regex: `\\b(${functions})(\\s*)(\\()`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'variable.language.jinja2',
|
||||||
|
regex: `\\b(?:${contextVariables})\\b`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: keywordMapper,
|
||||||
|
regex: /[a-zA-Z_$][a-zA-Z0-9_$]*\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.assignment.jinja2',
|
||||||
|
regex: /=|~/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.comparison.jinja2',
|
||||||
|
regex: /==|!=|<=|>=|<|>/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.arithmetic.jinja2',
|
||||||
|
regex: /\+|-|\/\/|\/|%|\*\*|\*/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.other.jinja2',
|
||||||
|
regex: /\.{2}|\||:/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'punctuation.operator.jinja2',
|
||||||
|
regex: /[.,;?]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'paren.lparen',
|
||||||
|
regex: /[\[({]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'paren.rparen',
|
||||||
|
regex: /[\])}]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'text',
|
||||||
|
regex: /\s+/,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
this.$rules = {
|
||||||
|
start: [
|
||||||
|
{
|
||||||
|
token: 'comment.block.jinja2',
|
||||||
|
regex: /\{#-?/,
|
||||||
|
push: 'jinja2-comment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.language.jinja2',
|
||||||
|
regex: /\{\{-?/,
|
||||||
|
push: 'jinja2-expression',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.control.jinja2',
|
||||||
|
regex: /\{%-?/,
|
||||||
|
push: 'jinja2-statement',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'jinja2-comment': [
|
||||||
|
{
|
||||||
|
token: 'comment.block.jinja2',
|
||||||
|
regex: /-?#\}/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'comment.block.jinja2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'jinja2-expression': [
|
||||||
|
{
|
||||||
|
token: 'constant.language.jinja2',
|
||||||
|
regex: /-?\}\}/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
...jinjaExpressionRules,
|
||||||
|
],
|
||||||
|
'jinja2-statement': [
|
||||||
|
{
|
||||||
|
token: 'keyword.control.jinja2',
|
||||||
|
regex: /-?%\}/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
...jinjaExpressionRules,
|
||||||
|
],
|
||||||
|
'jinja2-qqstring': [
|
||||||
|
{
|
||||||
|
token: 'constant.language.escape',
|
||||||
|
regex: /\\[\\"ntr]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: '"',
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'jinja2-qstring': [
|
||||||
|
{
|
||||||
|
token: 'constant.language.escape',
|
||||||
|
regex: /\\[\\'ntr]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: "'",
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.normalizeRules()
|
||||||
|
}
|
||||||
|
|
||||||
|
oop.inherits(Jinja2HighlightRules, TextHighlightRules)
|
||||||
|
exports.Jinja2HighlightRules = Jinja2HighlightRules
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
aceModule.define?.(
|
||||||
|
'ace/mode/jinja2',
|
||||||
|
['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text', 'ace/mode/jinja2_highlight_rules'],
|
||||||
|
(require: any, exports: any) => {
|
||||||
|
const oop = require('../lib/oop')
|
||||||
|
const TextMode = require('./text').Mode
|
||||||
|
const Jinja2HighlightRules = require('./jinja2_highlight_rules').Jinja2HighlightRules
|
||||||
|
|
||||||
|
const Mode = function (this: any) {
|
||||||
|
TextMode.call(this)
|
||||||
|
this.HighlightRules = Jinja2HighlightRules
|
||||||
|
}
|
||||||
|
|
||||||
|
oop.inherits(Mode, TextMode)
|
||||||
|
|
||||||
|
;(function (this: any) {
|
||||||
|
this.$id = 'ace/mode/jinja2'
|
||||||
|
this.blockComment = { start: '{#', end: '#}' }
|
||||||
|
}).call(Mode.prototype)
|
||||||
|
|
||||||
|
exports.Mode = Mode
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
aceModule.define?.('ace/snippets/jinja2', ['require', 'exports', 'module'], (_require: any, exports: any) => {
|
||||||
|
exports.snippetText =
|
||||||
|
'snippet if\n\t{% if ${1:condition} %}\n\t\t${0}\n\t{% endif %}\n' +
|
||||||
|
'snippet for\n\t{% for ${1:item} in ${2:items} %}\n\t\t${0}\n\t{% endfor %}\n' +
|
||||||
|
'snippet var\n\t{{ ${1:name} }}\n'
|
||||||
|
exports.scope = 'jinja2'
|
||||||
|
})
|
||||||
|
|
||||||
|
aceModule.define?.(
|
||||||
|
'ace/mode/jinja2_json_highlight_rules',
|
||||||
|
['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
|
||||||
|
(require: any, exports: any) => {
|
||||||
|
const oop = require('../lib/oop')
|
||||||
|
const TextHighlightRules = require('./text_highlight_rules').TextHighlightRules
|
||||||
|
|
||||||
|
const Jinja2JsonHighlightRules = function (this: any) {
|
||||||
|
const tags =
|
||||||
|
'autoescape|block|call|do|elif|else|endautoescape|endblock|endcall|endfilter|endfor|endif|endmacro|endraw|endset|endtrans|endwith|extends|filter|for|from|if|import|include|macro|raw|set|trans|with'
|
||||||
|
const filters =
|
||||||
|
'abs|attr|batch|capitalize|center|count|d|default|dictsort|e|escape|filesizeformat|first|float|forceescape|format|groupby|indent|int|items|join|last|length|list|lower|map|max|min|pprint|random|reject|rejectattr|replace|reverse|round|safe|select|selectattr|slice|sort|string|striptags|sum|title|tojson|trim|truncate|unique|upper|urlencode|urlize|wordcount|wordwrap|xmlattr'
|
||||||
|
const functions = 'cycler|dict|joiner|lipsum|namespace|range'
|
||||||
|
const tests =
|
||||||
|
'boolean|defined|divisibleby|eq|escaped|even|false|filter|float|ge|gt|in|integer|iterable|le|lower|lt|mapping|ne|none|number|odd|sameas|sequence|string|test|true|undefined|upper'
|
||||||
|
const operators = 'and|in|is|not|or'
|
||||||
|
const contextVariables =
|
||||||
|
'title|en_title|original_title|season|season_fmt|year|title_year|type|category|vote_average|poster|backdrop|season_year|actors|overview|tmdbid|imdbid|doubanid|episode_title|episode_date|original_name|name|en_name|episode|season_episode|part|customization|fps|resourceType|effect|edition|videoFormat|resource_term|releaseGroup|videoCodec|audioCodec|webSource|torrent_title|pubdate|freedate|seeders|volume_factor|hit_and_run|labels|description|site_name|size|transfer_type|file_count|total_size|err_msg|fileExt|__meta__|__mediainfo__|__torrentinfo__|__transferinfo__|__episodes_info__'
|
||||||
|
|
||||||
|
const keywordMapper = this.createKeywordMapper(
|
||||||
|
{
|
||||||
|
'keyword.control.jinja2': tags,
|
||||||
|
'keyword.operator.jinja2': operators,
|
||||||
|
'support.function.jinja2': [filters, functions, tests].join('|'),
|
||||||
|
'constant.language.jinja2': 'false|False|none|None|null|true|True',
|
||||||
|
},
|
||||||
|
'identifier',
|
||||||
|
)
|
||||||
|
|
||||||
|
const jinjaRules = [
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: "'",
|
||||||
|
push: 'jinja2-json-qstring',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.language.escape',
|
||||||
|
regex: /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.numeric',
|
||||||
|
regex: /[+-]?(?:0[xX][0-9a-fA-F]+|\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: ['keyword.operator.other.jinja2', 'text', 'support.function.jinja2'],
|
||||||
|
regex: `(\\|)(\\s*)(${filters})\\b`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: ['keyword.operator.jinja2', 'text', 'support.function.jinja2'],
|
||||||
|
regex: `(\\bis\\b)(\\s*)(${tests})\\b`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: ['support.function.jinja2', 'text', 'paren.lparen'],
|
||||||
|
regex: `\\b(${functions})(\\s*)(\\()`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'variable.language.jinja2',
|
||||||
|
regex: `\\b(?:${contextVariables})\\b`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: keywordMapper,
|
||||||
|
regex: /[a-zA-Z_$][a-zA-Z0-9_$]*\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.assignment.jinja2',
|
||||||
|
regex: /=|~/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.comparison.jinja2',
|
||||||
|
regex: /==|!=|<=|>=|<|>/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.arithmetic.jinja2',
|
||||||
|
regex: /\+|-|\/\/|\/|%|\*\*|\*/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.operator.other.jinja2',
|
||||||
|
regex: /\.{2}|\||:/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'punctuation.operator.jinja2',
|
||||||
|
regex: /[.,;?]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'paren.lparen',
|
||||||
|
regex: /[\[({]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'paren.rparen',
|
||||||
|
regex: /[\])}]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'text',
|
||||||
|
regex: /\s+/,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
this.$rules = {
|
||||||
|
start: [
|
||||||
|
{
|
||||||
|
token: 'variable',
|
||||||
|
regex: /"(?:(?:\\.)|(?:[^"\\]))*?"\s*(?=:)/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: '"',
|
||||||
|
push: 'json-string',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.numeric',
|
||||||
|
regex: /0[xX][0-9a-fA-F]+\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.numeric',
|
||||||
|
regex: /[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.language.boolean',
|
||||||
|
regex: /(?:true|false|null)\b/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'text',
|
||||||
|
regex: /['](?:(?:\\.)|(?:[^'\\]))*?[']/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'comment',
|
||||||
|
regex: /\/\/.*$/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'comment.start',
|
||||||
|
regex: /\/\*/,
|
||||||
|
push: 'comment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'paren.lparen',
|
||||||
|
regex: /[[({]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'paren.rparen',
|
||||||
|
regex: /[\])}]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'punctuation.operator',
|
||||||
|
regex: /[:,]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'text',
|
||||||
|
regex: /\s+/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'json-string': [
|
||||||
|
{
|
||||||
|
token: 'constant.language.escape',
|
||||||
|
regex: /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'comment.block.jinja2',
|
||||||
|
regex: /\{#-?/,
|
||||||
|
push: 'jinja2-json-comment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'constant.language.jinja2',
|
||||||
|
regex: /\{\{-?/,
|
||||||
|
push: 'jinja2-json-expression',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'keyword.control.jinja2',
|
||||||
|
regex: /\{%-?/,
|
||||||
|
push: 'jinja2-json-statement',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: /"|$/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
comment: [
|
||||||
|
{
|
||||||
|
token: 'comment.end',
|
||||||
|
regex: /\*\//,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'comment',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'jinja2-json-comment': [
|
||||||
|
{
|
||||||
|
token: 'comment.block.jinja2',
|
||||||
|
regex: /-?#\}/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'comment.block.jinja2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'jinja2-json-expression': [
|
||||||
|
{
|
||||||
|
token: 'constant.language.jinja2',
|
||||||
|
regex: /-?\}\}/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
...jinjaRules,
|
||||||
|
],
|
||||||
|
'jinja2-json-statement': [
|
||||||
|
{
|
||||||
|
token: 'keyword.control.jinja2',
|
||||||
|
regex: /-?%\}/,
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
...jinjaRules,
|
||||||
|
],
|
||||||
|
'jinja2-json-qstring': [
|
||||||
|
{
|
||||||
|
token: 'constant.language.escape',
|
||||||
|
regex: /\\[\\'ntr]/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: 'string',
|
||||||
|
regex: "'",
|
||||||
|
next: 'pop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
defaultToken: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.normalizeRules()
|
||||||
|
}
|
||||||
|
|
||||||
|
oop.inherits(Jinja2JsonHighlightRules, TextHighlightRules)
|
||||||
|
exports.Jinja2JsonHighlightRules = Jinja2JsonHighlightRules
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
aceModule.define?.(
|
||||||
|
'ace/mode/jinja2_json',
|
||||||
|
['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text', 'ace/mode/jinja2_json_highlight_rules'],
|
||||||
|
(require: any, exports: any) => {
|
||||||
|
const oop = require('../lib/oop')
|
||||||
|
const TextMode = require('./text').Mode
|
||||||
|
const Jinja2JsonHighlightRules = require('./jinja2_json_highlight_rules').Jinja2JsonHighlightRules
|
||||||
|
|
||||||
|
const Mode = function (this: any) {
|
||||||
|
TextMode.call(this)
|
||||||
|
this.HighlightRules = Jinja2JsonHighlightRules
|
||||||
|
}
|
||||||
|
|
||||||
|
oop.inherits(Mode, TextMode)
|
||||||
|
|
||||||
|
;(function (this: any) {
|
||||||
|
this.lineCommentStart = '//'
|
||||||
|
this.blockComment = { start: '/*', end: '*/' }
|
||||||
|
this.$id = 'ace/mode/jinja2_json'
|
||||||
|
}).call(Mode.prototype)
|
||||||
|
|
||||||
|
exports.Mode = Mode
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl)
|
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl)
|
||||||
ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl)
|
ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl)
|
||||||
ace.config.setModuleUrl('ace/mode/html', modeHtmlUrl)
|
ace.config.setModuleUrl('ace/mode/html', modeHtmlUrl)
|
||||||
@@ -61,9 +543,10 @@ ace.config.setModuleUrl('ace/mode/yaml_worker', workerYamlUrl)
|
|||||||
ace.config.setModuleUrl('ace/mode/css_worker', workerCssUrl)
|
ace.config.setModuleUrl('ace/mode/css_worker', workerCssUrl)
|
||||||
ace.config.setModuleUrl('ace/snippets/html', snippetsHtmlUrl)
|
ace.config.setModuleUrl('ace/snippets/html', snippetsHtmlUrl)
|
||||||
ace.config.setModuleUrl('ace/snippets/javascript', snippetsJsUrl)
|
ace.config.setModuleUrl('ace/snippets/javascript', snippetsJsUrl)
|
||||||
ace.config.setModuleUrl('ace/snippets/javascript', snippetsYamlUrl)
|
ace.config.setModuleUrl('ace/snippets/yaml', snippetsYamlUrl)
|
||||||
ace.config.setModuleUrl('ace/snippets/json', snippetsJsonUrl)
|
ace.config.setModuleUrl('ace/snippets/json', snippetsJsonUrl)
|
||||||
ace.config.setModuleUrl('ace/snippets/css', snippertsCssUrl)
|
ace.config.setModuleUrl('ace/snippets/css', snippertsCssUrl)
|
||||||
ace.config.setModuleUrl('ace/snippets/ini', snippertsIniUrl)
|
ace.config.setModuleUrl('ace/snippets/ini', snippertsIniUrl)
|
||||||
|
|
||||||
|
registerJinja2Mode()
|
||||||
ace.require('ace/ext/language_tools')
|
ace.require('ace/ext/language_tools')
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import StorageCard from '@/components/cards/StorageCard.vue'
|
|||||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||||
import CategoryEditDialog from '@/components/dialog/CategoryEditDialog.vue'
|
import CategoryEditDialog from '@/components/dialog/CategoryEditDialog.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useTheme } from 'vuetify'
|
||||||
import { storageAttributes } from '@/api/constants'
|
import { storageAttributes } from '@/api/constants'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const { global: globalTheme } = useTheme()
|
||||||
|
|
||||||
// 所有下载目录
|
// 所有下载目录
|
||||||
const directories = ref<TransferDirectoryConf[]>([])
|
const directories = ref<TransferDirectoryConf[]>([])
|
||||||
@@ -58,6 +60,30 @@ const SystemSettings = ref<any>({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 编辑器主题
|
||||||
|
const editorTheme = computed(() => (globalTheme.name.value === 'light' ? 'github' : 'monokai'))
|
||||||
|
|
||||||
|
const renameEditorOptions = {
|
||||||
|
fontSize: 14,
|
||||||
|
tabSize: 2,
|
||||||
|
showLineNumbers: true,
|
||||||
|
showGutter: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
const movieRenameFormat = computed({
|
||||||
|
get: () => SystemSettings.value.Basic.MOVIE_RENAME_FORMAT ?? '',
|
||||||
|
set: (value: string) => {
|
||||||
|
SystemSettings.value.Basic.MOVIE_RENAME_FORMAT = value || null
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const tvRenameFormat = computed({
|
||||||
|
get: () => SystemSettings.value.Basic.TV_RENAME_FORMAT ?? '',
|
||||||
|
set: (value: string) => {
|
||||||
|
SystemSettings.value.Basic.TV_RENAME_FORMAT = value || null
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
// 加载系统设置
|
// 加载系统设置
|
||||||
async function loadSystemSettings() {
|
async function loadSystemSettings() {
|
||||||
try {
|
try {
|
||||||
@@ -346,26 +372,48 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12">
|
<VCol cols="12">
|
||||||
<VTextarea
|
<div class="rename-format-editor">
|
||||||
v-model="SystemSettings.Basic.MOVIE_RENAME_FORMAT"
|
<div class="rename-format-editor__label">
|
||||||
:label="t('setting.directory.movieRenameFormat')"
|
<VIcon icon="mdi-movie-open" size="20" class="me-2" />
|
||||||
:hint="t('setting.directory.movieRenameFormatHint')"
|
<span>{{ t('setting.directory.movieRenameFormat') }}</span>
|
||||||
persistent-hint
|
</div>
|
||||||
clearable
|
<VAceEditor
|
||||||
active
|
v-model:value="movieRenameFormat"
|
||||||
prepend-inner-icon="mdi-movie-open"
|
lang="jinja2"
|
||||||
/>
|
:theme="editorTheme"
|
||||||
|
:options="renameEditorOptions"
|
||||||
|
:print-margin="false"
|
||||||
|
:min-lines="4"
|
||||||
|
:max-lines="12"
|
||||||
|
wrap
|
||||||
|
class="rename-format-editor__ace rounded"
|
||||||
|
/>
|
||||||
|
<div class="rename-format-editor__hint">
|
||||||
|
{{ t('setting.directory.movieRenameFormatHint') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12">
|
<VCol cols="12">
|
||||||
<VTextarea
|
<div class="rename-format-editor">
|
||||||
v-model="SystemSettings.Basic.TV_RENAME_FORMAT"
|
<div class="rename-format-editor__label">
|
||||||
:label="t('setting.directory.tvRenameFormat')"
|
<VIcon icon="mdi-television" size="20" class="me-2" />
|
||||||
:hint="t('setting.directory.tvRenameFormatHint')"
|
<span>{{ t('setting.directory.tvRenameFormat') }}</span>
|
||||||
persistent-hint
|
</div>
|
||||||
clearable
|
<VAceEditor
|
||||||
active
|
v-model:value="tvRenameFormat"
|
||||||
prepend-inner-icon="mdi-television"
|
lang="jinja2"
|
||||||
/>
|
:theme="editorTheme"
|
||||||
|
:options="renameEditorOptions"
|
||||||
|
:print-margin="false"
|
||||||
|
:min-lines="4"
|
||||||
|
:max-lines="12"
|
||||||
|
wrap
|
||||||
|
class="rename-format-editor__ace rounded"
|
||||||
|
/>
|
||||||
|
<div class="rename-format-editor__hint">
|
||||||
|
{{ t('setting.directory.tvRenameFormatHint') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
@@ -392,3 +440,28 @@ onMounted(() => {
|
|||||||
@done="loadMediaCategories"
|
@done="loadMediaCategories"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.rename-format-editor__label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(var(--v-theme-on-surface), 0.78);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.375rem;
|
||||||
|
margin-block-end: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rename-format-editor__ace {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
min-block-size: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rename-format-editor__hint {
|
||||||
|
color: rgba(var(--v-theme-on-surface), 0.6);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
margin-block-start: 0.375rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -480,8 +480,9 @@ onMounted(() => {
|
|||||||
</VCardItem>
|
</VCardItem>
|
||||||
<VCardText class="py-0">
|
<VCardText class="py-0">
|
||||||
<VAceEditor
|
<VAceEditor
|
||||||
|
:key="`${currentTemplate}-jinja2-json`"
|
||||||
v-model:value="editorContent"
|
v-model:value="editorContent"
|
||||||
lang="json"
|
lang="jinja2_json"
|
||||||
:theme="editorTheme"
|
:theme="editorTheme"
|
||||||
class="w-full h-full min-h-[30rem] rounded"
|
class="w-full h-full min-h-[30rem] rounded"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user