From 9b2e0f79d5376fee2eee2c8247d66978045d169c Mon Sep 17 00:00:00 2001 From: Nicolas Giard Date: Sun, 26 Feb 2023 09:42:46 +0000 Subject: [PATCH] feat: admin rendering (wip) --- .../rendering/markdown-abbr/definition.yml | 8 - .../rendering/markdown-abbr/renderer.js | 11 - .../rendering/markdown-core/definition.yml | 63 - .../rendering/markdown-core/renderer.js | 53 - .../rendering/markdown-core/underline.js | 12 - .../rendering/markdown-emoji/definition.yml | 8 - .../rendering/markdown-emoji/renderer.js | 20 - .../markdown-expandtabs/definition.yml | 13 - .../rendering/markdown-expandtabs/renderer.js | 14 - .../markdown-footnotes/definition.yml | 8 - .../rendering/markdown-footnotes/renderer.js | 11 - .../rendering/markdown-imsize/definition.yml | 8 - .../rendering/markdown-imsize/renderer.js | 11 - .../rendering/markdown-katex/definition.yml | 20 - .../rendering/markdown-katex/mhchem.js | 1677 ----------------- .../rendering/markdown-katex/renderer.js | 193 -- .../rendering/markdown-kroki/definition.yml | 29 - .../rendering/markdown-kroki/renderer.js | 143 -- .../rendering/markdown-mathjax/definition.yml | 20 - .../rendering/markdown-mathjax/renderer.js | 205 -- .../markdown-multi-table/definition.yml | 23 - .../markdown-multi-table/renderer.js | 11 - .../markdown-plantuml/definition.yml | 41 - .../rendering/markdown-plantuml/renderer.js | 190 -- .../rendering/markdown-supsub/definition.yml | 18 - .../rendering/markdown-supsub/renderer.js | 17 - .../markdown-tasklists/definition.yml | 8 - .../rendering/markdown-tasklists/renderer.js | 11 - .../rendering/openapi-core/definition.yml | 8 - .../rendering/openapi-core/renderer.js | 14 - ux/public/_assets/icons/ultraviolet-brick.svg | 1 + ux/src/i18n/locales/en.json | 2 +- ux/src/layouts/AdminLayout.vue | 2 +- ux/src/pages/AdminRendering.vue | 342 +--- ux/src/router/routes.js | 2 +- 35 files changed, 77 insertions(+), 3140 deletions(-) delete mode 100644 server/modules/rendering/markdown-abbr/definition.yml delete mode 100644 server/modules/rendering/markdown-abbr/renderer.js delete mode 100644 server/modules/rendering/markdown-core/definition.yml delete mode 100644 server/modules/rendering/markdown-core/renderer.js delete mode 100644 server/modules/rendering/markdown-core/underline.js delete mode 100644 server/modules/rendering/markdown-emoji/definition.yml delete mode 100644 server/modules/rendering/markdown-emoji/renderer.js delete mode 100644 server/modules/rendering/markdown-expandtabs/definition.yml delete mode 100644 server/modules/rendering/markdown-expandtabs/renderer.js delete mode 100644 server/modules/rendering/markdown-footnotes/definition.yml delete mode 100644 server/modules/rendering/markdown-footnotes/renderer.js delete mode 100644 server/modules/rendering/markdown-imsize/definition.yml delete mode 100644 server/modules/rendering/markdown-imsize/renderer.js delete mode 100644 server/modules/rendering/markdown-katex/definition.yml delete mode 100644 server/modules/rendering/markdown-katex/mhchem.js delete mode 100644 server/modules/rendering/markdown-katex/renderer.js delete mode 100644 server/modules/rendering/markdown-kroki/definition.yml delete mode 100644 server/modules/rendering/markdown-kroki/renderer.js delete mode 100644 server/modules/rendering/markdown-mathjax/definition.yml delete mode 100644 server/modules/rendering/markdown-mathjax/renderer.js delete mode 100644 server/modules/rendering/markdown-multi-table/definition.yml delete mode 100644 server/modules/rendering/markdown-multi-table/renderer.js delete mode 100644 server/modules/rendering/markdown-plantuml/definition.yml delete mode 100644 server/modules/rendering/markdown-plantuml/renderer.js delete mode 100644 server/modules/rendering/markdown-supsub/definition.yml delete mode 100644 server/modules/rendering/markdown-supsub/renderer.js delete mode 100644 server/modules/rendering/markdown-tasklists/definition.yml delete mode 100644 server/modules/rendering/markdown-tasklists/renderer.js delete mode 100644 server/modules/rendering/openapi-core/definition.yml delete mode 100644 server/modules/rendering/openapi-core/renderer.js create mode 100644 ux/public/_assets/icons/ultraviolet-brick.svg diff --git a/server/modules/rendering/markdown-abbr/definition.yml b/server/modules/rendering/markdown-abbr/definition.yml deleted file mode 100644 index f64ab46c..00000000 --- a/server/modules/rendering/markdown-abbr/definition.yml +++ /dev/null @@ -1,8 +0,0 @@ -key: markdownAbbr -title: Abbreviations -description: Parse abbreviations into abbr tags -author: requarks.io -icon: mdi-contain-start -enabledDefault: true -dependsOn: markdown-core -props: {} diff --git a/server/modules/rendering/markdown-abbr/renderer.js b/server/modules/rendering/markdown-abbr/renderer.js deleted file mode 100644 index 3438f947..00000000 --- a/server/modules/rendering/markdown-abbr/renderer.js +++ /dev/null @@ -1,11 +0,0 @@ -const mdAbbr = require('markdown-it-abbr') - -// ------------------------------------ -// Markdown - Abbreviations -// ------------------------------------ - -module.exports = { - init (md, conf) { - md.use(mdAbbr) - } -} diff --git a/server/modules/rendering/markdown-core/definition.yml b/server/modules/rendering/markdown-core/definition.yml deleted file mode 100644 index 17a35702..00000000 --- a/server/modules/rendering/markdown-core/definition.yml +++ /dev/null @@ -1,63 +0,0 @@ -key: markdown-core -title: Core -description: Basic Markdown Parser -author: requarks.io -input: markdown -output: html -icon: mdi-language-markdown -props: - allowHTML: - type: Boolean - default: true - title: Allow HTML - hint: Enable HTML tags in content. - order: 1 - public: true - linkify: - type: Boolean - default: true - title: Automatically convert links - hint: Links will automatically be converted to clickable links. - order: 2 - public: true - linebreaks: - type: Boolean - default: true - title: Automatically convert line breaks - hint: Add linebreaks within paragraphs. - order: 3 - public: true - underline: - type: Boolean - default: false - title: Underline Emphasis - hint: Enable text underlining by using _underline_ syntax. - order: 4 - public: true - typographer: - type: Boolean - default: false - title: Typographer - hint: Enable some language-neutral replacement + quotes beautification. - order: 5 - public: true - quotes: - type: String - default: English - title: Quotes style - hint: When typographer is enabled. Double + single quotes replacement pairs. e.g. «»„“ for Russian, „“‚‘ for German, etc. - order: 6 - enum: - - Chinese - - English - - French - - German - - Greek - - Japanese - - Hungarian - - Polish - - Portuguese - - Russian - - Spanish - - Swedish - public: true diff --git a/server/modules/rendering/markdown-core/renderer.js b/server/modules/rendering/markdown-core/renderer.js deleted file mode 100644 index 8e686c6c..00000000 --- a/server/modules/rendering/markdown-core/renderer.js +++ /dev/null @@ -1,53 +0,0 @@ -const md = require('markdown-it') -const mdAttrs = require('markdown-it-attrs') -const _ = require('lodash') -const underline = require('./underline') - -const quoteStyles = { - Chinese: '””‘’', - English: '“”‘’', - French: ['«\xA0', '\xA0»', '‹\xA0', '\xA0›'], - German: '„“‚‘', - Greek: '«»‘’', - Japanese: '「」「」', - Hungarian: '„”’’', - Polish: '„”‚‘', - Portuguese: '«»‘’', - Russian: '«»„“', - Spanish: '«»‘’', - Swedish: '””’’' -} - -module.exports = { - async render() { - const mkdown = md({ - html: this.config.allowHTML, - breaks: this.config.linebreaks, - linkify: this.config.linkify, - typographer: this.config.typographer, - quotes: _.get(quoteStyles, this.config.quotes, quoteStyles.English), - highlight(str, lang) { - if (lang === 'diagram') { - return `
` + Buffer.from(str, 'base64').toString() + `
` - } else { - return `
${_.escape(str)}
` - } - } - }) - - if (this.config.underline) { - mkdown.use(underline) - } - - mkdown.use(mdAttrs, { - allowedAttributes: ['id', 'class', 'target'] - }) - - for (let child of this.children) { - const renderer = require(`../${child.key}/renderer.js`) - await renderer.init(mkdown, child.config) - } - - return mkdown.render(this.input) - } -} diff --git a/server/modules/rendering/markdown-core/underline.js b/server/modules/rendering/markdown-core/underline.js deleted file mode 100644 index a7bc47f8..00000000 --- a/server/modules/rendering/markdown-core/underline.js +++ /dev/null @@ -1,12 +0,0 @@ -const renderEm = (tokens, idx, opts, env, slf) => { - const token = tokens[idx] - if (token.markup === '_') { - token.tag = 'u' - } - return slf.renderToken(tokens, idx, opts) -} - -module.exports = (md) => { - md.renderer.rules.em_open = renderEm - md.renderer.rules.em_close = renderEm -} diff --git a/server/modules/rendering/markdown-emoji/definition.yml b/server/modules/rendering/markdown-emoji/definition.yml deleted file mode 100644 index 716cddee..00000000 --- a/server/modules/rendering/markdown-emoji/definition.yml +++ /dev/null @@ -1,8 +0,0 @@ -key: markdownEmoji -title: Emoji -description: Convert tags to emojis -author: requarks.io -icon: mdi-sticker-emoji -enabledDefault: true -dependsOn: markdown-core -props: {} diff --git a/server/modules/rendering/markdown-emoji/renderer.js b/server/modules/rendering/markdown-emoji/renderer.js deleted file mode 100644 index 331b97ef..00000000 --- a/server/modules/rendering/markdown-emoji/renderer.js +++ /dev/null @@ -1,20 +0,0 @@ -const mdEmoji = require('markdown-it-emoji') -const twemoji = require('twemoji') - -// ------------------------------------ -// Markdown - Emoji -// ------------------------------------ - -module.exports = { - init (md, conf) { - md.use(mdEmoji) - - md.renderer.rules.emoji = (token, idx) => { - return twemoji.parse(token[idx].content, { - callback (icon, opts) { - return `/_assets/svg/twemoji/${icon}.svg` - } - }) - } - } -} diff --git a/server/modules/rendering/markdown-expandtabs/definition.yml b/server/modules/rendering/markdown-expandtabs/definition.yml deleted file mode 100644 index 6531d2a8..00000000 --- a/server/modules/rendering/markdown-expandtabs/definition.yml +++ /dev/null @@ -1,13 +0,0 @@ -key: markdownExpandtabs -title: Expand Tabs -description: Replace tabs with spaces in code blocks -author: requarks.io -icon: mdi-arrow-expand-horizontal -enabledDefault: true -dependsOn: markdown-core -props: - tabWidth: - type: Number - title: Tab Width - hint: Amount of spaces for each tab - default: 4 diff --git a/server/modules/rendering/markdown-expandtabs/renderer.js b/server/modules/rendering/markdown-expandtabs/renderer.js deleted file mode 100644 index 39c0825f..00000000 --- a/server/modules/rendering/markdown-expandtabs/renderer.js +++ /dev/null @@ -1,14 +0,0 @@ -const mdExpandTabs = require('markdown-it-expand-tabs') -const _ = require('lodash') - -// ------------------------------------ -// Markdown - Expand Tabs -// ------------------------------------ - -module.exports = { - init (md, conf) { - md.use(mdExpandTabs, { - tabWidth: _.toInteger(conf.tabWidth || 4) - }) - } -} diff --git a/server/modules/rendering/markdown-footnotes/definition.yml b/server/modules/rendering/markdown-footnotes/definition.yml deleted file mode 100644 index 00876294..00000000 --- a/server/modules/rendering/markdown-footnotes/definition.yml +++ /dev/null @@ -1,8 +0,0 @@ -key: markdownFootnotes -title: Footnotes -description: Parse footnotes references -author: requarks.io -icon: mdi-page-layout-footer -enabledDefault: true -dependsOn: markdown-core -props: {} diff --git a/server/modules/rendering/markdown-footnotes/renderer.js b/server/modules/rendering/markdown-footnotes/renderer.js deleted file mode 100644 index 553b04b3..00000000 --- a/server/modules/rendering/markdown-footnotes/renderer.js +++ /dev/null @@ -1,11 +0,0 @@ -const mdFootnote = require('markdown-it-footnote') - -// ------------------------------------ -// Markdown - Footnotes -// ------------------------------------ - -module.exports = { - init (md, conf) { - md.use(mdFootnote) - } -} diff --git a/server/modules/rendering/markdown-imsize/definition.yml b/server/modules/rendering/markdown-imsize/definition.yml deleted file mode 100644 index 603a3069..00000000 --- a/server/modules/rendering/markdown-imsize/definition.yml +++ /dev/null @@ -1,8 +0,0 @@ -key: markdownImsize -title: Image Size -description: Adds dimensions attributes to images -author: requarks.io -icon: mdi-image-size-select-large -enabledDefault: true -dependsOn: markdown-core -props: {} diff --git a/server/modules/rendering/markdown-imsize/renderer.js b/server/modules/rendering/markdown-imsize/renderer.js deleted file mode 100644 index 33bd80ac..00000000 --- a/server/modules/rendering/markdown-imsize/renderer.js +++ /dev/null @@ -1,11 +0,0 @@ -const mdImsize = require('markdown-it-imsize') - -// ------------------------------------ -// Markdown - Image Size -// ------------------------------------ - -module.exports = { - init (md, conf) { - md.use(mdImsize) - } -} diff --git a/server/modules/rendering/markdown-katex/definition.yml b/server/modules/rendering/markdown-katex/definition.yml deleted file mode 100644 index 0532ea75..00000000 --- a/server/modules/rendering/markdown-katex/definition.yml +++ /dev/null @@ -1,20 +0,0 @@ -key: markdownKatex -title: Katex -description: LaTeX Math + Chemical Expression Typesetting Renderer -author: requarks.io -icon: mdi-math-integral -enabledDefault: true -dependsOn: markdown-core -props: - useInline: - type: Boolean - default: true - title: Inline TeX - hint: Process inline TeX expressions surrounded by $ symbols. - order: 1 - useBlocks: - type: Boolean - default: true - title: TeX Blocks - hint: Process TeX blocks enclosed by $$ symbols. - order: 2 diff --git a/server/modules/rendering/markdown-katex/mhchem.js b/server/modules/rendering/markdown-katex/mhchem.js deleted file mode 100644 index 4a9860f7..00000000 --- a/server/modules/rendering/markdown-katex/mhchem.js +++ /dev/null @@ -1,1677 +0,0 @@ -/* eslint-disable */ -/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ - -/************************************************************* - * - * KaTeX mhchem.js - * - * This file implements a KaTeX version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from KaTeX, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. Four lines of code are edited in order to use \raisebox instead of \raise. - * 4. The reaction arrow code is simplified. All reaction arrows are rendered - * using KaTeX extensible arrows instead of building non-extensible arrows. - * 5. \tripledash vertical alignment is slightly adjusted. - * - * This code, as other KaTeX code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and KaTeX - - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - module.exports = function (tokens, stateMachine) { - // Recreate the argument string from KaTeX's array of tokens. - var str = ""; - var expectedLoc = tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i": return "rightarrow"; - case "\u2192": return "rightarrow"; - case "\u27F6": return "rightarrow"; - case "<-": return "leftarrow"; - case "<->": return "leftrightarrow"; - case "<-->": return "rightleftarrows"; - case "<=>": return "rightleftharpoons"; - case "\u21CC": return "rightleftharpoons"; - case "<=>>": return "rightequilibrium"; - case "<<=>": return "leftequilibrium"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripledash}"; - case "~-": return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}"; - case "~=": return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; - case "~--": return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; - case "-~-": return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} diff --git a/server/modules/rendering/markdown-katex/renderer.js b/server/modules/rendering/markdown-katex/renderer.js deleted file mode 100644 index d8f26510..00000000 --- a/server/modules/rendering/markdown-katex/renderer.js +++ /dev/null @@ -1,193 +0,0 @@ -const katex = require('katex') -const chemParse = require('./mhchem') - -// ------------------------------------ -// Markdown - KaTeX Renderer -// ------------------------------------ -// -// Includes code from https://github.com/liradb2000/markdown-it-katex - -// Add \ce, \pu, and \tripledash to the KaTeX macros. -katex.__defineMacro('\\ce', function(context) { - return chemParse(context.consumeArgs(1)[0], 'ce') -}) -katex.__defineMacro('\\pu', function(context) { - return chemParse(context.consumeArgs(1)[0], 'pu') -}) - -// Needed for \bond for the ~ forms -// Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not -// a mathematical minus, U+2212. So we need that extra 0.56. -katex.__defineMacro('\\tripledash', '{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu' + '\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}') - -module.exports = { - init (mdinst, conf) { - if (conf.useInline) { - mdinst.inline.ruler.after('escape', 'katex_inline', katexInline) - mdinst.renderer.rules.katex_inline = (tokens, idx) => { - try { - return katex.renderToString(tokens[idx].content, { - displayMode: false - }) - } catch (err) { - WIKI.logger.warn(err) - return tokens[idx].content - } - } - } - if (conf.useBlocks) { - mdinst.block.ruler.after('blockquote', 'katex_block', katexBlock, { - alt: [ 'paragraph', 'reference', 'blockquote', 'list' ] - }) - mdinst.renderer.rules.katex_block = (tokens, idx) => { - try { - return `

