aardio 文档

aardio 范例: WebView2 - ACE(Markdown)编辑器

import string.markdown;
import web.form.simpleMarkdown;
import fonts.fontAwesome;
import win.ui;
/*DSG{{*/
var mainForm = win.form(text="WebView2 - ACE(Markdown)编辑器";right=966;bottom=622)
mainForm.add(
btnClear={cls="plus";text="清空";left=122;top=586;right=202;bottom=616;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF26B';notify=1;textPadding={left=25};z=3};
btnPaster={cls="plus";text="粘贴";left=190;top=586;right=270;bottom=616;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF26B';notify=1;textPadding={left=25};z=4};
btnPreview={cls="plus";text="预览";left=841;top=586;right=921;bottom=616;align="left";color=0x3C3C3C;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF26B';notify=1;textPadding={left=25};z=2};
btnPrint={cls="plus";text="打印";left=752;top=586;right=832;bottom=616;align="left";color=0x3C3C3C;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF26B';notify=1;textPadding={left=25};z=5};
custom={cls="custom";text="自定义控件";left=0;top=0;right=967;bottom=581;db=1;dl=1;dr=1;dt=1;z=1}
)
/*}}*/

import web.view;
var wb = web.view(mainForm.custom);

var isMarkdown = function(text){
    if(!#text) return false;

    var patterns = {
        "^\s*\#+\s+"; // 标题
        "^\s*[\*\-\+]\s+"; // 无序列表
        "^\s*\d+\.\s+"; // 有序列表
        "\<```\>|\<`\>"; // 代码块或行内代码
        "\[.+\]\(.+\)"; // 链接
        "\*\*.+\*\*"; // 加粗
        "^\s*\>\s+"; // 引用
        "^\s*\|.+\|"; // 表格
    };

    for(i=1;#patterns;1){
        if(string.match(text,patterns[i])) return true;
    }

    return false;
}

import win.clip;
var clipText = win.clip.read();

if( isMarkdown(clipText) ){
   wb.markdown = clipText
}
else{
   wb.markdown = "> 在剪贴板未检测到 Markdown 格式文本,请手动输入"   
}

wb.html = /********
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ace Editor 示例</title>
<style type="text/css" media="screen">
    #editor {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
    }
</style>
<!-- 引入 Ace Editor -->
<script src="https://registry.npmmirror.com/ace-builds/1.43.6/files/src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
<!-- 引入主题文件 -->
<script src="https://registry.npmmirror.com/ace-builds/1.43.6/files/src-min-noconflict/theme-github.js"></script>
<!-- 引入语言模式文件 -->
<script src="https://registry.npmmirror.com/ace-builds/1.43.6/files/src-min-noconflict/mode-markdown.js"></script>
<script>

//在网页加载后执行代码
document.addEventListener('DOMContentLoaded', function() {
    window.editor = ace.edit("editor");
    editor.setTheme("ace/theme/chrome");
    editor.session.setMode("ace/mode/markdown");
    editor.setTheme("ace/theme/github");
})
</script>
</head>
<body id="editor">
<? =owner.markdown ?>
</body>

</html>
********/

import string.html;
var markdownToHTML = function(md){

    md = ..string.replaceUnmatched(md 
        ,"<$[""'`$]?![^$]+$>|<$$[^$]+$$>|<%<\\\(><\\\)>>|<%<\\\[><\\]>>"
        ,function(text){
            var t,e = ..string.match(text,"^(<<\\\[>|<\\\(>|<$$>|$>)(.+)<<\\\]>|<\\\)>|<$$>|$>$");
            if(#e){
                var displayMode = t=='[' || t =='$$'; 
                if(displayMode) return `<div class="katex">` + ..string.html.escape(e) + `</div>` 
                return `<span class="katex">` + ..string.html.escape(e) + `</span>`
            }

        }
        ,"!\N([ \t]*)(```+)<\a\w+>?(.+?)!\N\s*\2![^`\S]"
        ,"%``"
        ,"\<script!\W[^\>]*\>.*?\<\/script\>"
        ,`(["'])\s*javascript\:.+?\1`
    );

    var html = /***
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta http-equiv='content-language' content='zh-cn'>
    <link rel="stylesheet" href="https://registry.npmmirror.com/github-markdown-css/5.9.0/files/github-markdown.css">
    <link rel="stylesheet" href="https://lib.baomitu.com/KaTeX/latest/katex.min.css">
    <script src="https://lib.baomitu.com/KaTeX/latest/katex.min.js"></script>

    <link rel="stylesheet" href="https://lib.baomitu.com/prism/1.30.0/themes/prism.min.css">
    <script src="https://lib.baomitu.com/prism/1.30.0/prism.js"></script>
    <script src="https://lib.baomitu.com/prism/1.30.0/components/prism-javascript.min.js"></script>
    <script src="https://lib.baomitu.com/prism/1.30.0/components/prism-python.min.js"></script>
    <script src="https://lib.baomitu.com/prism/1.30.0/components/prism-go.min.js"></script>
    <script src="https://lib.baomitu.com/prism/1.30.0/components/prism-c.min.js"></script>
    <script src="https://lib.baomitu.com/prism/1.30.0/components/prism-markup.min.js"></script>
    <script>

    document.addEventListener('DOMContentLoaded', function () {
    Prism.languages.aardio = Prism.languages.extend('clike', {
        'class-name': [
            Prism.languages.clike['class-name']
        ],
        'keyword': {
            pattern: /(^|[^.])\b(?:begin|end|if|lambda|λ|else|elseif|class|function|return|while|do|namespace|select|case|catch|try|for|in|this|global|self|owner|var|def|null|and|not|or|break|continue|import|with|ctor|eval|type|assert|assert2|assertf|error|rget|callex|errput|loadcode|dumpcode|collectgarbage|call|invoke|tostring|topointer|tonumber|sleep|execute|setlocale|setprivilege|loadcodex|reduce|switch)\b/,
            lookbehind: true
        },
        'string': {
            pattern: /"(?:[^"]|"")*"|`(?:[^`]|``)*`|'(?:[^'\\]|\\.)*'/,
            greedy: true
        },
        'boolean': /\b(?:true|false)\b/,
        'function': /\b[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/,
        'number': /\b0x[a-fA-F_\d]+(?:\.[a-fA-F_\d]*)?(?:p[+-]?\d[_\d]*)?\b|\b\d+#[\d_]+\b|\b\d[_\d]*(?:\.\B|(?:\.[_\d]*)?(?:e[+-]?\d[_\d]*)?\b)|\B\.\d[_\d]*(?:e[+-]?\d[_\d]*)?\b/i,

        'operator': /\.\.|--|\+\+|\*\*=?|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|[~:?]/,
        'comment': [
            {
                pattern: /(^|[^\\])\/(\*+)(?:[\s\S]*?[^*])?\2\//,
                lookbehind: true
            },
            {
                pattern: /(^|[^\\:])\/\/.*/,
                lookbehind: true
            }
        ]
    });

    Prism.languages.aardio['class-name'][0].pattern = /(\b(?:class)\s+)[\w.\\]+/;
    Prism.languages.insertBefore('aardio', 'keyword', {
        'constant': /\b_[a-zA-Z]\w*\b/,
    }); 

    Prism.highlightAll();  

    document.querySelectorAll('div.katex').forEach(el => {

        try {
            katex.render(el.textContent, el, {
            displayMode: true,
            throwOnError: false
            });
        } catch (err) {
            console.error('KaTeX rendering error:', err);
        }
    });

    document.querySelectorAll('span.katex').forEach(el => { 
        try {
            katex.render(el.textContent, el, {
            displayMode: false,
            throwOnError: false
            });
        } catch (err) {
            console.error('KaTeX rendering error:', err);
        }
    });
    })
    </script>
    </head>
    <body class="markdown-body" style="margin:20px" id="markdown-body">
    ***/


    var markdownRenderer = string.markdown();
    return html ++ markdownRenderer.render(md);
}

