1
This commit is contained in:
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/*!
|
||||
Theme: Default
|
||||
Description: Original highlight.js style
|
||||
Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
|
||||
Maintainer: @highlightjs/core-team
|
||||
Website: https://highlightjs.org/
|
||||
License: see project LICENSE
|
||||
Touched: 2021
|
||||
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:6rpx 10rpx}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 2rpx solid #ddd;
|
||||
}
|
||||
|
||||
tr {
|
||||
text-align: center;
|
||||
border: 2rpx solid #ddd;
|
||||
}
|
||||
|
||||
/* 表格隔行变色 */
|
||||
tr:nth-child(even) {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 2rpx solid #ddd;
|
||||
padding: 8rpx 16rpx;
|
||||
font-size:31.4rpx;
|
||||
}
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,283 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link href="./css/qulliCore.css" type="text/css" rel="stylesheet" />
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#layout,
|
||||
#layout:focus,
|
||||
.ql-editor,
|
||||
.ql-editor:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ql-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ql-align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ql-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ql-size-medium {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="layout">
|
||||
|
||||
</div>
|
||||
<script src="./js/uni.webview.1.5.5.js"></script>
|
||||
<script src="./js/marked.min.js"></script>
|
||||
<script src="./js/quill.js"></script>
|
||||
<script type="text/javascript">
|
||||
// 3. 注册自定义格式
|
||||
const Inline = Quill.import('blots/inline');
|
||||
|
||||
class FontSizeBlot extends Inline {
|
||||
static create(value) {
|
||||
let node = super.create();
|
||||
node.style.fontSize = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
static formats(node) {
|
||||
return node.style.fontSize;
|
||||
}
|
||||
}
|
||||
|
||||
FontSizeBlot.blotName = 'size';
|
||||
|
||||
Quill.register(FontSizeBlot);
|
||||
|
||||
var quill = new Quill('#layout', {
|
||||
modules: {
|
||||
toolbar: false // 不使用默认主题的工具栏
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
var testEditormdView;
|
||||
|
||||
function getBodyHeight() {
|
||||
var targetDiv = document.body.querySelector("#layout")
|
||||
var height = targetDiv.scrollHeight
|
||||
// document.body.style.height = (height) + 'px'
|
||||
window.parent.postMessage({
|
||||
action: 'offsetHeight',
|
||||
data: height + 5,
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'offsetHeight',
|
||||
data: height
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var targetDiv = document.querySelector("#layout")
|
||||
// 创建一个观察者对象并传入回调函数
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.type === 'childList' || mutation.type === 'attributes') {
|
||||
getBodyHeight()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 配置观察选项:
|
||||
var config = {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
subtree: true
|
||||
};
|
||||
|
||||
// 选择需要观察变动的节点
|
||||
observer.observe(targetDiv, config);
|
||||
|
||||
function getValueContentFormt(nr, isHtml) {
|
||||
var content = ''
|
||||
|
||||
if (typeof nr == 'string') {
|
||||
var cto = JSON.parse(nr);
|
||||
if (cto.render == 'android') {
|
||||
content = decodeURIComponent(atob(cto.value))
|
||||
} else {
|
||||
content = decodeURIComponent(cto.value)
|
||||
}
|
||||
} else {
|
||||
if (nr.render == 'android') {
|
||||
content = decodeURIComponent(atob(nr.value))
|
||||
} else {
|
||||
content = decodeURIComponent(nr.value)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isHtml) {
|
||||
try {
|
||||
content = marked.parse(content)
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
function markdown(nr, isHtml) {
|
||||
var length = this.quill.getLength();
|
||||
|
||||
// 删除所有现有内容并在位置0插入新内容
|
||||
quill.deleteText(0, length);
|
||||
quill.clipboard.dangerouslyPasteHTML(0, getValueContentFormt(nr, isHtml))
|
||||
// quill.root.innerHTML = getValueContentFormt(nr, isHtml)
|
||||
}
|
||||
|
||||
function setBodyStyle(stylenr, isHtml) {
|
||||
targetDiv.style = stylenr;
|
||||
|
||||
}
|
||||
|
||||
function getHtml() {
|
||||
window.parent.postMessage({
|
||||
action: 'toValue',
|
||||
data: quill.root.innerHTML,
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'toValue',
|
||||
data: quill.root.innerHTML
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setSelectedStyle(nr, isHtml) {
|
||||
|
||||
var data = JSON.parse(getValueContentFormt(nr, isHtml))
|
||||
var key = data.key.toLowerCase()
|
||||
var value = data.value;
|
||||
|
||||
var eobj = {
|
||||
'b': 'bold', //true,false
|
||||
'i': 'italic', //true,false
|
||||
's': 'strike', //true,false
|
||||
'u': 'underline', //true,false
|
||||
'link': 'link',
|
||||
'img': 'image',
|
||||
'video': 'video',
|
||||
'align': 'align', //left,right,center
|
||||
/**
|
||||
* ordered:有序列表(编号列表)
|
||||
* bullet:无序列表(项目符号列表)
|
||||
* unchecked:未选中的复选框列表项
|
||||
* checked:选中的复选框列表项
|
||||
*/
|
||||
'list': 'list',
|
||||
'blockquote': 'blockquote', //true,false
|
||||
'indent': 'indent', //缩进值0-8
|
||||
'color': 'color',
|
||||
'background': 'background',
|
||||
'size': 'size',
|
||||
'script': 'script', //super,sub
|
||||
'header': 'header', //1-6
|
||||
}
|
||||
var range = quill.getSelection();
|
||||
if (range) {
|
||||
var currentFormat = quill.getFormat(range.index, range.length);
|
||||
var styleforamtvalue = value;
|
||||
var foramtStyleName = eobj[key]
|
||||
if (
|
||||
(foramtStyleName == 'header' && styleforamtvalue == 0) ||
|
||||
(foramtStyleName == 'size' && styleforamtvalue == '') ||
|
||||
foramtStyleName == 'align' && (styleforamtvalue == '' || styleforamtvalue == 'left')
|
||||
) {
|
||||
styleforamtvalue = false;
|
||||
}
|
||||
|
||||
console.log(foramtStyleName, styleforamtvalue)
|
||||
quill.format(foramtStyleName, styleforamtvalue);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
quill.on('selection-change', function() {
|
||||
var range = quill.getSelection();
|
||||
if (!range) return;
|
||||
var format = quill.getFormat(range);
|
||||
|
||||
var fontStyleOpts = {
|
||||
img: format['image'] ? format['image'] : '',
|
||||
link: format['link'] ? format['link'] : '',
|
||||
b: format['bold'] === true,
|
||||
i: format['italic'] === true,
|
||||
s: format['strike'] === true,
|
||||
u: format['underline'] === true,
|
||||
align: format['align'] ? format['align'] : 'left',
|
||||
list: format['list'] ? format['list'] : '',
|
||||
indent: format['indent'] ? format['indent'] : 0,
|
||||
header: format['header'] ? format['header'] : 0,
|
||||
size: format['size'] ? format['size'] : 0,
|
||||
color: format['color'] ? format['color'] : '',
|
||||
background: format['background'] ? format['background'] : '',
|
||||
}
|
||||
|
||||
window.parent.postMessage({
|
||||
action: 'fontStyleOpts',
|
||||
data: fontStyleOpts,
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'fontStyleOpts',
|
||||
data: fontStyleOpts
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
// 在iframe内部执行以下代码
|
||||
var frameElement = window.frameElement;
|
||||
var iframeId = frameElement == null ? "" : frameElement.getAttribute('id');
|
||||
// 等待初始化完毕
|
||||
document.addEventListener('UniAppJSBridgeReady', () => {
|
||||
window.parent.postMessage({
|
||||
action: 'onJSBridgeReady',
|
||||
data: '',
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'onJSBridgeReady'
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+45
File diff suppressed because one or more lines are too long
@@ -0,0 +1,195 @@
|
||||
|
||||
var iframeId = new URLSearchParams(window.location.search).get('id')||Math.random().toString(16).substring(4)
|
||||
|
||||
// 等待初始化完毕
|
||||
document.addEventListener('UniAppJSBridgeReady', function(){
|
||||
window.parent.postMessage({
|
||||
action: 'onJSBridgeReady',
|
||||
data: '',
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'onJSBridgeReady'
|
||||
}
|
||||
})
|
||||
})
|
||||
// window.addEventListener('message', function(event) {
|
||||
|
||||
// // 根据消息内容执行相应的操作或调用函数
|
||||
// if (typeof event.data === 'object' && event.data.action === 'callFunctionInIframe') {
|
||||
// var data = event.data.data;
|
||||
// myFunctionInIframe(data);
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
var qr = null
|
||||
// 绘制二维码。
|
||||
//https://github.com/soldair/node-qrcode?tab=readme-ov-file#createtext-options
|
||||
function createQrcode(size, foreground, background, text, logo, logoSize, padding) {
|
||||
// let width = window.frameElement.offsetWidth
|
||||
// let height = window.frameElement.offsetHeight
|
||||
var canvas = document.getElementById("qrcode")
|
||||
// canvas.width=width
|
||||
// canvas.height=height
|
||||
// canvas.style.width=width+'px'
|
||||
// canvas.style.height=height+'px'
|
||||
canvas.style.display = "block"
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
document.body.style.overflow = "hidden"
|
||||
document.body.style.height = "100%"
|
||||
size = size || 128;
|
||||
padding = padding || 2
|
||||
QRCode.toCanvas(canvas, text || 'xui', {
|
||||
element: canvas,
|
||||
width: size,
|
||||
errorCorrectionLevel: 'H',
|
||||
margin: padding,
|
||||
color: {
|
||||
dark: foreground || "black",
|
||||
light: background || "white"
|
||||
}
|
||||
})
|
||||
if (logo) {
|
||||
let ctx = canvas.getContext("2d");
|
||||
let img = new Image();
|
||||
logoSize = logoSize || 50
|
||||
img.width = logoSize + "px"
|
||||
img.height = logoSize + "px"
|
||||
img.src = logo
|
||||
img.onload = function() {
|
||||
let x = (size - logoSize) / 2
|
||||
let y = x;
|
||||
ctx.drawImage(img, x, y, logoSize, logoSize)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//获取二维码图片。
|
||||
function QrcodeToDateUrl() {
|
||||
if (qr) {
|
||||
let imgdata = qr.toDataURL();
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'img',
|
||||
url: imgdata
|
||||
}
|
||||
})
|
||||
} else {
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'error',
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var ect = null;
|
||||
|
||||
function getchart() {
|
||||
if (ect) return ect;
|
||||
let dom = document.getElementById('echart');
|
||||
return echarts.init(dom);
|
||||
}
|
||||
|
||||
function chart_setSize() {
|
||||
let width = window.innerWidth
|
||||
let height = window.innerHeight
|
||||
let dom = document.getElementById('echart');
|
||||
let domhtml = document.getElement
|
||||
dom.style.width = width + 'px'
|
||||
dom.style.height = height + 'px'
|
||||
document.getElementsByTagName('html')[0].style = 'overflow:hidden'
|
||||
}
|
||||
|
||||
// 解码 JSON 字符串(包括深层解码)
|
||||
function decodeJSON(jsonString) {
|
||||
// 如果输入不是字符串,直接返回
|
||||
if (typeof jsonString !== 'string') {
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
const obj = JSON.parse(jsonString,function(k,v){
|
||||
// 处理常规函数定义,包括多行函数 "key": function(params) { ... }
|
||||
var isFunctionStr =
|
||||
// 常规函数
|
||||
/^\s*function\s*\([^)]*\)\s*\{[\s\S]*\}\s*$/.test(v) ||
|
||||
// 箭头函数 - 带花括号
|
||||
/^\s*\([^)]*\)\s*=>\s*\{[\s\S]*\}\s*$/.test(v) ||
|
||||
// 箭头函数 - 简写形式
|
||||
/^\s*\([^)]*\)\s*=>\s*[^{\s][\s\S]*$/.test(v) ||
|
||||
// 单参数箭头函数 - 无括号
|
||||
/^\s*[a-zA-Z0-9_$]+\s*=>\s*[^{\s][\s\S]*$/.test(v) ||
|
||||
// 单参数箭头函数 - 带花括号
|
||||
/^\s*[a-zA-Z0-9_$]+\s*=>\s*\{[\s\S]*\}\s*$/.test(v);
|
||||
|
||||
|
||||
if(typeof v === 'string' && isFunctionStr){
|
||||
v = eval('('+v+')')
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
function chart_setOption(optionStr) {
|
||||
chart_setSize()
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
let chart = getchart();
|
||||
if (!optionStr) return;
|
||||
try {
|
||||
|
||||
let option = decodeJSON(optionStr)
|
||||
|
||||
chart.setOption(option)
|
||||
} catch (error) {
|
||||
alert(error)
|
||||
}
|
||||
}
|
||||
|
||||
function chart_call(funName, optionStr, eventsid) {
|
||||
|
||||
chart_setSize()
|
||||
let filterevents = ["click"]
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
let chart = getchart();
|
||||
|
||||
if (filterevents.includes(funName)) {
|
||||
|
||||
chart['on'](funName, function(params) {
|
||||
delete params.event
|
||||
window.parent.postMessage({
|
||||
action: funName,
|
||||
eventId: eventsid,
|
||||
data: JSON.stringify(params),
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: funName,
|
||||
eventId: eventsid,
|
||||
data: JSON.stringify(params)
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
} else {
|
||||
|
||||
try {
|
||||
let option = JSON.parse(optionStr)
|
||||
chart[funName](option)
|
||||
} catch (e) {
|
||||
chart[funName]()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Vendored
+1004
File diff suppressed because one or more lines are too long
+19092
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
||||
|
||||
function markedHighlight(options) {
|
||||
if (typeof options === 'function') {
|
||||
options = {
|
||||
highlight: options,
|
||||
};
|
||||
}
|
||||
|
||||
if (!options || typeof options.highlight !== 'function') {
|
||||
throw new Error('Must provide highlight function');
|
||||
}
|
||||
|
||||
if (typeof options.langPrefix !== 'string') {
|
||||
options.langPrefix = 'language-';
|
||||
}
|
||||
|
||||
if (typeof options.emptyLangClass !== 'string') {
|
||||
options.emptyLangClass = '';
|
||||
}
|
||||
|
||||
return {
|
||||
async: !!options.async,
|
||||
walkTokens(token) {
|
||||
if (token.type !== 'code') {
|
||||
return;
|
||||
}
|
||||
|
||||
const lang = getLang(token.lang);
|
||||
|
||||
if (options.async) {
|
||||
return Promise.resolve(options.highlight(token.text, lang, token.lang || '')).then(
|
||||
updateToken(token));
|
||||
}
|
||||
|
||||
const code = options.highlight(token.text, lang, token.lang || '');
|
||||
if (code instanceof Promise) {
|
||||
throw new Error(
|
||||
'markedHighlight is not set to async but the highlight function is async. Set the async option to true on markedHighlight to await the async highlight function.'
|
||||
);
|
||||
}
|
||||
updateToken(token)(code);
|
||||
},
|
||||
useNewRenderer: true,
|
||||
renderer: {
|
||||
code(code, infoString, escaped) {
|
||||
// istanbul ignore next
|
||||
if (typeof code === 'object') {
|
||||
escaped = code.escaped;
|
||||
infoString = code.lang;
|
||||
code = code.text;
|
||||
}
|
||||
const lang = getLang(infoString);
|
||||
const classValue = lang ? options.langPrefix + escape(lang) : options.emptyLangClass;
|
||||
const classAttr = classValue ?
|
||||
` class="${classValue}"` :
|
||||
'';
|
||||
code = code.replace(/\n$/, '');
|
||||
return `<pre><code${classAttr}>${escaped ? code : escape(code, true)}\n</code></pre>`;
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getLang(lang) {
|
||||
return (lang || '').match(/\S*/)[0];
|
||||
}
|
||||
|
||||
function updateToken(token) {
|
||||
return (code) => {
|
||||
if (typeof code === 'string' && code !== token.text) {
|
||||
token.escaped = true;
|
||||
token.text = code;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// copied from marked helpers
|
||||
const escapeTest = /[&<>"']/;
|
||||
const escapeReplace = new RegExp(escapeTest.source, 'g');
|
||||
const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
|
||||
const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
|
||||
const escapeReplacements = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
};
|
||||
const getEscapeReplacement = (ch) => escapeReplacements[ch];
|
||||
|
||||
function escape(html, encode) {
|
||||
if (encode) {
|
||||
if (escapeTest.test(html)) {
|
||||
return html.replace(escapeReplace, getEscapeReplacement);
|
||||
}
|
||||
} else {
|
||||
if (escapeTestNoEncode.test(html)) {
|
||||
return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('katex')) :
|
||||
typeof define === 'function' && define.amd ? define(['katex'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.markedKatex = factory(global.katex));
|
||||
})(this, (function (katex) { 'use strict';
|
||||
|
||||
const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
|
||||
const inlineRuleNonStandard = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1/; // Non-standard, even if there are no spaces before and after $ or $$, try to parse
|
||||
|
||||
const blockRule = /^(\${1,2})\n((?:\\[^]|[^\\])+?)\n\1(?:\n|$)/;
|
||||
|
||||
function index(options = {}) {
|
||||
return {
|
||||
extensions: [
|
||||
inlineKatex(options, createRenderer(options, false)),
|
||||
blockKatex(options, createRenderer(options, true)),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function createRenderer(options, newlineAfter) {
|
||||
return (token) => katex.renderToString(token.text, { ...options, displayMode: token.displayMode }) + (newlineAfter ? '\n' : '');
|
||||
}
|
||||
|
||||
function inlineKatex(options, renderer) {
|
||||
const nonStandard = options && options.nonStandard;
|
||||
const ruleReg = nonStandard ? inlineRuleNonStandard : inlineRule;
|
||||
return {
|
||||
name: 'inlineKatex',
|
||||
level: 'inline',
|
||||
start(src) {
|
||||
let index;
|
||||
let indexSrc = src;
|
||||
|
||||
while (indexSrc) {
|
||||
index = indexSrc.indexOf('$');
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
const f = nonStandard ? index > -1 : index === 0 || indexSrc.charAt(index - 1) === ' ';
|
||||
if (f) {
|
||||
const possibleKatex = indexSrc.substring(index);
|
||||
|
||||
if (possibleKatex.match(ruleReg)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, '');
|
||||
}
|
||||
},
|
||||
tokenizer(src, tokens) {
|
||||
const match = src.match(ruleReg);
|
||||
if (match) {
|
||||
return {
|
||||
type: 'inlineKatex',
|
||||
raw: match[0],
|
||||
text: match[2].trim(),
|
||||
displayMode: match[1].length === 2,
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer,
|
||||
};
|
||||
}
|
||||
|
||||
function blockKatex(options, renderer) {
|
||||
return {
|
||||
name: 'blockKatex',
|
||||
level: 'block',
|
||||
tokenizer(src, tokens) {
|
||||
const match = src.match(blockRule);
|
||||
if (match) {
|
||||
return {
|
||||
type: 'blockKatex',
|
||||
raw: match[0],
|
||||
text: match[2].trim(),
|
||||
displayMode: match[1].length === 2,
|
||||
};
|
||||
}
|
||||
},
|
||||
renderer,
|
||||
};
|
||||
}
|
||||
|
||||
return index;
|
||||
|
||||
}));
|
||||
@@ -0,0 +1,242 @@
|
||||
|
||||
function extendedTables({
|
||||
interruptPatterns = [],
|
||||
skipEmptyRows = true
|
||||
} = {}) {
|
||||
return {
|
||||
extensions: [{
|
||||
name: 'spanTable',
|
||||
level: 'block', // Is this a block-level or inline-level tokenizer?
|
||||
start(src) {
|
||||
return src.match(/\n *([^\n ].*\|.*)\n/m)?.index;
|
||||
}, // Hint to Marked.js to stop and check for a match
|
||||
tokenizer(src, tokens) {
|
||||
// const regex = this.tokenizer.rules.block.table;
|
||||
let regexString = '^ *([^\\n ].*\\|.*\\n(?: *[^\\s].*\\n)*?)' // Header
|
||||
+
|
||||
' {0,3}(?:\\| *)?(:?-+(?: *(?:100|[1-9][0-9]?%) *-+)?:? *(?:\\| *:?-+(?: *(?:100|[1-9][0-9]?%) *-+)?:? *)*)(?:\\| *)?' // Align
|
||||
+
|
||||
'(?:\\n((?:(?! *\\n| {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})' // Cells
|
||||
+
|
||||
'(?:\\n+|$)| {0,3}#{1,6}(?:\\s|$)| {0,3}>| {4}[^\\n]| {0,3}(?:`{3,}' +
|
||||
'(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n| {0,3}(?:[*+-]|1[.)]) |' +
|
||||
'<\\/?(?:address|article|aside|base|basefont|blockquote|body' +
|
||||
'|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt' +
|
||||
'|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]' +
|
||||
'|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem' +
|
||||
'|meta|nav|noframes|ol|optgroup|option|p|param|section|source' +
|
||||
'|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)' +
|
||||
'(?: +|\\n|\\/?>)|<(?:script|pre|style|textarea|!--)endRegex).*(?:\\n|$))*)\\n*|$)'; // Cells
|
||||
|
||||
regexString = regexString.replace('endRegex', interruptPatterns.map(str =>
|
||||
`|(?:${str})`).join(''));
|
||||
const widthRegex = / *(?:100|[1-9][0-9]?%) */g;
|
||||
const regex = new RegExp(regexString);
|
||||
const cap = regex.exec(src);
|
||||
|
||||
if (cap) {
|
||||
const item = {
|
||||
type: 'spanTable',
|
||||
header: cap[1].replace(/\n$/, '').split('\n'),
|
||||
align: cap[2].replace(widthRegex, '').replace(/^ *|\| *$/g, '').split(
|
||||
/ *\| */),
|
||||
rows: cap[3]?.trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : [],
|
||||
width: cap[2].replace(/:/g, '').replace(/-+| /g, '').split('|')
|
||||
};
|
||||
|
||||
// Get first header row to determine how many columns
|
||||
item.header[0] = splitCells(item.header[0]);
|
||||
|
||||
const colCount = item.header[0].reduce((length, header) => {
|
||||
return length + header.colspan;
|
||||
}, 0);
|
||||
|
||||
if (colCount === item.align.length) {
|
||||
item.raw = cap[0];
|
||||
|
||||
let i, j, k, row;
|
||||
|
||||
// Get alignment row (:---:)
|
||||
let l = item.align.length;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
if (/^ *-+: *$/.test(item.align[i])) {
|
||||
item.align[i] = 'right';
|
||||
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
||||
item.align[i] = 'center';
|
||||
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
||||
item.align[i] = 'left';
|
||||
} else {
|
||||
item.align[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get any remaining header rows
|
||||
l = item.header.length;
|
||||
for (i = 1; i < l; i++) {
|
||||
item.header[i] = splitCells(item.header[i], colCount, item.header[i -
|
||||
1], skipEmptyRows);
|
||||
}
|
||||
|
||||
// Get main table cells
|
||||
l = item.rows.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
item.rows[i] = splitCells(item.rows[i], colCount, item.rows[i - 1],
|
||||
skipEmptyRows);
|
||||
}
|
||||
|
||||
// header child tokens
|
||||
l = item.header.length;
|
||||
for (j = 0; j < l; j++) {
|
||||
row = item.header[j];
|
||||
for (k = 0; k < row.length; k++) {
|
||||
row[k].tokens = [];
|
||||
this.lexer.inline(row[k].text, row[k].tokens);
|
||||
}
|
||||
}
|
||||
|
||||
// cell child tokens
|
||||
l = item.rows.length;
|
||||
for (j = 0; j < l; j++) {
|
||||
row = item.rows[j];
|
||||
for (k = 0; k < row.length; k++) {
|
||||
row[k].tokens = [];
|
||||
this.lexer.inline(row[k].text, row[k].tokens);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
},
|
||||
renderer(token) {
|
||||
|
||||
let i, j, row, cell, col, text;
|
||||
let output = '<table>';
|
||||
output += '<thead>';
|
||||
for (i = 0; i < token.header.length; i++) {
|
||||
row = token.header[i];
|
||||
let col = 0;
|
||||
output += '<tr>';
|
||||
for (j = 0; j < row.length; j++) {
|
||||
cell = row[j];
|
||||
text = this.parser.parseInline(cell.tokens);
|
||||
output += getTableCell(text, cell, 'th', token.align[col], token.width[
|
||||
col]);
|
||||
col += cell.colspan;
|
||||
}
|
||||
output += '</tr>';
|
||||
}
|
||||
output += '</thead>';
|
||||
if (token.rows.length) {
|
||||
output += '<tbody>';
|
||||
for (i = 0; i < token.rows.length; i++) {
|
||||
row = token.rows[i];
|
||||
col = 0;
|
||||
if (!row[0].emptyRow) {
|
||||
output += '<tr>';
|
||||
for (j = 0; j < row.length; j++) {
|
||||
cell = row[j];
|
||||
text = this.parser.parseInline(cell.tokens);
|
||||
output += getTableCell(text, cell, 'td', token.align[col], token
|
||||
.width[col]);
|
||||
col += cell.colspan;
|
||||
}
|
||||
output += '</tr>';
|
||||
}
|
||||
}
|
||||
output += '</tbody>';
|
||||
}
|
||||
output += '</table>';
|
||||
return output;
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
const getTableCell = (text, cell, type, align, width) => {
|
||||
if (!cell.rowspan) {
|
||||
return '';
|
||||
}
|
||||
const tag = `<${type}` +
|
||||
`${cell.colspan > 1 ? ` colspan=${cell.colspan}` : ''}` +
|
||||
`${cell.rowspan > 1 ? ` rowspan=${cell.rowspan}` : ''}` +
|
||||
`${align ? ` align=${align}` : ''}` +
|
||||
`${width ? ` width=${width}` : ''}>`;
|
||||
return `${tag + text}</${type}>\n`;
|
||||
};
|
||||
|
||||
const splitCells = (tableRow, count, prevRow = [], skipEmptyRows) => {
|
||||
const cells = [...tableRow.trim().matchAll(/(?:[^|\\]|\\.?)+(?:\|+|$)/g)].map((x) => x[0]);
|
||||
|
||||
// Remove first/last cell in a row if whitespace only and no leading/trailing pipe
|
||||
if (!cells[0]?.trim()) {
|
||||
cells.shift();
|
||||
}
|
||||
if (!cells[cells.length - 1]?.trim()) {
|
||||
cells.pop();
|
||||
}
|
||||
|
||||
let numCols = 0;
|
||||
let i, j, trimmedCell, prevCell, prevCols;
|
||||
|
||||
for (i = 0; i < cells.length; i++) {
|
||||
trimmedCell = cells[i].split(/\|+$/)[0];
|
||||
cells[i] = {
|
||||
rowspan: 1,
|
||||
colspan: Math.max(cells[i].length - trimmedCell.length, 1),
|
||||
text: trimmedCell.trim().replace(/\\\|/g, '|')
|
||||
// display escaped pipes as normal character
|
||||
};
|
||||
|
||||
// Handle Rowspan
|
||||
if (trimmedCell.slice(-1) === '^' && prevRow.length) {
|
||||
// Find matching cell in previous row
|
||||
prevCols = 0;
|
||||
for (j = 0; j < prevRow.length; j++) {
|
||||
prevCell = prevRow[j];
|
||||
if ((prevCols === numCols) && (prevCell.colspan === cells[i].colspan)) {
|
||||
// merge into matching cell in previous row (the "target")
|
||||
cells[i].rowSpanTarget = prevCell.rowSpanTarget ?? prevCell;
|
||||
cells[i].rowSpanTarget.text += ` ${cells[i].text.slice(0, -1)}`;
|
||||
cells[i].rowSpanTarget.rowspan += 1;
|
||||
cells[i].rowspan = 0;
|
||||
break;
|
||||
}
|
||||
prevCols += prevCell.colspan;
|
||||
if (prevCols > numCols) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numCols += cells[i].colspan;
|
||||
}
|
||||
|
||||
// If all cells have been merged, flag as an empty row
|
||||
if (cells.length > 0 && skipEmptyRows && cells.length === cells.filter((cell) => {
|
||||
return cell.rowspan === 0;
|
||||
}).length) {
|
||||
cells[0].emptyRow = true;
|
||||
for (i = 0; i < cells.length; i++) {
|
||||
cells[i].rowSpanTarget.rowspan -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Force main cell rows to match header column count
|
||||
if (numCols > count) {
|
||||
cells.splice(count);
|
||||
} else {
|
||||
while (numCols < count) {
|
||||
cells.push({
|
||||
rowspan: 1,
|
||||
colspan: 1,
|
||||
text: ''
|
||||
});
|
||||
numCols += 1;
|
||||
}
|
||||
}
|
||||
return cells;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Vendored
+21
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<title>本地网页</title>
|
||||
</head>
|
||||
<style>
|
||||
body,html{
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width:100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<!-- html组件使用 -->
|
||||
<div id="html" style="overflow: auto;"></div>
|
||||
<!-- 给echart图表使用 -->
|
||||
<div id="echart" ></div>
|
||||
<script type="text/javascript" src="./js/uni.webview.1.5.5.js"></script>
|
||||
<script type="text/javascript" src="./js/echarts.min.js"></script>
|
||||
<script type="text/javascript" src="./js/handler.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,267 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link href="./css/default.min.css" type="text/css" rel="stylesheet" />
|
||||
<link href="./css/katex.min.css" type="text/css" rel="stylesheet" />
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
/* padding: 0;
|
||||
margin: 0; */
|
||||
}
|
||||
|
||||
p,
|
||||
h1,
|
||||
h3,
|
||||
h2,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="layout">
|
||||
|
||||
</div>
|
||||
|
||||
<script src="./js/uni.webview.1.5.5.js"></script>
|
||||
<script src="./js/highlight.min.js"></script>
|
||||
<script src="./js/marked-highlight.js"></script>
|
||||
<script src="./js/marked-tables.js"></script>
|
||||
<script src="./js/katex.js"></script>
|
||||
<script src="./js/marked.min.js"></script>
|
||||
<script src="./js/marked-katex-extension.js"></script>
|
||||
<script type="text/javascript">
|
||||
var md;
|
||||
|
||||
function getBodyHeight() {
|
||||
var targetDiv = document.body.querySelector("#layout")
|
||||
let height = targetDiv.scrollHeight
|
||||
document.body.style.height = (height) + 'px'
|
||||
window.parent.postMessage({
|
||||
action: 'offsetHeight',
|
||||
data: height + 5,
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'offsetHeight',
|
||||
data: height
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var targetDiv = document.querySelector("#layout")
|
||||
// 创建一个观察者对象并传入回调函数
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.type === 'childList' || mutation.type === 'attributes') {
|
||||
getBodyHeight()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 配置观察选项:
|
||||
var config = {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
subtree: true
|
||||
};
|
||||
|
||||
// 选择需要观察变动的节点
|
||||
observer.observe(targetDiv, config);
|
||||
|
||||
|
||||
// 监听 div 的点击事件
|
||||
targetDiv.addEventListener('click', function(event) {
|
||||
let attr = {
|
||||
text: "",
|
||||
attr: "",
|
||||
tag: ""
|
||||
}
|
||||
|
||||
// 检查点击的目标是否是 <a> 标签
|
||||
if (event.target.tagName === 'A') {
|
||||
// 阻止默认行为(如跳转)
|
||||
event.preventDefault();
|
||||
attr.text = event.target.textContent
|
||||
attr.attr = event.target.href
|
||||
attr.tag = "a"
|
||||
|
||||
} else if (event.target.tagName === 'IMG') {
|
||||
attr.attr = event.target.src
|
||||
attr.tag = "img"
|
||||
}
|
||||
if (attr.attr != '') {
|
||||
window.parent.postMessage({
|
||||
action: 'click',
|
||||
data: attr,
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'click',
|
||||
data: attr
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
function processMarkdown(markdown) {
|
||||
// 1. 分割成行
|
||||
const lines = markdown.split('\n');
|
||||
let inCodeBlock = false;
|
||||
let codeBlockIndentation = 0;
|
||||
let processedLines = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const trimmedLine = line.trimLeft();
|
||||
|
||||
// 检测代码块开始
|
||||
if (trimmedLine.startsWith('```')) {
|
||||
if (!inCodeBlock) {
|
||||
// 进入代码块
|
||||
inCodeBlock = true;
|
||||
// 记录代码块的缩进级别
|
||||
codeBlockIndentation = line.length - trimmedLine.length;
|
||||
// 移除开始标记的缩进
|
||||
processedLines.push(trimmedLine);
|
||||
} else {
|
||||
// 退出代码块
|
||||
inCodeBlock = false;
|
||||
// 移除结束标记的缩进
|
||||
processedLines.push(trimmedLine);
|
||||
}
|
||||
} else if (inCodeBlock) {
|
||||
// 代码块内的内容保持原有缩进
|
||||
processedLines.push(line);
|
||||
} else {
|
||||
// 非代码块内容保持不变
|
||||
processedLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return processedLines.join('\n');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function markdown(nr, isHtml) {
|
||||
let content = ''
|
||||
|
||||
if (typeof nr == 'string') {
|
||||
let cto = JSON.parse(nr);
|
||||
if (cto.render == 'android') {
|
||||
content = decodeURIComponent(atob(cto.value))
|
||||
} else {
|
||||
content = decodeURIComponent(cto.value)
|
||||
}
|
||||
} else {
|
||||
if (nr.render == 'android') {
|
||||
content = decodeURIComponent(atob(nr.value))
|
||||
} else {
|
||||
content = decodeURIComponent(nr.value)
|
||||
}
|
||||
}
|
||||
|
||||
if (isHtml) {
|
||||
document.querySelector("#layout").innerHTML = content
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
document.getElementById('layout').innerHTML = md.parse(processMarkdown(content));
|
||||
|
||||
}
|
||||
|
||||
function setBodyStyle(stylenr, isHtml) {
|
||||
targetDiv.style = stylenr;
|
||||
|
||||
}
|
||||
|
||||
function getHtml() {
|
||||
|
||||
window.parent.postMessage({
|
||||
action: 'toValue',
|
||||
data: targetDiv.innerhtml,
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'toValue',
|
||||
data: targetDiv.innerhtml
|
||||
}
|
||||
})
|
||||
}
|
||||
// 在iframe内部执行以下代码
|
||||
var frameElement = window.frameElement;
|
||||
var iframeId = frameElement == null ? "" : frameElement.getAttribute('id');
|
||||
|
||||
|
||||
// 等待初始化完毕
|
||||
document.addEventListener('UniAppJSBridgeReady', () => {
|
||||
|
||||
md = new marked.Marked(
|
||||
markedHighlight({
|
||||
emptyLangClass: 'hljs',
|
||||
langPrefix: 'hljs language-',
|
||||
highlight(code, lang, info) {
|
||||
// const language = hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||
// return hljs.highlight(code, {
|
||||
// language
|
||||
// }).value;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
md.use(extendedTables());
|
||||
md.use(markedKatex({
|
||||
throwOnError: false
|
||||
}));
|
||||
|
||||
|
||||
md.setOptions({
|
||||
breaks: true,
|
||||
gfm: true,
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
window.parent.postMessage({
|
||||
action: 'onJSBridgeReady',
|
||||
data: '',
|
||||
iframeId: iframeId
|
||||
}, '*');
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'onJSBridgeReady'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user