feat: office-viewer Word 文档渲染 (#6412)

* init

* theme

* 基础文本渲染

* 基础文本样式

* 支持简单链接和图片

* 修复 jc 解析不正确问题

* 解析和渲染分离

* 初步支持列表渲染

* 完善样式表的实现

* 表格解析初步

* 避免解析顺序不一致

* 避免解析顺序不一致导致的问题

* 基于 DOMParser 来实现解析; 初步实现表格渲染

* 修复行高解析不正确问题

* 修复变量替换不正确问题

* 补充注释

* 用 fflate 替换 jszip, 支持同步使用

* 支持渲染 tab

* 支持表格条件渲染

* 优化表格样式适配

* 完善背景色支持

* 支持 ruby

* 支持简单 inserttext

* 修复表格合并不正确问题

* amis 渲染初步

* 整合 amis 初步

* 支持 input-file 上传预览

* styles: 优化button组件单icon情况的样式 (#6269)

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* fix: Badge设置overflowCount不生效问题修复 (#6267)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* feat: InputGroup报错展示优化 (#5803)

* feat:增加DATETOWEEK表达式

* feat:增加DATETOWEEK表达式

* feat:增加WEEKDAY和WEEK表达式

* feat:增加WEEKDAY和WEEK表达式

* feat:增加WEEKDAY和WEEK表达式

* feat:增加WEEKDAY和WEEK表达式

* feat:增加WEEKDAY和WEEK表达式

* chore: 2.7.3版本改为2.8.0 (#6272)

* styles: 输入框附加组件样式 (#6271)

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* styles: 优化checkbox组件选中态样式 (#6277)

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* feat:增加判断日期范围的表达式BETWEENRANGE&&优化STARTOF和ENDOF

* docs:表达式文档 (#6282)

* fix: Nav样式问题、性能优化 (#6280)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* chore: 还原几个 antd 导航及表格的颜色 (#6276)

* chore: Action倒计时key添加id避免冲突 (#5943)

* fix: nav同层拖拽问题修复 (#6285)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* v2.8.0

* chore: 删除在 ts 编译后永远都不会成立的代码 (#6291)

* styles: 将组件透明背景颜色改为白色 (#6289)

* styles: 将组件透明背景颜色改为白色

* styles: 将组件透明背景颜色改为白色

---------

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* fix: Select组件overlay属性在popOverContainer时宽度错误问题 (#6284)

* fix:Select组件overlay属性在popOverContainer时宽度错误问题

* 问题修改

* styles: 优化link组件svg图标样式 (#6292)

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* chore: Tree 组件中使用 value 替换 key (#6194)

* fix: 单选选项值包含逗号时获取选项错误问题 (#6258)

* fix: 单选选项值包含逗号时获取选项错误问题

* 加个单测

* 单测问题

* 在WrapControl 中使渲染器默认 multiple 生效

* 修改

* fix: select 各种模式支持 checkAll (#5941)

* feat(页面交互行为跟踪): 新增pageLoaded事件 (#6299)

* fix: nav拖拽卡顿、更多操作打开定位等问题修复 (#6304)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* fix: toast组件css变量拼错 (#6302)

Co-authored-by: renjianhua <renjianhua@zuoshouyisheng.com>

* fix: CRUD2 加载更多时接口page传参始终为1 (#6298)

* fix: 日期范围底部按钮居中 (#6301)

* 调整 saveAs  fileName 优先级

* feat: 移动端人员选择增加确定按钮

* Update UserSelect.tsx

* fix: 人员选择ts 类型错误

* fix: 城市选择组件移动端回显问题

* fix: 移动端级联选择器选中值bug修复

* Update Cascader.tsx

* fix: 城市选择香港、澳门不能选择市

* fix: 删除错误城市数据

* feat: 移动端人员选择支持字段配置

* feat: 人员选择组件支持字段配置

* Update UserSelect.tsx

* fix: 移动端人员选择静态展示头像url回显

* fix: 日期时间选择器底部按钮居中

---------

Co-authored-by: zhangxulong <zhangxulong@baidu.com>

* fix: table2全选、嵌套展开等问题修复 (#6313)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* docs(API 适配器): 调整文档细节 (#6314)

* styles: 优化清除图标样式 (#6312)

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* fix: 修复 Tree 在传入 pathSeparator 时,非根节点无法选中 (#6315)

* Update README.md

* fix: 解决因部分组件默认配置,导致编辑器配置面板宽度溢出问题 (#6328)

Co-authored-by: zhangzhulei <zhangzhulei@baidu.com>

* chore: svg 瘦身 (#6320)

* chore: svg 瘦身

* chore: svg 瘦身

* chore: svg 瘦身

* feat: mapping 的 source 接口支持 select 选项类接口 (#6326)

* fix: 调整 spinner-overlay 和 dialog 的 z-index,使关闭按钮不会被 spinner 遮挡 (#6321)

* feat: 新增 number 组件用来展示数字 (#6330)

* feat: 新增 number 组件用来展示数字

* feat: 新增 number 组件用来展示数字

* chore: tableCell 内部属性换个名字,以免跟已有其他组件组合使用时冲突

* fix: 注销renderer问题 (#6327)

Co-authored-by: liujintao03 <liujintao03@baidu.com>

* feat: InputExcel支持placeholder (#6295)

* feat: button-group-select支持角标 (#6309)

Co-authored-by: yanglu19 <yanglu19@baidu.com>

* chore: 暴露 InputBoxWithSuggestion (#6337)

* fix: 注销renderer问题 (#6338)

Co-authored-by: liujintao03 <liujintao03@baidu.com>

* docs: 补充trackExpression用法示例 (#6286)

* fix: 解决monaco环境变量和monaco插件的冲突 (#6283)

Co-authored-by: renjianhua <renjianhua@zuoshouyisheng.com>

* fix: Cards嵌套List组件时, props透传导致Schema不生效问题 (#6110)

* styles: 优化带单位的number组件样式 (#6054)

* styles: 优化待单位的number组件样式

* 更新快照

---------

Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>

* fix(Table): #2978 嵌套表格如何设置默认全部展开 (#6028)

* fix(Table): #2978 嵌套表格如何设置默认全部展开

* fix(Table): #2978 更改函数命名

* fix: now表达式作为form组件默认值时,增加特殊逻辑,处理数据更新 (#5783)

* fix: 解决公式编辑器 搜索变量失效bug (#6345)

Co-authored-by: zhangzhulei <zhangzhulei@baidu.com>

* fix: nav角标、悬浮展开子菜单、更多操作不可点击等问题修复 (#6346)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* feat:config动作优化

* fix: 修复卡片的 checkOnItemClick 配置问题 (#6365)

* fix: 修复弹窗中 form 配置 closeDialogOnSubmit 无效的问题 (#6368)

* fix: Transfer tree mode 支持 onlyChildren;两个值为undefined的Option不相等 (#6342)

* fix:transfer tree 支持 onlyChildren;两个值为undefined的Option不相等

* 修改

* 修改

* feat:carousel支持卡片动画模式 (#6354)

* feat:carousel支持多图配置

* Update carousel.md

---------

Co-authored-by: zhaowenli <zhaowenli@baidu.com>
Co-authored-by: RUNZE LU <36724300+lurunze1226@users.noreply.github.com>

* fix: inputTable 组件value依赖别的字段时,不同步数据域的问题 (#6360)

* fix: inputTable 组件value依赖别的字段时,不同步数据域的问题

* 修改

* 修改

* feat: 添加input-table子表单校验 (#6357)

* feat: 添加input-table子表单校验

* feat: 添加input-table snapshots更新

* feat: 添加input-table子表单校验

* feat: 添加input-table子表单校验

* feat: 添加input-table子表单校验

* feat: input-table snapshots更新

* feat: 添加input-table子表单校验

* feat: 添加input-table子表单校验

* feat: Steps source支持动态获取value status (#6370)

* fix: 修复 drawer reload 目标可能找不到的问题 (#6373)

* fix: 修复 crud 嵌套会触发多次快速保存接口问题 (#6374)

* fix: 修复 this.model.validated 可能读取不到的报错 (#6375)

* chore: alert 支持多个实例

* feat: Tag支持事件动作 (#6325)

* feat: reload 支持动态目标, 解决目标在循环中场景 (#6372)

* chore: Select组件checkAllBySearch默认为true (#6347)

* fix: Nav切换数据源实时更新、点击分组卡顿、横向模式排序等问题修复 (#6371)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* fix: table单元格支持自定义样式、crud支持本地数据快速过滤 (#6353)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>

* fix: 修改角标样式 (#6383)

Co-authored-by: yanglu19 <yanglu19@baidu.com>

* fix: 图标选择器,如果图标不属于saas项目中的,则默认显示schema配置的内容 (#6394)

Co-authored-by: zhangzhulei <zhangzhulei@baidu.com>

* feat: icon支持自定义样式 (#6379)

Co-authored-by: sarding <hongfuquan@baidu.com>

* fix: 解决input-table某些场景下无法新增的bug (#6400)

Co-authored-by: zhangzhulei <zhangzhulei@baidu.com>

* fix: 解决input-table某些场景下无法新增的bug (#6404)

Co-authored-by: zhangzhulei <zhangzhulei@baidu.com>

* fix: input-table内columns为下拉框时,删掉下拉框的选中值,发现input-table的数据域更新错误 (#6402)

* fix: input-table内columns为下拉框时,删掉下拉框的选中值,发现input-table的数据域更新错误

* fix: input-table内columns为下拉框时,删掉下拉框的选中值,发现input-table的数据域更新错误

* 修复示例文档错误

* 修复用例报错

* 修复 fis 报错

---------

Co-authored-by: qkiroc <30946345+qkiroc@users.noreply.github.com>
Co-authored-by: qinhaoyan <30946345+qinhaoyan@users.noreply.github.com>
Co-authored-by: wanglinfang2014 <w.l.fang@foxmail.com>
Co-authored-by: wanglinfang <wanglinfang@baidu.com>
Co-authored-by: RUNZE LU <36724300+lurunze1226@users.noreply.github.com>
Co-authored-by: lvxiaojiao <lvxiaojiao@baidu.com>
Co-authored-by: hsm-lv <80095014+hsm-lv@users.noreply.github.com>
Co-authored-by: lurunze1226 <lurunze1226@foxmail.com>
Co-authored-by: liaoxuezhi <2betop.cn@gmail.com>
Co-authored-by: sansiro <sansiro@sansiro.me>
Co-authored-by: meerkat <kit_hack@outlook.com>
Co-authored-by: 刘丹 <365533093@qq.com>
Co-authored-by: backpast <agileago@gmail.com>
Co-authored-by: renjianhua <renjianhua@zuoshouyisheng.com>
Co-authored-by: ls <1769057083@qq.com>
Co-authored-by: zhangxulong <zhangxulong@baidu.com>
Co-authored-by: zhangzhulei <30931358+DynaZhang@users.noreply.github.com>
Co-authored-by: zhangzhulei <zhangzhulei@baidu.com>
Co-authored-by: gooolh <57032082+gooolh@users.noreply.github.com>
Co-authored-by: liujintao03 <liujintao03@baidu.com>
Co-authored-by: Dora <53067150+Dora-boots@users.noreply.github.com>
Co-authored-by: yanglu19 <yanglu19@baidu.com>
Co-authored-by: TommyShao <tomieric@gmail.com>
Co-authored-by: pianruijie <13522335863@163.com>
Co-authored-by: xiangwaner <1186355501@qq.com>
Co-authored-by: zhaowenli <zhaowenli@baidu.com>
Co-authored-by: zhou999 <zhousq809@163.com>
Co-authored-by: Allen <yupeng.fe@qq.com>
Co-authored-by: sarding <37691952+sarding@users.noreply.github.com>
Co-authored-by: sarding <hongfuquan@baidu.com>
This commit is contained in:
吴多益 2023-03-20 20:09:13 +08:00 committed by GitHub
parent 6e346a3f13
commit 85bae586a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
210 changed files with 37202 additions and 5 deletions

1
.gitignore vendored
View File

@ -33,3 +33,4 @@ lerna-debug.log
package-lock.json
revision.json
**/revision.json
~$*

View File

@ -15,6 +15,9 @@
},
{
"path": "./packages/amis"
},
{
"path": "./packages/office-viewer"
}
]
}

View File

@ -0,0 +1,246 @@
---
title: Office Viewer
description:
type: 0
group: ⚙ 组件
menuName: OfficeViewer 文档渲染
icon:
order: 23
---
用于渲染 office 文档,目前只支持 docx 格式,通过前端转成 HTML 的方式进行渲染,支持以下功能:
- 基础文本样式
- 表格及表格样式
- 内嵌图片
- 列表
- 注音
- 链接
不支持的功能:
- 分页符
- 形状
- 艺术字
- 域
- 对象
## 基本用法
```schema: scope="body"
{
"type": "office-viewer",
"src": "../../../examples/static/example.docx"
}
```
## 渲染配置项
目前只支持 Word 文档,所以只有 word 的配置项,放在 `wordOptions`
### word 渲染配置属性表
```json
{
"type": "office-viewer",
"wordOptions": {
"padding": "8px",
"classPrefix": "docx"
}
}
```
| 属性名 | 类型 | 默认值 | 说明 |
| ----------------- | --------- | ------------- | ------------------------------------------ |
| classPrefix | `string` | 'docx-viewer' | 渲染的 class 类前缀 |
| bulletUseFont | `boolean` | true | 列表使用字体渲染,请参考下面的乱码说明 |
| fontMapping | `object` | | 字体映射,是个键值对,用于替换文档中的字体 |
| forceLineHeight | `string` | | 设置段落行高,忽略文档中的设置 |
| padding | `string` | | 设置页面间距,忽略文档中的设置 |
| enableReplaceText | `boolean` | true | 是否开启变量替换功能 |
## 列表符号出现乱码问题
默认情况下列表左侧的符号使用字体渲染,这样能做到最接近 Word 渲染效果,但如果用户的系统中没有这些字体就会显示乱码,为了解决这个问题需要手动在 amis 渲染的页面里导入对应的字体,比如
```
<style>
@font-face {
font-family: Wingdings;
src: url(./static/font/wingding.ttf);
}
@font-face {
font-family: Symbol;
src: url(./static/font/symbol.ttf);
}
</style>
```
目前已知会有 `Wingdings``Symbol` 两个字体,可能还有别的
如果不想嵌入这两个字体,就只能在前面的 `wordOptions` 里设置 `bulletUseFont: false`
## 变量替换
文档可以预先定义变量,通过配置 `enableVar` 来开启这个功能,在实际渲染时根据上下文数据来渲染变量,比如
```schema: scope="body"
{
"type": "form",
"title": "",
"mode": "inline",
"wrapWithPanel": false,
"body": [
{
"type": "input-text",
"name": "name",
"value": "amis",
"label": "姓名"
},
{
"type": "input-email",
"name": "email",
"label": "邮箱"
},
{
"type": "input-text",
"name": "phone",
"label": "手机号"
},
{
"type": "office-viewer",
"id": "office-viewer",
"src": "../../../examples/static/info.docx",
"wordOptions": {
"enableVar": true,
"padding": "8px"
}
}
]
}
```
如果关闭将显示原始文档
```schema: scope="body"
{
"type": "office-viewer",
"id": "office-viewer",
"src": "../../../examples/static/info.docx",
"wordOptions": {
"padding": "8px"
}
}
```
### 变量详细说明
目前变量使用的写法是 `{{name}}`,其中 `name` 代表变量名,另外这里可以是 amis 表达式,比如前面示例的 `{{DATETOSTR(TODAY(), 'YYYY-MM-DD')}}`
> 为了避免 Word 自作主张添加额外标签,对于复杂的变量建议先在记事本之类的纯文本编辑器里编辑,再粘贴进 Word 里。
## 不渲染模式
通过配置 `display: false` 可以让文档不渲染,虽然不渲染,但还是可以使用后面的下载及打印功能
## 下载文档
基于事件动作实现
```schema: scope="body"
[
{
"type": "action",
"label": "下载文档",
"onEvent": {
"click": {
"actions": [
{
"actionType": "saveAs",
"componentId": "office-viewer-download"
}
]
}
}
},
{
"type": "office-viewer",
"id": "office-viewer-download",
"display": false,
"src": "../../../examples/static/example.docx"
}
]
```
## 打印文档
基于事件动作实现
```schema: scope="body"
[
{
"type": "action",
"label": "打印",
"onEvent": {
"click": {
"actions": [
{
"actionType": "print",
"componentId": "office-viewer-print"
}
]
}
}
},
{
"type": "office-viewer",
"id": "office-viewer-print",
"display": false,
"src": "../../../examples/static/example.docx"
}
]
```
## 配合文件上传实现预览功能
配置和 `input-file` 相同的 `name` 即可
```schema: scope="body"
{
"type": "form",
"title": "",
"wrapWithPanel": false,
"body": [
{
"type": "input-file",
"name": "file",
"label": "File",
"asBlob": true,
"accept": ".docx"
},
{
"type": "office-viewer",
"id": "office-viewer",
"name": "file"
}
]
}
```
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| ----------- | --------- | ------ | -------------------- |
| src | Api | | 文档地址 |
| enableVar | `boolean` | | 是否开启变量替换功能 |
| wordOptions | `object` | | Word 渲染配置 |
## 动作表
当前组件对外暴露以下特性动作,其他组件可以通过指定`actionType: 动作名称`、`componentId: 该组件id`来触发这些动作,动作配置可以通过`args: {动作配置项名称: xxx}`来配置具体的参数,详细请查看[事件动作](../../docs/concepts/event-action#触发其他组件的动作)。
| 动作名称 | 动作配置 | 说明 |
| -------- | ---------------------- | -------- |
| saveAs | `name?: string` 文件名 | 下载文档 |
| print | - | 打印文档 |

View File

@ -964,6 +964,13 @@ export const components = [
import('../../docs/zh-CN/components/markdown.md').then(wrapDoc)
)
},
{
label: 'OfficeViewer 文档渲染',
path: '/zh-CN/components/office-viewer',
component: React.lazy(() =>
import('../../docs/zh-CN/components/office-viewer.md').then(wrapDoc)
)
},
{
label: 'Progress 进度条',
path: '/zh-CN/components/progress',

Binary file not shown.

BIN
examples/static/info.docx Normal file

Binary file not shown.

View File

@ -773,6 +773,7 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!markdown-it-html5-media/**',
'!punycode/**',
'!amis-formula/**',
'!office-viewer/**',
'!amis-core/**',
'!amis-ui/**',
'!amis/**'

View File

@ -4,7 +4,8 @@
"packages/amis-formula",
"packages/amis-core",
"packages/amis-ui",
"packages/amis"
"packages/amis",
"packages/office-viewer"
],
"scripts": {
"fis3-serve": "fis3 server start --www ./public --port 8888 --no-daemon --no-browse",

View File

@ -64,6 +64,7 @@
"mobx-state-tree": "^3.17.3",
"moment": "^2.19.4",
"mpegts.js": "^1.6.10",
"office-viewer": "0.1.0",
"prop-types": "^15.6.1",
"qrcode.react": "^3.1.0",
"rc-overflow": "^1.2.4",

View File

@ -248,6 +248,7 @@ export type SchemaType =
| 'input-excel'
| 'input-formula'
| 'diff-editor'
| 'office-viewer'
// editor 系列
| 'editor'

View File

@ -150,6 +150,7 @@ import './renderers/Words';
import './renderers/Password';
import './renderers/DateRange';
import './renderers/MultilineText';
import './renderers/OfficeViewer';
import './compat';
import './schemaExtend';

View File

@ -0,0 +1,189 @@
/**
* office
*/
import React from 'react';
import {BaseSchema} from '../Schema';
import {evaluate} from 'amis-formula';
import {Word} from 'office-viewer';
import {
ActionObject,
isApiOutdated,
IScopedContext,
Renderer,
RendererProps,
resolveVariableAndFilter,
ScopedContext,
ServiceStore
} from 'amis-core';
export interface OfficeViewerSchema extends BaseSchema {
type: 'office-viewer';
/**
*
*/
src: string;
/**
* word
*/
wordOptions?: {};
/**
*
*/
display?: boolean;
}
export interface OfficeViewerProps
extends RendererProps,
Omit<OfficeViewerSchema, 'className'> {
columnsCount: number;
}
export interface OfficeViewerState {}
export default class OfficeViewer extends React.Component<
OfficeViewerProps,
OfficeViewerState
> {
rootElement: React.RefObject<HTMLDivElement>;
word: Word;
fileName?: string;
constructor(props: OfficeViewerProps) {
super(props);
this.rootElement = React.createRef();
}
componentDidMount() {
if (this.rootElement?.current) {
this.renderWord();
}
}
componentDidUpdate(prevProps: OfficeViewerProps) {
const props = this.props;
if (isApiOutdated(prevProps.src, props.src, prevProps.data, props.data)) {
this.renderWord();
}
if (props.name) {
if (prevProps.data[props.name] !== props.data[props.name]) {
this.renderWord();
}
}
// 这个变量替换只会更新变化的部分,所以性能还能接受
this.word?.updateVariable();
}
doAction(action: ActionObject, args: any, throwErrors: boolean): any {
const actionType = action?.actionType as string;
if (actionType === 'saveAs') {
this.word?.download(args?.name || this.fileName);
}
if (actionType === 'print') {
this.word?.print();
}
}
replaceText(text: string) {
const {data} = this.props;
// 将 {{xxx}} 替换成 ${xxx},为啥要这样呢,因为输入 $ 可能会变成两段文本
text = text.replace(/{{/g, '${').replace(/}}/g, '}');
return resolveVariableAndFilter(text, data, '| raw');
}
async renderWord() {
const {src, name} = this.props;
if (src) {
this.renderRemoteWord();
} else if (name) {
this.renderFormFile();
} else {
console.warn(`office-viewer must have src or name`);
}
}
/**
*
*/
async renderRemoteWord() {
const {wordOptions, env, src, data, display} = this.props;
const finalSrc = src
? resolveVariableAndFilter(src, data, '| raw')
: undefined;
if (typeof finalSrc === 'string') {
this.fileName = finalSrc.split('/').pop();
}
const response = await env.fetcher(finalSrc, data, {
responseType: 'arraybuffer'
});
const word = new Word(response.data, {
...wordOptions,
replaceText: this.replaceText.bind(this)
});
if (display !== false) {
word.render(this.rootElement?.current!);
}
this.word = word;
}
/**
* input-file
*/
renderFormFile() {
const {wordOptions, name, data, display} = this.props;
const file = data[name];
if (file instanceof File) {
const reader = new FileReader();
reader.onload = _e => {
const data = reader.result as ArrayBuffer;
const word = new Word(data, {
...wordOptions,
replaceText: this.replaceText.bind(this)
});
if (display !== false) {
word.render(this.rootElement?.current!);
}
};
reader.readAsArrayBuffer(file);
}
}
render() {
const {classnames: cx, translate: __} = this.props;
return <div ref={this.rootElement} className={cx('Office-Viewer')}></div>;
}
}
@Renderer({
type: 'office-viewer'
})
export class OfficeViewerRenderer extends OfficeViewer {
static contextType = ScopedContext;
constructor(props: OfficeViewerProps, context: IScopedContext) {
super(props);
const scoped = context;
scoped.registerComponent(this);
}
componentWillUnmount() {
super.componentWillUnmount?.();
const scoped = this.context as IScopedContext;
scoped.unRegisterComponent(this);
}
}

View File

@ -11,5 +11,9 @@
]
},
"include": ["src/**/*", "../amis-ui/src/custom.d.ts"],
"references": [{"path": "../amis-core"}, {"path": "../amis-ui"}]
"references": [
{"path": "../amis-core"},
{"path": "../amis-ui"},
{"path": "../office-viewer"}
]
}

View File

@ -0,0 +1,19 @@
# 说明
## 原理
docx 渲染器,原理是将 docx 里的 xml 格式转成 html
相对于 Canvas 渲染,这个实现方案比较简单,最终页面也可以很方便复制,但无法保证和原始 docx 文件展现一致,因为有部分功能难以在 HTML 中实现,比如图文环绕效果。
## 参考资料
- [官方规范](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/)
- [标签的在线文档](http://webapp.docx4java.org/OnlineDemo/ecma376/WordML/index.html)
日常开发可以使用 [OOXML viewer](https://marketplace.visualstudio.com/items?itemName=yuenm18.ooxml-viewer) 插件查看
开发过程啊参考了
- [docx](https://github.com/dolanmiu/docx) 的类型定义
- [docxjs](https://github.com/zVolodymyr/docxjs) 里格式的实现

View File

@ -0,0 +1,16 @@
/**
* word
*/
import Word from '../src/Word';
import fs from 'fs';
import path from 'path';
import XMLPackageParser from '../src/package/XMLPackageParser';
export async function createWord(): Promise<Word> {
const xmlContent = fs.readFileSync(
path.join(__dirname, './docx/empty.xml'),
'utf-8'
);
return new Word(xmlContent, {}, new XMLPackageParser());
}

View File

@ -0,0 +1,90 @@
import {createWord} from './EmptyWord';
import {mergeRun} from '../src/util/mergeRun';
import {parseXML, buildXML} from '../src/util/xml';
test('proofErr', async () => {
const xmlDoc = parseXML(
`
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>{{var</w:t>
</w:r>
<w:proofErr w:type="gramStart"/>
<w:r>
<w:t>}}</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
`.trim()
);
const word = await createWord();
mergeRun(word, xmlDoc);
expect(xmlDoc.getElementsByTagName('w:t')[0]?.innerHTML).toBe('{{var}}');
});
test('font hint', async () => {
const xmlDoc = parseXML(
`
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
</w:rPr>
<w:t>B</w:t>
</w:r>
<w:r>
<w:t>6</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
`.trim()
);
const word = await createWord();
mergeRun(word, xmlDoc);
console.log(buildXML(xmlDoc));
expect(xmlDoc.getElementsByTagName('w:t')[0]?.innerHTML).toBe('B6');
});
test('space', async () => {
const xmlDoc = parseXML(
`
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>C</w:t>
</w:r>
<w:r w:rsidR="007D7B36">
<w:t>ustom</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> </w:t>
</w:r>
<w:r w:rsidR="007D7B36">
<w:t>Style</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
`.trim()
);
const word = await createWord();
mergeRun(word, xmlDoc);
expect(xmlDoc.getElementsByTagName('w:t')[0]?.innerHTML).toBe('Custom');
});

View File

@ -0,0 +1,3 @@
sample-docs 来自 https://docx4java.org/docx4j/docx4j-8.3.9/docx4j-samples-docx4j-8.3.9.zip
目前主要用 simple type组合类型目前还是手动解析后续考虑改成自动解析

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,28 @@
A simple HelloWorld docx created in Word Online on 20181129:
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml" Id="rId3" />
<Relationship Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml" Id="rId2" />
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="/word/document22.xml" Id="rId1" />
</Relationships>
Note Target="/word/document22.xml"!!!
compare others which don't start with "/"
Compare Word 2016 (which is correct):
-<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Target="docProps/app.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Id="rId3"/>
<Relationship Target="docProps/core.xml" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Id="rId2"/>
<Relationship Target="word/document.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Id="rId1"/>
</Relationships>
[Content_Types].xml is consistent; there the partname starts with "/":
<Override PartName="/word/document22.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" />
If you open the Word Online docx in Word 2016 then save it, it "normalises" the rel to Target="word/document.xml"
docx4j should do the same (but currently leaves things as-is). Tracking at https://github.com/plutext/docx4j/issues/332

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
<myxml>
<element1>hydrogen</element1>
<element2>helium</element2>
<element3>lithium</element3>
</myxml>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><invoice>
<date>2019-01-15</date>
<customer>
<name>Joe Bloggs</name>
</customer>
<items>
<item>
<name>apples</name>
<price>$20</price>
</item>
<item>
<name>bananas</name>
<price>$30</price>
</item>
<item>
<name>gas</name>
<price>$40</price>
</item>
</items>
<misc>
<includeBankDetails>true</includeBankDetails>
<wantspam>false</wantspam>
</misc>
</invoice>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,402 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<pkg:package
xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">
<pkg:part pkg:name="/_rels/.rels"
pkg:contentType="application/vnd.openxmlformats-package.relationships+xml"
pkg:padding="512">
<pkg:xmlData>
<Relationships
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
Target="word/document.xml" />
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/_rels/document.xml.rels"
pkg:contentType="application/vnd.openxmlformats-package.relationships+xml"
pkg:padding="256">
<pkg:xmlData>
<Relationships
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId2"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
Target="styles.xml" />
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"
Target="numbering.xml" />
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/document.xml"
pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml">
<pkg:xmlData>
<w:document
xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<w:body>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph" />
<w:numPr>
<w:ilvl w:val="0" />
<w:numId w:val="1" />
</w:numPr>
</w:pPr>
<w:r>
<w:t>A</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>B</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>C</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>D</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="2"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>Aa</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="2"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>Inserted</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="2"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>Bb</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>Inserted</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
<w:numPr>
<w:ilvl w:val="0"/>
<w:numId w:val="1"/>
</w:numPr>
</w:pPr>
<w:r>
<w:t>Inserted</w:t>
</w:r>
</w:p>
<w:p/>
<w:p>
<w:r>
<w:t>To restart numbering, use:</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;w:num w:numId="2"&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;w:abstractNumId w:val="0"/&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;w:lvlOverride w:ilvl="0"&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;w:startOverride w:val="10"/&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;/w:lvlOverride&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;/w:num&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>It has to refer to the same abstractNumId.</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;w:num w:numId="1"&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;w:abstractNumId w:val="0"/&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t xml:space="preserve"> &lt;/w:num&gt;</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>It doesnt matter whether subsequent numbers refer to numId=”1” or “2”; what appears in the document is the same.</w:t>
</w:r>
</w:p>
<w:sectPr>
<w:pgSz w:w="12240" w:h="15840"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
</w:document>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/styles.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml">
<pkg:xmlData>
<w:styles xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:docDefaults>
<w:rPrDefault>
<w:rPr>
<w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi"/>
<w:sz w:val="22"/>
<w:szCs w:val="22"/>
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA"/>
</w:rPr>
</w:rPrDefault>
<w:pPrDefault>
<w:pPr>
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
</w:pPr>
</w:pPrDefault>
</w:docDefaults>
<w:latentStyles w:defLockedState="0" w:defUIPriority="99" w:defSemiHidden="1" w:defUnhideWhenUsed="1" w:defQFormat="0" w:count="267">
<w:lsdException w:name="Normal" w:semiHidden="0" w:uiPriority="0" w:unhideWhenUsed="0" w:qFormat="1"/>
<w:lsdException w:name="heading 1" w:semiHidden="0" w:uiPriority="9" w:unhideWhenUsed="0" w:qFormat="1"/>
<w:lsdException w:name="heading 2" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 3" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 4" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 5" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 6" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 7" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 8" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 9" w:uiPriority="9" w:qFormat="1"/>
</w:latentStyles>
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
<w:qFormat/>
</w:style>
<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
<w:name w:val="Default Paragraph Font"/>
<w:uiPriority w:val="1"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="table" w:default="1" w:styleId="TableNormal">
<w:name w:val="Normal Table"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:qFormat/>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
<w:style w:type="numbering" w:default="1" w:styleId="NoList">
<w:name w:val="No List"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="paragraph" w:styleId="ListParagraph">
<w:name w:val="List Paragraph"/>
<w:basedOn w:val="Normal"/>
<w:uiPriority w:val="34"/>
<w:qFormat/>
<w:pPr>
<w:ind w:left="720"/>
<w:contextualSpacing/>
</w:pPr>
</w:style>
</w:styles>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/numbering.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml">
<pkg:xmlData>
<w:numbering xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<w:abstractNum w:abstractNumId="0">
<w:nsid w:val="2DD860C0"/>
<w:multiLevelType w:val="multilevel"/>
<w:tmpl w:val="0409001D"/>
<w:lvl w:ilvl="0">
<w:start w:val="1"/>
<w:numFmt w:val="decimal"/>
<w:lvlText w:val="%1)"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="360" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="1">
<w:start w:val="1"/>
<w:numFmt w:val="lowerLetter"/>
<w:lvlText w:val="%2)"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="720" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="2">
<w:start w:val="1"/>
<w:numFmt w:val="lowerRoman"/>
<w:lvlText w:val="%3)"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="1080" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="3">
<w:start w:val="1"/>
<w:numFmt w:val="decimal"/>
<w:lvlText w:val="(%4)"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="1440" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="4">
<w:start w:val="1"/>
<w:numFmt w:val="lowerLetter"/>
<w:lvlText w:val="(%5)"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="1800" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="5">
<w:start w:val="1"/>
<w:numFmt w:val="lowerRoman"/>
<w:lvlText w:val="(%6)"/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="2160" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="6">
<w:start w:val="1"/>
<w:numFmt w:val="decimal"/>
<w:lvlText w:val="%7."/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="2520" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="7">
<w:start w:val="1"/>
<w:numFmt w:val="lowerLetter"/>
<w:lvlText w:val="%8."/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="2880" w:hanging="360"/>
</w:pPr>
</w:lvl>
<w:lvl w:ilvl="8">
<w:start w:val="1"/>
<w:numFmt w:val="lowerRoman"/>
<w:lvlText w:val="%9."/>
<w:lvlJc w:val="left"/>
<w:pPr>
<w:ind w:left="3240" w:hanging="360"/>
</w:pPr>
</w:lvl>
</w:abstractNum>
<w:num w:numId="1">
<w:abstractNumId w:val="0"/>
</w:num>
<w:num w:numId="2">
<w:abstractNumId w:val="0"/>
<w:lvlOverride w:ilvl="0">
<w:startOverride w:val="10"/>
</w:lvlOverride>
</w:num>
</w:numbering>
</pkg:xmlData>
</pkg:part>
</pkg:package>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">
<pkg:part pkg:name="/_rels/.rels" pkg:contentType="application/vnd.openxmlformats-package.relationships+xml" pkg:padding="512">
<pkg:xmlData>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/_rels/document.xml.rels" pkg:contentType="application/vnd.openxmlformats-package.relationships+xml" pkg:padding="256">
<pkg:xmlData>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/document.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml">
<pkg:xmlData>
<w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<w:body>
<w:p>
<w:r>
<w:t>Simple table:</w:t>
</w:r>
</w:p>
<w:tbl>
<w:tblPr>
<w:tblStyle w:val="TableGrid"/>
<w:tblW w:w="0" w:type="auto"/>
<w:tblLook w:val="04A0"/>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="4788"/>
<w:gridCol w:w="4788"/>
</w:tblGrid>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="4788" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1c1</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="4788" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1c2</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="4788" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2c1</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="4788" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2c2</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</w:tbl>
<w:p/>
<w:p>
<w:r>
<w:t>Horizontal merge:</w:t>
</w:r>
</w:p>
<w:tbl>
<w:tblPr>
<w:tblStyle w:val="TableGrid"/>
<w:tblW w:w="0" w:type="auto"/>
<w:tblLook w:val="04A0"/>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="3192"/>
<w:gridCol w:w="3192"/>
<w:gridCol w:w="3192"/>
</w:tblGrid>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="6384" w:type="dxa"/>
<w:gridSpan w:val="2"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1 c1 &amp; c2</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1 c3</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2c1</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2c2</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2c3</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R3c1</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="6384" w:type="dxa"/>
<w:gridSpan w:val="2"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R3 c2 &amp; c3</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</w:tbl>
<w:p/>
<w:p>
<w:r>
<w:t>Vertical merge:</w:t>
</w:r>
</w:p>
<w:tbl>
<w:tblPr>
<w:tblStyle w:val="TableGrid"/>
<w:tblW w:w="0" w:type="auto"/>
<w:tblLook w:val="04A0"/>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="3192"/>
<w:gridCol w:w="3192"/>
<w:gridCol w:w="3192"/>
</w:tblGrid>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
<w:vMerge w:val="restart"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1 &amp; r2, c1</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1c2</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R1c3</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
<w:vMerge/>
</w:tcPr>
<w:p/>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2c2</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
<w:vMerge w:val="restart"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R2 &amp; r3, c3</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
<w:tr>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R3c1</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
</w:tcPr>
<w:p>
<w:r>
<w:t>R3c2</w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="3192" w:type="dxa"/>
<w:vMerge/>
</w:tcPr>
<w:p/>
</w:tc>
</w:tr>
</w:tbl>
<w:p/>
<w:p/>
<w:sectPr>
<w:pgSz w:w="12240" w:h="15840"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
</w:document>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/styles.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml">
<pkg:xmlData>
<w:styles xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:docDefaults>
<w:rPrDefault>
<w:rPr>
<w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi"/>
<w:sz w:val="22"/>
<w:szCs w:val="22"/>
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA"/>
</w:rPr>
</w:rPrDefault>
<w:pPrDefault>
<w:pPr>
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
</w:pPr>
</w:pPrDefault>
</w:docDefaults>
<w:latentStyles w:defLockedState="0" w:defUIPriority="99" w:defSemiHidden="1" w:defUnhideWhenUsed="1" w:defQFormat="0" w:count="267">
<w:lsdException w:name="Normal" w:semiHidden="0" w:uiPriority="0" w:unhideWhenUsed="0" w:qFormat="1"/>
<w:lsdException w:name="heading 1" w:semiHidden="0" w:uiPriority="9" w:unhideWhenUsed="0" w:qFormat="1"/>
<w:lsdException w:name="heading 2" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 3" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 4" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 5" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 6" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 7" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 8" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 9" w:uiPriority="9" w:qFormat="1"/>
</w:latentStyles>
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
<w:qFormat/>
</w:style>
<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
<w:name w:val="Default Paragraph Font"/>
<w:uiPriority w:val="1"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="table" w:default="1" w:styleId="TableNormal">
<w:name w:val="Normal Table"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:qFormat/>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
<w:style w:type="numbering" w:default="1" w:styleId="NoList">
<w:name w:val="No List"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="table" w:styleId="TableGrid">
<w:name w:val="Table Grid"/>
<w:basedOn w:val="TableNormal"/>
<w:uiPriority w:val="59"/>
<w:pPr>
<w:spacing w:after="0" w:line="240" w:lineRule="auto"/>
</w:pPr>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblBorders>
<w:top w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:left w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:bottom w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:right w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:insideH w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:insideV w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
</w:tblBorders>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
</w:styles>
</pkg:xmlData>
</pkg:part>
</pkg:package>

Binary file not shown.

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">
<pkg:part pkg:name="/_rels/.rels" pkg:contentType="application/vnd.openxmlformats-package.relationships+xml" pkg:padding="512">
<pkg:xmlData>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/_rels/document.xml.rels" pkg:contentType="application/vnd.openxmlformats-package.relationships+xml" pkg:padding="256">
<pkg:xmlData>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/document.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml">
<pkg:xmlData>
<w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<w:body>
<w:p>
<w:r>
<w:t>empty</w:t>
</w:r>
</w:p>
<w:sectPr>
<w:pgSz w:w="12240" w:h="15840"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
</w:document>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/styles.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml">
<pkg:xmlData>
<w:styles xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:docDefaults>
<w:rPrDefault>
<w:rPr>
<w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi"/>
<w:sz w:val="22"/>
<w:szCs w:val="22"/>
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA"/>
</w:rPr>
</w:rPrDefault>
<w:pPrDefault>
<w:pPr>
<w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
</w:pPr>
</w:pPrDefault>
</w:docDefaults>
<w:latentStyles w:defLockedState="0" w:defUIPriority="99" w:defSemiHidden="1" w:defUnhideWhenUsed="1" w:defQFormat="0" w:count="267">
<w:lsdException w:name="Normal" w:semiHidden="0" w:uiPriority="0" w:unhideWhenUsed="0" w:qFormat="1"/>
<w:lsdException w:name="heading 1" w:semiHidden="0" w:uiPriority="9" w:unhideWhenUsed="0" w:qFormat="1"/>
<w:lsdException w:name="heading 2" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 3" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 4" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 5" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 6" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 7" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 8" w:uiPriority="9" w:qFormat="1"/>
<w:lsdException w:name="heading 9" w:uiPriority="9" w:qFormat="1"/>
</w:latentStyles>
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
<w:qFormat/>
</w:style>
<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
<w:name w:val="Default Paragraph Font"/>
<w:uiPriority w:val="1"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="table" w:default="1" w:styleId="TableNormal">
<w:name w:val="Normal Table"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:qFormat/>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
<w:style w:type="numbering" w:default="1" w:styleId="NoList">
<w:name w:val="No List"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="table" w:styleId="TableGrid">
<w:name w:val="Table Grid"/>
<w:basedOn w:val="TableNormal"/>
<w:uiPriority w:val="59"/>
<w:pPr>
<w:spacing w:after="0" w:line="240" w:lineRule="auto"/>
</w:pPr>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblBorders>
<w:top w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:left w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:bottom w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:right w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:insideH w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
<w:insideV w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/>
</w:tblBorders>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
</w:styles>
</pkg:xmlData>
</pkg:part>
</pkg:package>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,118 @@
/**
*
*/
import XMLPackageParser from '../src/package/XMLPackageParser';
import Word from '../src/Word';
const viewerElement = document.getElementById('viewer') as HTMLElement;
const testDir = '__tests__/docx';
const fileLists = {
simple: [
'helloworld.docx',
'list.docx',
'tableborder.docx',
'tablestyle.docx',
'pinyin.docx'
],
docx4j: [
'ArialUnicodeMS.docx',
'DOCPROP_builtin.docx',
'FontEmbedded.docx',
'Headers.docx',
'Images.docx',
'Symbols.docx',
'Word2007-fonts.docx',
'chart.docx',
'chunk.docx',
'decracdiscrim1.docx',
'docProps.docx',
'fonts-modesOfApplication.docx',
'hyperlinks-internal.docx',
'sample-docx.docx',
'sample-docxv2.docx',
'tableborder.docx',
'tables.docx',
'toc.docx',
'unmarshallFromTemplateDirtyExample.docx',
'unmarshallFromTemplateExample.docx',
'numberingrestart.xml',
'sample-docx.xml',
'table-features.xml',
'table-spans.xml'
]
};
/**
*
*/
(function genFileList() {
const fileListElement = document.getElementById('fileList')!;
for (const dirName in fileLists) {
fileListElement.innerHTML += `<h2 class="dir">${dirName}</h2>`;
const dir = dirName as keyof typeof fileLists;
for (const file of fileLists[dir]) {
const fileName = file.split('.')[0];
fileListElement.innerHTML += `<div class="file" data-path="${dirName}/${file}" title="${file}">${fileName}</div>`;
}
}
document.querySelectorAll('.file').forEach(file => {
file.addEventListener('click', elm => {
const fileName = (elm.target as Element).getAttribute('data-path')!;
history.pushState({fileName}, fileName, `?file=${fileName}`);
renderDocx(fileName);
});
});
})();
const data = {
var: 'amis'
};
function replaceText(text: string) {
// 将 {{xxx}} 替换成 ${xxx},为啥要这样呢,因为输入 $ 可能会变成两段文本
text = text.replace(/{{/g, '${').replace(/}}/g, '}');
return text;
}
async function renderDocx(fileName: string) {
const filePath = `${testDir}/${fileName}`;
const file = await (await fetch(filePath)).arrayBuffer();
let word: Word;
const renderOptions = {
debug: true
// replaceText
};
if (filePath.endsWith('.xml')) {
word = new Word(file, renderOptions, new XMLPackageParser());
} else {
word = new Word(file, renderOptions);
}
const fileNameSplit = fileName.split('/');
const downloadName = fileNameSplit[fileNameSplit.length - 1].replace(
'.xml',
'.docx'
);
(window as any).downloadDocx = () => {
word.download(downloadName);
};
(window as any).printDocx = () => {
word.print();
};
word.render(viewerElement);
}
const url = new URL(location.href);
const initFile = url.searchParams.get('file');
if (initFile) {
renderDocx(initFile);
}

View File

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>load docx</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
@font-face {
font-family: Wingdings;
src: url(./static/font/wingding.ttf);
}
@font-face {
font-family: Symbol;
src: url(./static/font/symbol.ttf);
}
</style>
</head>
<body>
<input
type="file"
id="upload"
accept="*.docx"
onchange="renderWord(this)"
/>
<button type="button" onclick="printElement()">print</button>
<div id="app"></div>
<script type="module">
import Word from '../src/Word';
const appElement = document.getElementById('app');
document.addEventListener('dragover', function (event) {
event.preventDefault();
});
document.addEventListener(
'drop',
e => {
e.preventDefault();
let dt = e.dataTransfer;
let files = dt.files;
renderWord(files[0]);
},
false
);
function renderInputFile(input) {
const file = input.files[0];
renderWord(file);
}
function renderWord(file) {
const reader = new FileReader();
reader.onload = _e => {
const data = reader.result;
const word = new Word(data);
word.render(appElement);
};
reader.readAsArrayBuffer(file);
}
function printElement() {
var contentOfDiv = appElement.innerHTML;
var newWin = window.open('', '');
newWin.document.write('');
newWin.document.write(
'<title>Print Content of Div element by using Javascript</title>'
);
newWin.document.write(contentOfDiv);
newWin.document.write('');
newWin.document.close();
newWin.print();
}
window.renderWord = renderWord;
window.printElement = printElement;
</script>
</body>
</html>

View File

@ -0,0 +1,44 @@
html,
body {
margin: 0;
padding: 0;
}
@font-face {
font-family: Wingdings;
src: url(/examples/static/font/wingding.ttf);
}
@font-face {
font-family: Symbol;
src: url(/examples/static/font/symbol.ttf);
}
/** 参考 bulma 的命名 */
.columns {
display: flex;
}
.column {
display: block;
flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;
}
.file-list {
width: 140px;
padding-top: 4px;
padding-left: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file {
cursor: pointer;
}
.file:hover {
color: hsl(217, 71%, 53%);
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>docx viewer</title>
<link rel="stylesheet" href="/examples/static/css/app.css" />
</head>
<body>
<div class="columns">
<div class="column file-list" id="fileList">
<button type="button" onclick="downloadDocx()">download</button>
<button type="button" onclick="printDocx()">print</button>
</div>
<div class="column">
<div id="viewer"></div>
</div>
</div>
<script type="module" src="/examples/app.ts"></script>
</body>
</html>

View File

@ -0,0 +1,91 @@
{
"name": "office-viewer",
"version": "0.1.0",
"description": "office 文档在线预览",
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts",
"scripts": {
"dev": "vite",
"build": "npm run clean-dist && cross-env NODE_ENV=production rollup -c ",
"test": "jest",
"lib": "npm run clean-dist && cross-env NODE_ENV=production IS_LIB=1 rollup -c",
"coverage": "jest --coverage",
"declaration": "tsc --project tsconfig-for-declaration.json --allowJs --declaration --emitDeclarationOnly --declarationDir ./lib --rootDir ./src",
"clean-dist": "rimraf lib/** esm/**",
"xsd2ts": "cd tools && ts-node --transpileOnly xsd2ts.ts"
},
"exports": {
".": {
"require": "./lib/index.js",
"import": "./esm/index.js"
},
"./lib/*": {
"require": "./lib/*.js",
"import": "./esm/*.js"
}
},
"files": [
"lib",
"esm"
],
"keywords": [
"office",
"docx"
],
"license": "Apache 2.0",
"bugs": {
"url": "https://github.com/baidu/amis/issues"
},
"homepage": "https://github.com/baidu/amis#readme",
"dependencies": {
"fflate": "^0.7.4"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^22.0.2",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^14.1.0",
"@rollup/plugin-typescript": "^8.3.4",
"@types/jest": "^28.1.0",
"amis-formula": "^2.7.2",
"jest": "^29.0.3",
"ts-jest": "^29.0.2",
"ts-loader": "^9.2.3",
"ts-node": "^10.4.0",
"typescript": "^4.3.5",
"rollup": "^2.60.2",
"rollup-plugin-terser": "^7.0.2",
"vite": "^3.2.2"
},
"jest": {
"testEnvironment": "jsdom",
"collectCoverageFrom": [
"src/**/*"
],
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"\\.(ts|tsx)$": [
"ts-jest",
{
"diagnostics": false
}
]
},
"setupFiles": [
"jest-canvas-mock"
],
"testRegex": "/.*\\.test\\.(ts|tsx|js)$",
"moduleNameMapper": {
"\\.(css|less|sass|scss)$": "<rootDir>/../__mocks__/styleMock.js",
"\\.(svg)$": "<rootDir>/../__mocks__/svgMock.js"
},
"snapshotFormat": {
"escapeString": false,
"printBasicPrototype": false
}
}
}

View File

@ -0,0 +1,92 @@
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import {main, module, dependencies} from './package.json';
import path from 'path';
const settings = {
globals: {}
};
const external = id =>
new RegExp(
`^(?:${Object.keys(dependencies)
.concat([])
.map(value =>
value.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
)
.join('|')})`
).test(id);
export default [
{
input: ['./src/index.ts'],
output: [
{
...settings,
dir: path.dirname(main),
format: 'cjs',
exports: 'named',
preserveModulesRoot: './src',
preserveModules: true // Keep directory structure and files
}
],
external: external,
plugins: getPlugins('cjs')
},
{
input: ['./src/index.ts'],
output: [
{
...settings,
dir: path.dirname(module),
format: 'esm',
exports: 'named',
preserveModulesRoot: './src',
preserveModules: true // Keep directory structure and files
}
],
external: external,
plugins: getPlugins('esm')
}
];
function getPlugins(format = 'esm') {
const typeScriptOptions = {
typescript: require('typescript'),
sourceMap: false,
outputToFilesystem: true,
...(format === 'esm'
? {
compilerOptions: {
rootDir: './src',
outDir: path.dirname(module)
}
}
: {
compilerOptions: {
rootDir: './src',
outDir: path.dirname(main)
}
})
};
return [
json(),
resolve({
jsnext: true,
main: true,
browser: true
}),
typescript(typeScriptOptions),
commonjs({
include: 'node_modules/**',
extensions: ['.js'],
ignoreGlobal: false,
sourceMap: false
})
];
}

Some files were not shown because too many files have changed in this diff Show More