diff --git a/README.md b/README.md index 1eaa8e6f7949e5b64fdd39c2ccf03e6e584e664f..6b8ff4a5ab94f47f086466d864be0452e08c3832 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,27 @@ |流量(GB)|0.18 | |售价(元/月)#{colspan=2} |5 | ``` + +14. 表格支持行展开 + md 书写格式 + ```md + | |原生语言插件 |uts插件| + |:------ |:------- |:--------| + |开发语言 |java/oc |uts| + |开发环境 |Android Studio/XCode |[HBuilderX](https://www.baidu.com)| + ->|第一列|第二列 |第三列 | + ->|:------ |:-------: |-------: | + ->|左对齐 |[居中](https://www.baidu.com)|右对齐| + |打包方式 |外挂aar 等产出物 |编译时生成原生代码| + |js层调用方式 |uni.requireNativePlugin() |普通的js函数/对象,可以直接 import,支持摇树优化| + ->|第一列|第二列 | + ->|:------ |:------- | + ->|第一列内容 |[HBuilderX](https://www.baidu.com)| + |支持项目类型 |uni-app |uni-app和uni-app x| + ``` + 表现为: + ![](https://qiniudcdn.qnqcdn.net/web-ext-storage.dcloud.net.cn/doc/subtable.png) + ## 文档 Algolia 使用限额 Included Quota: - Records: 1,000,000 diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 26dcbcda15934a24fa0bc3048079780dd605b075..ff351229df85d895c2de49cc24448f378dd2d77e 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -109,6 +109,9 @@ const config = { .end() .plugin('markdown-it-raw-table') .use(require('markdown-it-raw-table')) + .end() + .plugin('subtable') + .use(require('./markdown/markdown-it-subtable').markdownIt, [{ flags: ['->'] }]) } }, chainWebpack (config, isServer) { diff --git a/docs/.vuepress/markdown/markdown-it-subtable.js b/docs/.vuepress/markdown/markdown-it-subtable.js new file mode 100644 index 0000000000000000000000000000000000000000..50a0332dec9e69e57291d23feacffc549a134f5e --- /dev/null +++ b/docs/.vuepress/markdown/markdown-it-subtable.js @@ -0,0 +1,146 @@ +function normalizeMD (md) { + if (typeof md === 'string') { + return md + .replace(/(? { + if (Array.isArray(tokenIndex) && tokenIndex.length > 2) { + const tableOpenIndex = tokenIndex.shift(); + const tableCloseIndex = tokenIndex.pop(); + let deleteOffset = 0; + + tokenIndex.forEach(subtableIndexes => { + const subtableOpenIndex = subtableIndexes.shift() + deleteOffset; + const subtableColumnCount = (subtableIndexes[0] + deleteOffset - subtableOpenIndex - 2) / 3 - 1; + const subtableCloseIndex = subtableIndexes.pop() + deleteOffset + subtableColumnCount * 3; + const subtableTokens = tokens.slice(subtableOpenIndex - 1, subtableCloseIndex + 1); + + // 2 table token 新行开始时固定的 tr_open td_open 数量 + // 3 每个 inline 都会伴随一个 td_close、td_open(行最后一列 inline 会伴随 td_close tr_close) + // 1 为 flag ->(标识符) 的列,需要去掉 + let tableColumnCount = 0; + for (let i = 0; i < tableCloseIndex; i++) { + const token = tokens[i]; + if (i < subtableOpenIndex) { + if (token.type === 'th_open') { + tableColumnCount++; + } else if (token.type === 'thead_close') { + break; + } + } + } + + let subtableMD = subtableTokens + .map(token => { + if (token.type === 'inline' && !flags.includes(token.content)) { + return normalizeMD(token.content); + } else if (token.type === 'tr_close') { + return '\n'; + } + }) + .filter(Boolean); + const subtableLevel = subtableTokens[0].level; + const newTokens = md.parse(`|${subtableMD.join('|')}|`); + newTokens.forEach(token => { + token.content = ''; // 和 children 内容重复 + token.level = token.level + subtableLevel; + }); + newTokens[0].attrJoin('style', 'overflow-x: visible;margin: auto;'); + const childrenTableTokenIndex = subtableOpenIndex - 2; + const subtablePrevTrOpenIndex = childrenTableTokenIndex - tableColumnCount * 3 - 2; + tokens[tableOpenIndex].attrJoin('class', 'have-children-table'); // table + tokens[subtablePrevTrOpenIndex].attrJoin('class', 'have-children-tr'); // table tr_open + + // table td_open + const haveChildrenTrTdToken = tokens[subtablePrevTrOpenIndex + 1]; + haveChildrenTrTdToken.attrJoin('class', 'have-children-tr-td'); + haveChildrenTrTdToken.attrJoin('style', ';text-wrap: nowrap'); + + tokens[childrenTableTokenIndex].attrJoin('class', 'children-table'); // subtable tr_open + tokens[childrenTableTokenIndex].attrJoin('hidden', ''); // subtable tr_open + + tokens[subtableOpenIndex - 1].attrJoin('colspan', tableColumnCount); // subtable td_open + const deleteCount = subtableCloseIndex - subtableOpenIndex + 1; + tokens.splice(subtableOpenIndex, deleteCount, ...newTokens); + deleteOffset = deleteOffset + newTokens.length - deleteCount; + }); + } + }); + } +} + +function process(md, tokens, flags = ['->']) { + const subtableMinTokenCount = 3; + if ( + Array.isArray(tokens) && + tokens.length && + tokens.some(token => token.content.includes('->') && token.type === 'inline') + ) { + const tableOpenTokenIndex = tokens.findIndex(token => token.type === 'table_open'); + if (tableOpenTokenIndex > -1) { + /** + * [ + * table_open index, + * [] // subtable indexes, + * table_close index + * ] + */ + let tableTokensIndexes = [[]]; + let tableIndex = 0; + let subtableIndex = 1; + tokens.forEach((token, index) => { + if (token.type === 'table_open' && tableTokensIndexes[tableIndex].length === 0) { + tableTokensIndexes[tableIndex].push(index); + } + if (tableTokensIndexes[tableIndex] && typeof tableTokensIndexes[tableIndex][0] !== 'undefined') { + if (token.type === 'inline') { + if (flags.find(flag => new RegExp(`^\\s*${flag}\\s*$`).test(token.content))) { + ( + tableTokensIndexes[tableIndex][subtableIndex] || (tableTokensIndexes[tableIndex][subtableIndex] = []) + ).push(index); + } else if (tokens[index - 2].type === 'tr_open') { + tableTokensIndexes[tableIndex][++subtableIndex] = []; + } + } + } + if (token.type === 'table_close') { + subtableIndex = 1; + tableTokensIndexes[tableIndex].push(index); + tableTokensIndexes[++tableIndex] = []; + } + }); + tableTokensIndexes.forEach((subtableTokensIndex, index) => { + tableTokensIndexes[index] = subtableTokensIndex.filter( + i => typeof i === 'number' || (Array.isArray(i) && i.length >= subtableMinTokenCount) + ); + }); + tableTokensIndexes = tableTokensIndexes.filter(i => i.length); + if (tableTokensIndexes.length) { + resolveSubtable(md, tokens, tableTokensIndexes, flags); + } + } + } +} + +module.exports = { + process, + markdownIt: function subTablePlugin(md, { flags = ['->'] } = {}) { + md.core.ruler.after( + 'inline', + 'subtable', + (state, startLine, endLine, silent) => { + process(md, state.tokens, flags); + }, + { + alt: ['paragraph', 'reference'], + } + ); + }, +}; diff --git a/package.json b/package.json index 2ddcb5e90ce8f0e122710c6a13de500553ba8b82..f2a4f84ce5466cc41b3c4c4cc0c81ae5a8101d4f 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "markdown-it-raw-table": "^1.0.0", "markdown-it-task-lists": "^2.1.1", "vuepress-plugin-named-chunks": "^1.1.4", - "vuepress-theme-uni-app-test": "^1.4.4" + "vuepress-theme-uni-app-test": "^1.4.7" }, "dependencies": { "@docsearch/js": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index f4f621ce0cc17df9842bc489b624264f92861fb5..5d78e6a36f3bbbf6233808406fad95aadf5e7d2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9288,10 +9288,10 @@ vuepress-plugin-zooming@^1.1.8: dependencies: zooming "^2.1.1" -vuepress-theme-uni-app-test@^1.4.4: - version "1.4.4" - resolved "https://registry.npmmirror.com/vuepress-theme-uni-app-test/-/vuepress-theme-uni-app-test-1.4.4.tgz#6f7175f7b8ebc00a7496b7d02027c4900790aedc" - integrity sha512-WEvTL6xvw4Bzw7efqe/Y4dhpfdGYaKUsdoW5WmlcWDPxcWmT/pLMa7JYmGlGvJPFjhi6Ak3j//sIkEJbAsYcgQ== +vuepress-theme-uni-app-test@^1.4.7: + version "1.4.7" + resolved "https://registry.npmmirror.com/vuepress-theme-uni-app-test/-/vuepress-theme-uni-app-test-1.4.7.tgz#566be747f080f551a0f65ac306ccc09dab2ab623" + integrity sha512-O+4FGNetUqEHBpz/EE7KJlwNP3LrU2iz7W1WEq2vHnowPyOxwB2DiSA1aHaHhX1zDAG4n/HILQXhjH48r4uGhw== dependencies: "@vuepress/plugin-back-to-top" "^1.9.5" "@vuepress/theme-default" "^1.8.2"