` + katex.renderToString(tokens[idx].content, { - displayMode: true - }) + `

` - } catch (err) { - WIKI.logger.warn(err) - return tokens[idx].content - } - } - } - } -} - -// Test if potential opening or closing delimieter -// Assumes that there is a "$" at state.src[pos] -function isValidDelim (state, pos) { - let prevChar - let nextChar - let max = state.posMax - let canOpen = true - let canClose = true - - prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1 - nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1 - - // Check non-whitespace conditions for opening and closing, and - // check that closing delimeter isn't followed by a number - if (prevChar === 0x20/* " " */ || prevChar === 0x09/* \t */ || - (nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */)) { - canClose = false - } - if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */) { - canOpen = false - } - - return { - canOpen: canOpen, - canClose: canClose - } -} - -function katexInline (state, silent) { - let start, match, token, res, pos - - if (state.src[state.pos] !== '$') { return false } - - res = isValidDelim(state, state.pos) - if (!res.canOpen) { - if (!silent) { state.pending += '$' } - state.pos += 1 - return true - } - - // First check for and bypass all properly escaped delimieters - // This loop will assume that the first leading backtick can not - // be the first character in state.src, which is known since - // we have found an opening delimieter already. - start = state.pos + 1 - match = start - while ((match = state.src.indexOf('$', match)) !== -1) { - // Found potential $, look for escapes, pos will point to - // first non escape when complete - pos = match - 1 - while (state.src[pos] === '\\') { pos -= 1 } - - // Even number of escapes, potential closing delimiter found - if (((match - pos) % 2) === 1) { break } - match += 1 - } - - // No closing delimter found. Consume $ and continue. - if (match === -1) { - if (!silent) { state.pending += '$' } - state.pos = start - return true - } - - // Check if we have empty content, ie: $$. Do not parse. - if (match - start === 0) { - if (!silent) { state.pending += '$$' } - state.pos = start + 1 - return true - } - - // Check for valid closing delimiter - res = isValidDelim(state, match) - if (!res.canClose) { - if (!silent) { state.pending += '$' } - state.pos = start - return true - } - - if (!silent) { - token = state.push('katex_inline', 'math', 0) - token.markup = '$' - token.content = state.src.slice(start, match) - } - - state.pos = match + 1 - return true -} - -function katexBlock (state, start, end, silent) { - let firstLine; let lastLine; let next; let lastPos; let found = false; let token - let pos = state.bMarks[start] + state.tShift[start] - let max = state.eMarks[start] - - if (pos + 2 > max) { return false } - if (state.src.slice(pos, pos + 2) !== '$$') { return false } - - pos += 2 - firstLine = state.src.slice(pos, max) - - if (silent) { return true } - if (firstLine.trim().slice(-2) === '$$') { - // Single line expression - firstLine = firstLine.trim().slice(0, -2) - found = true - } - - for (next = start; !found;) { - next++ - - if (next >= end) { break } - - pos = state.bMarks[next] + state.tShift[next] - max = state.eMarks[next] - - if (pos < max && state.tShift[next] < state.blkIndent) { - // non-empty line with negative indent should stop the list: - break - } - - if (state.src.slice(pos, max).trim().slice(-2) === '$$') { - lastPos = state.src.slice(0, max).lastIndexOf('$$') - lastLine = state.src.slice(pos, lastPos) - found = true - } - } - - state.line = next + 1 - - token = state.push('katex_block', 'math', 0) - token.block = true - token.content = (firstLine && firstLine.trim() ? firstLine + '\n' : '') + - state.getLines(start + 1, next, state.tShift[start], true) + - (lastLine && lastLine.trim() ? lastLine : '') - token.map = [ start, state.line ] - token.markup = '$$' - return true -} diff --git a/server/modules/rendering/markdown-kroki/definition.yml b/server/modules/rendering/markdown-kroki/definition.yml deleted file mode 100644 index b56d3785..00000000 --- a/server/modules/rendering/markdown-kroki/definition.yml +++ /dev/null @@ -1,29 +0,0 @@ -key: markdownKroki -title: Kroki -description: Kroki Diagrams Parser -author: rlanyi (based on PlantUML renderer) -icon: mdi-sitemap -enabledDefault: false -dependsOn: markdown-core -props: - server: - type: String - default: https://kroki.io - title: Kroki Server - hint: Kroki server used for image generation - order: 1 - public: true - openMarker: - type: String - default: "```kroki" - title: Open Marker - hint: String to use as opening delimiter. Diagram type must be put in the next line in lowercase. - order: 2 - public: true - closeMarker: - type: String - default: "```" - title: Close Marker - hint: String to use as closing delimiter - order: 3 - public: true diff --git a/server/modules/rendering/markdown-kroki/renderer.js b/server/modules/rendering/markdown-kroki/renderer.js deleted file mode 100644 index 801bab6d..00000000 --- a/server/modules/rendering/markdown-kroki/renderer.js +++ /dev/null @@ -1,143 +0,0 @@ -const zlib = require('zlib') - -// ------------------------------------ -// Markdown - Kroki Preprocessor -// ------------------------------------ - -module.exports = { - init (mdinst, conf) { - mdinst.use((md, opts) => { - const openMarker = opts.openMarker || '```kroki' - const openChar = openMarker.charCodeAt(0) - const closeMarker = opts.closeMarker || '```' - const closeChar = closeMarker.charCodeAt(0) - const server = opts.server || 'https://kroki.io' - - md.block.ruler.before('fence', 'kroki', (state, startLine, endLine, silent) => { - let nextLine - let markup - let params - let token - let i - let autoClosed = false - let start = state.bMarks[startLine] + state.tShift[startLine] - let max = state.eMarks[startLine] - - // Check out the first character quickly, - // this should filter out most of non-uml blocks - // - if (openChar !== state.src.charCodeAt(start)) { return false } - - // Check out the rest of the marker string - // - for (i = 0; i < openMarker.length; ++i) { - if (openMarker[i] !== state.src[start + i]) { return false } - } - - markup = state.src.slice(start, start + i) - params = state.src.slice(start + i, max) - - // Since start is found, we can report success here in validation mode - // - if (silent) { return true } - - // Search for the end of the block - // - nextLine = startLine - - for (;;) { - nextLine++ - if (nextLine >= endLine) { - // unclosed block should be autoclosed by end of document. - // also block seems to be autoclosed by end of parent - break - } - - start = state.bMarks[nextLine] + state.tShift[nextLine] - max = state.eMarks[nextLine] - - if (start < max && state.sCount[nextLine] < state.blkIndent) { - // non-empty line with negative indent should stop the list: - // - ``` - // test - break - } - - if (closeChar !== state.src.charCodeAt(start)) { - // didn't find the closing fence - continue - } - - if (state.sCount[nextLine] > state.sCount[startLine]) { - // closing fence should not be indented with respect of opening fence - continue - } - - let closeMarkerMatched = true - for (i = 0; i < closeMarker.length; ++i) { - if (closeMarker[i] !== state.src[start + i]) { - closeMarkerMatched = false - break - } - } - - if (!closeMarkerMatched) { - continue - } - - // make sure tail has spaces only - if (state.skipSpaces(start + i) < max) { - continue - } - - // found! - autoClosed = true - break - } - - let contents = state.src - .split('\n') - .slice(startLine + 1, nextLine) - .join('\n') - - // We generate a token list for the alt property, to mimic what the image parser does. - let altToken = [] - // Remove leading space if any. - let alt = params ? params.slice(1) : 'uml diagram' - state.md.inline.parse( - alt, - state.md, - state.env, - altToken - ) - - let firstlf = contents.indexOf('\n') - if (firstlf === -1) firstlf = undefined - let diagramType = contents.substring(0, firstlf) - contents = contents.substring(firstlf + 1) - - let result = zlib.deflateSync(contents).toString('base64').replace(/\+/g, '-').replace(/\//g, '_') - - token = state.push('kroki', 'img', 0) - // alt is constructed from children. No point in populating it here. - token.attrs = [ [ 'src', `${server}/${diagramType}/svg/${result}` ], [ 'alt', '' ], ['class', 'uml-diagram prefetch-candidate'] ] - token.block = true - token.children = altToken - token.info = params - token.map = [ startLine, nextLine ] - token.markup = markup - - state.line = nextLine + (autoClosed ? 1 : 0) - - return true - }, { - alt: [ 'paragraph', 'reference', 'blockquote', 'list' ] - }) - md.renderer.rules.kroki = md.renderer.rules.image - }, { - openMarker: conf.openMarker, - closeMarker: conf.closeMarker, - server: conf.server - }) - } -} diff --git a/server/modules/rendering/markdown-mathjax/definition.yml b/server/modules/rendering/markdown-mathjax/definition.yml deleted file mode 100644 index c0e95120..00000000 --- a/server/modules/rendering/markdown-mathjax/definition.yml +++ /dev/null @@ -1,20 +0,0 @@ -key: markdownMathjax -title: Mathjax -description: LaTeX Math + Chemical Expression Typesetting Renderer -author: requarks.io -icon: mdi-math-integral -enabledDefault: false -dependsOn: markdown-core -props: - useInline: - type: Boolean - default: true - title: Inline TeX - hint: Process inline TeX expressions surrounded by $ symbols. - order: 1 - useBlocks: - type: Boolean - default: true - title: TeX Blocks - hint: Process TeX blocks enclosed by $$ symbols. - order: 2 diff --git a/server/modules/rendering/markdown-mathjax/renderer.js b/server/modules/rendering/markdown-mathjax/renderer.js deleted file mode 100644 index b7596521..00000000 --- a/server/modules/rendering/markdown-mathjax/renderer.js +++ /dev/null @@ -1,205 +0,0 @@ -const mjax = require('mathjax') - -// ------------------------------------ -// Markdown - MathJax Renderer -// ------------------------------------ - -const extensions = [ - 'bbox', - 'boldsymbol', - 'braket', - 'color', - 'extpfeil', - 'mhchem', - 'newcommand', - 'unicode', - 'verb' -] - -module.exports = { - async init (mdinst, conf) { - const MathJax = await mjax.init({ - loader: { - require: require, - paths: { mathjax: 'mathjax/es5' }, - load: [ - 'input/tex', - 'output/svg', - ...extensions.map(e => `[tex]/${e}`) - ] - }, - tex: { - packages: {'[+]': extensions} - } - }) - if (conf.useInline) { - mdinst.inline.ruler.after('escape', 'mathjax_inline', mathjaxInline) - mdinst.renderer.rules.mathjax_inline = (tokens, idx) => { - try { - const result = MathJax.tex2svg(tokens[idx].content, { - display: false - }) - return MathJax.startup.adaptor.innerHTML(result) - } catch (err) { - WIKI.logger.warn(err) - return tokens[idx].content - } - } - } - if (conf.useBlocks) { - mdinst.block.ruler.after('blockquote', 'mathjax_block', mathjaxBlock, { - alt: [ 'paragraph', 'reference', 'blockquote', 'list' ] - }) - mdinst.renderer.rules.mathjax_block = (tokens, idx) => { - try { - const result = MathJax.tex2svg(tokens[idx].content, { - display: true - }) - return `