mainForm.btnPreview.oncommand = function(id,event){

    var markdown = wb.xcall("editor.getValue")

    import web.view;
    var frmPreview = win.form(text="WebView2 - Markdown 预览,支持数学公式、高亮代码块,右键菜单可打印";parent=mainForm;right=966;bottom=622)
    var wb = web.view(frmPreview);

    wb.html = markdownToHTML(markdown);
    frmPreview.show();
}

mainForm.btnPrint.oncommand = function(id,event){
    mainForm.btnPrint.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']

    //WebView2 加载用户配置
    var userDataDir = ..io.appData("aardio/example/web-view-ace-markdown-print-direct/");
    var preferences,path = web.view.loadPreferences(userDataDir);
    var appState = table.get("printing.print_preview_sticky_settings.appState",preferences)

    //获取与修改打印设置
    var printAppState = JSON.tryParse(appState) //不存在会返回 NULL 值
    printAppState = table.assignDeep(printAppState , {
        "version":2,
        "duplexType":"LONG_EDGE",
        "mediaSize":{"height_microns":297000,"width_microns":210000},
        "marginsType":0,
        "customMargins":{"marginTop":72,"marginRight":72,"marginBottom":72,"marginLeft":72},
        "isColorEnabled":true,
        "isHeaderFooterEnabled":false,
        "isLandscapeEnabled":false,
        "isCollateEnabled":true,
        "isCssBackgroundEnabled":false,
        "scaling":"100"
    });

    //保存打印机设置
    printAppState = JSON.stringify(printAppState)
    table.set("printing.print_preview_sticky_settings.appState",printAppState,preferences)
    JSON.save(path,preferences,false);//保存,不需要格式化

    var markdown = wb.xcall("editor.getValue")

    import web.view;
    var wb = web.view(,{
        startArguments =  ["--kiosk-printing","--use-system-default-printer"];
        userDataDir = userDataDir;
    })

    wb.html = markdownToHTML(markdown);
    wb.wait();
    wb.xcall("print");  

    thread.delay(5000);
    wb.closeAndWait();
    mainForm.btnPrint.disabledText = null;
}

mainForm.btnClear.oncommand = function(id,event){
    wb.invoke("editor.setValue","") 
}

import win.clip;
mainForm.btnPaster.oncommand = function(id,event){
    var text = win.clip.read();

    if(#text) {
        wb.invoke("editor.insert",text) 
    }   
}

var style = {
    button = {
        color={
            active=0xFF00FF00;
            default=0xFF3C3C3C;
            disabled=0xFF6D6D6D;
            hover=0xFFFF0000        
        }
    }
}

mainForm.btnPaster.skin(style.button)
mainForm.btnPrint.skin(style.button)
mainForm.btnPreview.skin(style.button)
mainForm.btnClear.skin(style.button)

mainForm.show();
win.loopMessage();
Markdown 格式