` + MathJax.startup.adaptor.innerHTML(result) + `

` - } catch (err) { - WIKI.logger.warn(err) - return tokens[idx].content - } - } - } - } -} - -// Test if potential opening or closing delimieter -// Assumes that there is a "$" at state.src[pos] -function isValidDelim (state, pos) { - let prevChar - let nextChar - let max = state.posMax - let canOpen = true - let canClose = true - - prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1 - nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1 - - // Check non-whitespace conditions for opening and closing, and - // check that closing delimeter isn't followed by a number - if (prevChar === 0x20/* " " */ || prevChar === 0x09/* \t */ || - (nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */)) { - canClose = false - } - if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */) { - canOpen = false - } - - return { - canOpen: canOpen, - canClose: canClose - } -} - -function mathjaxInline (state, silent) { - let start, match, token, res, pos - - if (state.src[state.pos] !== '$') { return false } - - res = isValidDelim(state, state.pos) - if (!res.canOpen) { - if (!silent) { state.pending += '$' } - state.pos += 1 - return true - } - - // First check for and bypass all properly escaped delimieters - // This loop will assume that the first leading backtick can not - // be the first character in state.src, which is known since - // we have found an opening delimieter already. - start = state.pos + 1 - match = start - while ((match = state.src.indexOf('$', match)) !== -1) { - // Found potential $, look for escapes, pos will point to - // first non escape when complete - pos = match - 1 - while (state.src[pos] === '\\') { pos -= 1 } - - // Even number of escapes, potential closing delimiter found - if (((match - pos) % 2) === 1) { break } - match += 1 - } - - // No closing delimter found. Consume $ and continue. - if (match === -1) { - if (!silent) { state.pending += '$' } - state.pos = start - return true - } - - // Check if we have empty content, ie: $$. Do not parse. - if (match - start === 0) { - if (!silent) { state.pending += '$$' } - state.pos = start + 1 - return true - } - - // Check for valid closing delimiter - res = isValidDelim(state, match) - if (!res.canClose) { - if (!silent) { state.pending += '$' } - state.pos = start - return true - } - - if (!silent) { - token = state.push('mathjax_inline', 'math', 0) - token.markup = '$' - token.content = state.src.slice(start, match) - } - - state.pos = match + 1 - return true -} - -function mathjaxBlock (state, start, end, silent) { - let firstLine; let lastLine; let next; let lastPos; let found = false; let token - let pos = state.bMarks[start] + state.tShift[start] - let max = state.eMarks[start] - - if (pos + 2 > max) { return false } - if (state.src.slice(pos, pos + 2) !== '$$') { return false } - - pos += 2 - firstLine = state.src.slice(pos, max) - - if (silent) { return true } - if (firstLine.trim().slice(-2) === '$$') { - // Single line expression - firstLine = firstLine.trim().slice(0, -2) - found = true - } - - for (next = start; !found;) { - next++ - - if (next >= end) { break } - - pos = state.bMarks[next] + state.tShift[next] - max = state.eMarks[next] - - if (pos < max && state.tShift[next] < state.blkIndent) { - // non-empty line with negative indent should stop the list: - break - } - - if (state.src.slice(pos, max).trim().slice(-2) === '$$') { - lastPos = state.src.slice(0, max).lastIndexOf('$$') - lastLine = state.src.slice(pos, lastPos) - found = true - } - } - - state.line = next + 1 - - token = state.push('mathjax_block', 'math', 0) - token.block = true - token.content = (firstLine && firstLine.trim() ? firstLine + '\n' : '') + - state.getLines(start + 1, next, state.tShift[start], true) + - (lastLine && lastLine.trim() ? lastLine : '') - token.map = [ start, state.line ] - token.markup = '$$' - return true -} diff --git a/server/modules/rendering/markdown-multi-table/definition.yml b/server/modules/rendering/markdown-multi-table/definition.yml deleted file mode 100644 index 57885052..00000000 --- a/server/modules/rendering/markdown-multi-table/definition.yml +++ /dev/null @@ -1,23 +0,0 @@ -key: markdownMultiTable -title: MultiMarkdown Table -description: Add MultiMarkdown table support -author: requarks.io -icon: mdi-table -enabledDefault: false -dependsOn: markdown-core -props: - multilineEnabled: - type: Boolean - title: Multiline - hint: Enable multiple lines rows - default: true - headerlessEnabled: - type: Boolean - title: Headerless - hint: Enable ommited table headers - default: true - rowspanEnabled: - type: Boolean - title: Rowspan - hint: Enable table row spans - default: true diff --git a/server/modules/rendering/markdown-multi-table/renderer.js b/server/modules/rendering/markdown-multi-table/renderer.js deleted file mode 100644 index 79be64c1..00000000 --- a/server/modules/rendering/markdown-multi-table/renderer.js +++ /dev/null @@ -1,11 +0,0 @@ -const multiTable = require('markdown-it-multimd-table') - -module.exports = { - init (md, conf) { - md.use(multiTable, { - multiline: conf.multilineEnabled, - rowspan: conf.rowspanEnabled, - headerless: conf.headerlessEnabled - }) - } -} diff --git a/server/modules/rendering/markdown-plantuml/definition.yml b/server/modules/rendering/markdown-plantuml/definition.yml deleted file mode 100644 index eb81d834..00000000 --- a/server/modules/rendering/markdown-plantuml/definition.yml +++ /dev/null @@ -1,41 +0,0 @@ -key: markdownPlantuml -title: PlantUML -description: PlantUML Markdown Parser -author: ethanmdavidson -icon: mdi-sitemap -enabledDefault: true -dependsOn: markdown-core -props: - server: - type: String - default: https://plantuml.requarks.io - title: PlantUML Server - hint: PlantUML server used for image generation - order: 1 - public: true - openMarker: - type: String - default: "```plantuml" - title: Open Marker - hint: String to use as opening delimiter - order: 2 - public: true - closeMarker: - type: String - default: "```" - title: Close Marker - hint: String to use as closing delimiter - order: 3 - public: true - imageFormat: - type: String - default: svg - title: Image Format - hint: Format to use for rendered PlantUML images - enum: - - svg - - png - - latex - - ascii - order: 4 - public: true diff --git a/server/modules/rendering/markdown-plantuml/renderer.js b/server/modules/rendering/markdown-plantuml/renderer.js deleted file mode 100644 index 40eedc04..00000000 --- a/server/modules/rendering/markdown-plantuml/renderer.js +++ /dev/null @@ -1,190 +0,0 @@ -const zlib = require('zlib') - -// ------------------------------------ -// Markdown - PlantUML Preprocessor -// ------------------------------------ - -module.exports = { - init (mdinst, conf) { - mdinst.use((md, opts) => { - const openMarker = opts.openMarker || '```plantuml' - const openChar = openMarker.charCodeAt(0) - const closeMarker = opts.closeMarker || '```' - const closeChar = closeMarker.charCodeAt(0) - const imageFormat = opts.imageFormat || 'svg' - const server = opts.server || 'https://plantuml.requarks.io' - - md.block.ruler.before('fence', 'uml_diagram', (state, startLine, endLine, silent) => { - let nextLine - let markup - let params - let token - let i - let autoClosed = false - let start = state.bMarks[startLine] + state.tShift[startLine] - let max = state.eMarks[startLine] - - // Check out the first character quickly, - // this should filter out most of non-uml blocks - // - if (openChar !== state.src.charCodeAt(start)) { return false } - - // Check out the rest of the marker string - // - for (i = 0; i < openMarker.length; ++i) { - if (openMarker[i] !== state.src[start + i]) { return false } - } - - markup = state.src.slice(start, start + i) - params = state.src.slice(start + i, max) - - // Since start is found, we can report success here in validation mode - // - if (silent) { return true } - - // Search for the end of the block - // - nextLine = startLine - - for (;;) { - nextLine++ - if (nextLine >= endLine) { - // unclosed block should be autoclosed by end of document. - // also block seems to be autoclosed by end of parent - break - } - - start = state.bMarks[nextLine] + state.tShift[nextLine] - max = state.eMarks[nextLine] - - if (start < max && state.sCount[nextLine] < state.blkIndent) { - // non-empty line with negative indent should stop the list: - // - ``` - // test - break - } - - if (closeChar !== state.src.charCodeAt(start)) { - // didn't find the closing fence - continue - } - - if (state.sCount[nextLine] > state.sCount[startLine]) { - // closing fence should not be indented with respect of opening fence - continue - } - - let closeMarkerMatched = true - for (i = 0; i < closeMarker.length; ++i) { - if (closeMarker[i] !== state.src[start + i]) { - closeMarkerMatched = false - break - } - } - - if (!closeMarkerMatched) { - continue - } - - // make sure tail has spaces only - if (state.skipSpaces(start + i) < max) { - continue - } - - // found! - autoClosed = true - break - } - - const contents = state.src - .split('\n') - .slice(startLine + 1, nextLine) - .join('\n') - - // We generate a token list for the alt property, to mimic what the image parser does. - let altToken = [] - // Remove leading space if any. - let alt = params ? params.slice(1) : 'uml diagram' - state.md.inline.parse( - alt, - state.md, - state.env, - altToken - ) - - const zippedCode = encode64(zlib.deflateRawSync('@startuml\n' + contents + '\n@enduml').toString('binary')) - - token = state.push('uml_diagram', 'img', 0) - // alt is constructed from children. No point in populating it here. - token.attrs = [ [ 'src', `${server}/${imageFormat}/${zippedCode}` ], [ 'alt', '' ], ['class', 'uml-diagram prefetch-candidate'] ] - token.block = true - token.children = altToken - token.info = params - token.map = [ startLine, nextLine ] - token.markup = markup - - state.line = nextLine + (autoClosed ? 1 : 0) - - return true - }, { - alt: [ 'paragraph', 'reference', 'blockquote', 'list' ] - }) - md.renderer.rules.uml_diagram = md.renderer.rules.image - }, { - openMarker: conf.openMarker, - closeMarker: conf.closeMarker, - imageFormat: conf.imageFormat, - server: conf.server - }) - } -} - -function encode64 (data) { - let r = '' - for (let i = 0; i < data.length; i += 3) { - if (i + 2 === data.length) { - r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0) - } else if (i + 1 === data.length) { - r += append3bytes(data.charCodeAt(i), 0, 0) - } else { - r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), data.charCodeAt(i + 2)) - } - } - return r -} - -function append3bytes (b1, b2, b3) { - let c1 = b1 >> 2 - let c2 = ((b1 & 0x3) << 4) | (b2 >> 4) - let c3 = ((b2 & 0xF) << 2) | (b3 >> 6) - let c4 = b3 & 0x3F - let r = '' - r += encode6bit(c1 & 0x3F) - r += encode6bit(c2 & 0x3F) - r += encode6bit(c3 & 0x3F) - r += encode6bit(c4 & 0x3F) - return r -} - -function encode6bit(raw) { - let b = raw - if (b < 10) { - return String.fromCharCode(48 + b) - } - b -= 10 - if (b < 26) { - return String.fromCharCode(65 + b) - } - b -= 26 - if (b < 26) { - return String.fromCharCode(97 + b) - } - b -= 26 - if (b === 0) { - return '-' - } - if (b === 1) { - return '_' - } - return '?' -} diff --git a/server/modules/rendering/markdown-supsub/definition.yml b/server/modules/rendering/markdown-supsub/definition.yml deleted file mode 100644 index ffb63b21..00000000 --- a/server/modules/rendering/markdown-supsub/definition.yml +++ /dev/null @@ -1,18 +0,0 @@ -key: markdownSupsub -title: Subscript/Superscript -description: Parse subscript and superscript tags -author: requarks.io -icon: mdi-format-superscript -enabledDefault: true -dependsOn: markdown-core -props: - subEnabled: - type: Boolean - title: Subscript - hint: Enable subscript tags - default: true - supEnabled: - type: Boolean - title: Superscript - hint: Enable superscript tags - default: true diff --git a/server/modules/rendering/markdown-supsub/renderer.js b/server/modules/rendering/markdown-supsub/renderer.js deleted file mode 100644 index be57ac1f..00000000 --- a/server/modules/rendering/markdown-supsub/renderer.js +++ /dev/null @@ -1,17 +0,0 @@ -const mdSub = require('markdown-it-sub') -const mdSup = require('markdown-it-sup') - -// ------------------------------------ -// Markdown - Subscript / Superscript -// ------------------------------------ - -module.exports = { - init (md, conf) { - if (conf.subEnabled) { - md.use(mdSub) - } - if (conf.supEnabled) { - md.use(mdSup) - } - } -} diff --git a/server/modules/rendering/markdown-tasklists/definition.yml b/server/modules/rendering/markdown-tasklists/definition.yml deleted file mode 100644 index 866ef99b..00000000 --- a/server/modules/rendering/markdown-tasklists/definition.yml +++ /dev/null @@ -1,8 +0,0 @@ -key: markdownTasklists -title: Task Lists -description: Parse task lists to checkboxes -author: requarks.io -icon: mdi-format-list-checks -enabledDefault: true -dependsOn: markdown-core -props: {} diff --git a/server/modules/rendering/markdown-tasklists/renderer.js b/server/modules/rendering/markdown-tasklists/renderer.js deleted file mode 100644 index 6950acdd..00000000 --- a/server/modules/rendering/markdown-tasklists/renderer.js +++ /dev/null @@ -1,11 +0,0 @@ -const mdTaskLists = require('markdown-it-task-lists') - -// ------------------------------------ -// Markdown - Task Lists -// ------------------------------------ - -module.exports = { - init (md, conf) { - md.use(mdTaskLists, { label: false, labelAfter: false }) - } -} diff --git a/server/modules/rendering/openapi-core/definition.yml b/server/modules/rendering/openapi-core/definition.yml deleted file mode 100644 index 557ad792..00000000 --- a/server/modules/rendering/openapi-core/definition.yml +++ /dev/null @@ -1,8 +0,0 @@ -key: openapiCore -title: Core -description: Basic OpenAPI Parser -author: requarks.io -input: openapi -output: html -icon: mdi-api -props: {} diff --git a/server/modules/rendering/openapi-core/renderer.js b/server/modules/rendering/openapi-core/renderer.js deleted file mode 100644 index 25df7eca..00000000 --- a/server/modules/rendering/openapi-core/renderer.js +++ /dev/null @@ -1,14 +0,0 @@ -const _ = require('lodash') - -module.exports = { - async render() { - let output = this.input - - for (let child of this.children) { - const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`) - output = await renderer.init(output, child.config) - } - - return output - } -} diff --git a/ux/public/_assets/icons/ultraviolet-brick.svg b/ux/public/_assets/icons/ultraviolet-brick.svg new file mode 100644 index 00000000..521e18c3 --- /dev/null +++ b/ux/public/_assets/icons/ultraviolet-brick.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ux/src/i18n/locales/en.json b/ux/src/i18n/locales/en.json index d2ae6246..472c71b9 100644 --- a/ux/src/i18n/locales/en.json +++ b/ux/src/i18n/locales/en.json @@ -449,7 +449,7 @@ "admin.navigation.visibilityMode.all": "Visible to everyone", "admin.navigation.visibilityMode.restricted": "Visible to select groups...", "admin.pages.title": "Pages", - "admin.rendering.subtitle": "Configure the page rendering pipeline", + "admin.rendering.subtitle": "Configure the content rendering pipeline", "admin.rendering.title": "Rendering", "admin.scheduler.active": "Active", "admin.scheduler.activeNone": "There are no active jobs at the moment.", diff --git a/ux/src/layouts/AdminLayout.vue b/ux/src/layouts/AdminLayout.vue index e285d608..5b43bb75 100644 --- a/ux/src/layouts/AdminLayout.vue +++ b/ux/src/layouts/AdminLayout.vue @@ -157,7 +157,7 @@ q-layout.admin(view='hHh Lpr lff') q-item-section {{ t('admin.mail.title') }} q-item-section(side) status-light(:color='adminStore.info.isMailConfigured ? `positive` : `warning`') - q-item(to='/_admin/rendering', v-ripple, active-class='bg-primary text-white', disabled, v-if='flagsStore.experimental') + q-item(to='/_admin/rendering', v-ripple, active-class='bg-primary text-white') q-item-section(avatar) q-icon(name='img:/_assets/icons/fluent-rich-text-converter.svg') q-item-section {{ t('admin.rendering.title') }} diff --git a/ux/src/pages/AdminRendering.vue b/ux/src/pages/AdminRendering.vue index b20f031b..d4e658f4 100644 --- a/ux/src/pages/AdminRendering.vue +++ b/ux/src/pages/AdminRendering.vue @@ -11,7 +11,7 @@ q-page.admin-mail icon='las la-question-circle' flat color='grey' - href='https://docs.js.wiki/admin/rendering' + :href='siteStore.docsBase + `/system/rendering`' target='_blank' type='a' ) @@ -19,7 +19,7 @@ q-page.admin-mail icon='las la-redo-alt' flat color='secondary' - :loading='loading > 0' + :loading='state.loading > 0' @click='load' ) q-btn( @@ -28,284 +28,88 @@ q-page.admin-mail :label='$t(`common.actions.apply`)' color='secondary' @click='save' - :disabled='loading > 0' + :disabled='state.loading > 0' ) q-separator(inset) - //- v-container(fluid, grid-list-lg) - //- v-layout(row, wrap) - //- v-flex(xs12) - //- .admin-header - //- img.animated.fadeInUp(src='/_assets/svg/icon-process.svg', alt='Rendering', style='width: 80px;') - //- .admin-header-title - //- .headline.primary--text.animated.fadeInLeft {{ $t('admin.rendering.title') }} - //- .subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{ $t('admin.rendering.subtitle') }} - //- v-spacer - //- v-btn.animated.fadeInDown.wait-p3s(icon, outlined, color='grey', href='https://docs.requarks.io/rendering', target='_blank') - //- v-icon mdi-help-circle - //- v-btn.mx-3.animated.fadeInDown.wait-p2s(icon, outlined, color='grey', @click='refresh') - //- v-icon mdi-refresh - //- v-btn.animated.fadeInDown(color='success', @click='save', depressed, large) - //- v-icon(left) mdi-check - //- span {{$t('common.actions.apply')}} - //- v-flex.animated.fadeInUp(lg3, xs12) - //- v-toolbar( - //- color='blue darken-2' - //- dense - //- flat - //- dark - //- ) - //- .subtitle-1 Pipeline - //- v-expansion-panels.adm-rendering-pipeline( - //- v-model='selectedCore' - //- accordion - //- mandatory - //- ) - //- v-expansion-panel( - //- v-for='core in renderers' - //- :key='core.key' - //- ) - //- v-expansion-panel-header( - //- hide-actions - //- ripple - //- ) - //- v-toolbar( - //- color='blue' - //- dense - //- dark - //- flat - //- ) - //- v-spacer - //- .body-2 {{core.input}} - //- v-icon.mx-2 mdi-arrow-right-circle - //- .caption {{core.output}} - //- v-spacer - //- v-expansion-panel-content - //- v-list.py-0(two-line, dense) - //- template(v-for='(rdr, n) in core.children') - //- v-list-item( - //- :key='rdr.key' - //- @click='selectRenderer(rdr.key)' - //- :class='currentRenderer.key === rdr.key ? ($vuetify.theme.dark ? `grey darken-4-l4` : `blue lighten-5`) : ``' - //- ) - //- v-list-item-avatar(size='24', tile) - //- v-icon(:color='currentRenderer.key === rdr.key ? "primary" : "grey"') {{rdr.icon}} - //- v-list-item-content - //- v-list-item-title {{rdr.title}} - //- v-list-item-subtitle: .caption {{rdr.description}} - //- v-list-item-avatar(size='24') - //- status-indicator(v-if='rdr.isEnabled', positive, pulse) - //- status-indicator(v-else, negative, pulse) - //- v-divider.my-0(v-if='n < core.children.length - 1') + .row.q-pa-md.q-col-gutter-md + .col-auto + q-card.rounded-borders.bg-dark + q-list( + style='min-width: 300px;' + padding + dark + ) + q-item( + v-for='rdr of state.renderers' + :key='rdr.key' + active-class='bg-primary text-white' + :active='state.selectedRenderer === rdr.id' + @click='state.selectedRenderer = rdr.id' + clickable + ) + q-item-section(side) + q-icon(:name='`img:` + rdr.icon') + q-item-section + q-item-label {{rdr.title}} + q-item-label(caption) {{rdr.description}} + q-item-section(side) + status-light(:color='rdr.isEnabled ? `positive` : `negative`', :pulse='rdr.isEnabled') + .col + .row.q-col-gutter-md + .col-12.col-lg - //- v-flex(lg9, xs12) - //- v-card.wiki-form.animated.fadeInUp - //- v-toolbar( - //- color='indigo' - //- dark - //- flat - //- dense - //- ) - //- v-icon.mr-2 {{currentRenderer.icon}} - //- .subtitle-1 {{currentRenderer.title}} - //- v-spacer - //- v-switch( - //- dark - //- color='white' - //- label='Enabled' - //- v-model='currentRenderer.isEnabled' - //- hide-details - //- inset - //- ) - //- v-card-info(color='blue') - //- div - //- div {{currentRenderer.description}} - //- span.caption: a(href='https://docs.requarks.io/en/rendering', target='_blank') Documentation - //- v-card-text.pb-4.pl-4 - //- .overline.mb-5 Rendering Module Configuration - //- .body-2.ml-3(v-if='!currentRenderer.config || currentRenderer.config.length < 1'): em This rendering module has no configuration options you can modify. - //- template(v-else, v-for='(cfg, idx) in currentRenderer.config') - //- v-select( - //- v-if='cfg.value.type === "string" && cfg.value.enum' - //- outlined - //- :items='cfg.value.enum' - //- :key='cfg.key' - //- :label='cfg.value.title' - //- v-model='cfg.value.value' - //- :hint='cfg.value.hint ? cfg.value.hint : ""' - //- persistent-hint - //- :class='cfg.value.hint ? "mb-2" : ""' - //- color='indigo' - //- ) - //- v-switch( - //- v-else-if='cfg.value.type === "boolean"' - //- :key='cfg.key' - //- :label='cfg.value.title' - //- v-model='cfg.value.value' - //- color='indigo' - //- :hint='cfg.value.hint ? cfg.value.hint : ""' - //- persistent-hint - //- inset - //- ) - //- v-text-field( - //- v-else - //- outlined - //- :key='cfg.key' - //- :label='cfg.value.title' - //- v-model='cfg.value.value' - //- :hint='cfg.value.hint ? cfg.value.hint : ""' - //- persistent-hint - //- :class='cfg.value.hint ? "mb-2" : ""' - //- color='indigo' - //- ) - //- v-divider.my-5(v-if='idx < currentRenderer.config.length - 1') - //- v-card-chin - //- v-spacer - //- .caption.pr-3.grey--text Module: {{ currentRenderer.key }} - +import { useI18n } from 'vue-i18n' +import { useMeta, useQuasar } from 'quasar' +import { computed, onMounted, reactive, watch } from 'vue' + +import { useAdminStore } from 'src/stores/admin' +import { useSiteStore } from 'src/stores/site' + +// QUASAR + +const $q = useQuasar() + +// STORES + +const adminStore = useAdminStore() +const siteStore = useSiteStore() + +// I18N + +const { t } = useI18n() - + +async function save () { + +} + + diff --git a/ux/src/router/routes.js b/ux/src/router/routes.js index 74a60f91..2048434b 100644 --- a/ux/src/router/routes.js +++ b/ux/src/router/routes.js @@ -51,7 +51,7 @@ const routes = [ { path: 'icons', component: () => import('pages/AdminIcons.vue') }, { path: 'instances', component: () => import('pages/AdminInstances.vue') }, { path: 'mail', component: () => import('pages/AdminMail.vue') }, - // { path: 'rendering', component: () => import('pages/AdminRendering.vue') }, + { path: 'rendering', component: () => import('pages/AdminRendering.vue') }, { path: 'scheduler', component: () => import('pages/AdminScheduler.vue') }, { path: 'security', component: () => import('pages/AdminSecurity.vue') }, { path: 'system', component: () => import('pages/AdminSystem.vue') },