diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..45202c0c6
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,53 @@
+name: Go
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ build:
+ name: ${{ matrix.config.name }}
+ runs-on: ${{ matrix.config.os }}
+ outputs:
+ tag: ${{ steps.git.outputs.tag }}
+ strategy:
+ fail-fast: false
+ matrix:
+ config:
+ - {
+ name: "Windows Latest MSVC",
+ artifact: "windows",
+ os: windows-latest
+ }
+ - {
+ name: "Ubuntu Latest GCC",
+ artifact: "linux",
+ os: ubuntu-latest
+ }
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.18
+
+ - name: Build
+ run: |
+ go mod tidy
+ go build -v
+
+ # - name: Test
+ # run: go test -v ./...
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v3
+ with:
+ path: |
+ conf/**/*
+ static/**/*
+ views/**/*
+ mindoc.*
+ name: mindoc-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
diff --git a/Dockerfile b/Dockerfile
index e13982c17..98bf9a95c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -36,14 +36,25 @@ FROM ubuntu:focal
# 切换默认shell为bash
SHELL ["/bin/bash", "-c"]
-COPY --from=build /usr/share/fonts/win/simsun.ttc /usr/share/fonts/win/
-COPY --from=build /go/src/github.com/mindoc-org/mindoc /mindoc
WORKDIR /mindoc
+
+# 文件复制
+COPY --from=build /usr/share/fonts/win/simsun.ttc /usr/share/fonts/win/
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/mindoc_linux_amd64 /mindoc/
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/start.sh /mindoc/
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/LICENSE.md /mindoc/
+# 文件夹复制
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/lib /mindoc/lib
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/conf /mindoc/__default_assets__/conf
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/static /mindoc/__default_assets__/static
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/views /mindoc/__default_assets__/views
+COPY --from=build /go/src/github.com/mindoc-org/mindoc/uploads /mindoc/__default_assets__/uploads
+
RUN chmod a+r /usr/share/fonts/win/simsun.ttc
# 备份原有源
RUN mv /etc/apt/sources.list /etc/apt/sources.list-backup
-# 最小化源,缩短apt update时间(ca-certificates必须先安装才支持换tsinghua源)
+# 最小化源,缩短apt update时间(ca-certificates必须先安装才支持换aliyun源)
RUN echo 'deb http://archive.ubuntu.com/ubuntu/ focal main restricted' > /etc/apt/sources.list
RUN apt-get update
RUN apt install -y ca-certificates
@@ -88,18 +99,14 @@ RUN update-locale LANG=zh_CN.UTF-8
ENV LANG=zh_CN.UTF-8
ENV LANGUAGE=zh_CN:en
ENV LC_ALL=zh_CN.UTF-8
+
# 安装-calibre
# RUN apt-get install -y calibre # 此种方式安装省事,但会安装很多额外不需要的软件包,导致体积过大
RUN mkdir -p /tmp/calibre-cache
-# 获取最新版本号
-RUN curl -s http://code.calibre-ebook.com/latest>/tmp/calibre-cache/version
-# 下载最新版本
-# RUN wget -O /tmp/calibre-cache/calibre-x86_64.txz -c https://download.calibre-ebook.com/`cat /tmp/calibre-cache/version`/calibre-`cat /tmp/calibre-cache/version`-x86_64.txz
-# 使用 ghproxy.com 替换 github 实现加速
-# RUN wget -O /tmp/calibre-cache/calibre-x86_64.txz -c https://ghproxy.com/https://github.com/kovidgoyal/calibre/releases/download/v`cat /tmp/calibre-cache/version`/calibre-`cat /tmp/calibre-cache/version`-x86_64.txz
-RUN wget -O /tmp/calibre-cache/calibre-x86_64.txz -c https://github.com/kovidgoyal/calibre/releases/download/v`cat /tmp/calibre-cache/version`/calibre-`cat /tmp/calibre-cache/version`-x86_64.txz
-# 注: 调试阶段,下载alibre-5.22.1-x86_64.txz到本地(使用 python -m http.server),加速构建
-# RUN wget -O /tmp/calibre-cache/calibre-x86_64.txz -c http://10.96.8.252:8000/calibre-5.22.1-x86_64.txz
+# 强制使用 5.44.0 版本(5.x的最新版本)
+RUN wget -O /tmp/calibre-cache/calibre-x86_64.txz -c https://download.calibre-ebook.com/5.44.0/calibre-5.44.0-x86_64.txz
+# 注: 调试阶段,下载alibre-5.44.0-x86_64.txz到本地(使用 python -m http.server),加速构建
+# RUN wget -O /tmp/calibre-cache/calibre-x86_64.txz -c http://10.96.8.252:8000/calibre-5.44.0-x86_64.txz
# 解压
RUN mkdir -p /opt/calibre
# RUN tar --extract --file=/tmp/calibre-cache/calibre-x86_64.txz --directory /opt/calibre
@@ -114,23 +121,19 @@ RUN ebook-convert --version
RUN rm -rf /tmp/calibre-cache
# refer: https://docs.docker.com/engine/reference/builder/#volume
-# 数据同步目录
-VOLUME /mindoc-sync-host
+VOLUME ["/mindoc/conf","/mindoc/static","/mindoc/views","/mindoc/uploads","/mindoc/runtime","/mindoc/database"]
# refer: https://docs.docker.com/engine/reference/builder/#expose
EXPOSE 8181/tcp
-# 如果配置文件不存在就复制
-RUN cp --no-clobber /mindoc/conf/app.conf.example /mindoc/conf/app.conf
-
ENV ZONEINFO=/mindoc/lib/time/zoneinfo.zip
RUN chmod +x /mindoc/start.sh
ENTRYPOINT ["/bin/bash", "/mindoc/start.sh"]
# https://docs.docker.com/engine/reference/commandline/build/#options
-# docker build --progress plain --rm --build-arg TAG=2.0.1 --tag gsw945/mindoc:2.0.1 .
+# docker build --progress plain --rm --build-arg TAG=2.1 --tag gsw945/mindoc:2.1 .
# https://docs.docker.com/engine/reference/commandline/run/#options
# set MINDOC=//d/mindoc # windows
# export MINDOC=/home/ubuntu/mindoc-docker # linux
-# docker run --rm -it -p 8181:8181 -v "%MINDOC%":"/mindoc-sync-host" --name mindoc -e MINDOC_ENABLE_EXPORT=true -d gsw945/mindoc:2.0.1
+# docker run --rm -it -p 8181:8181 -v "%MINDOC%":"/mindoc-sync-host" --name mindoc -e MINDOC_ENABLE_EXPORT=true -d gsw945/mindoc:2.1
diff --git a/README.md b/README.md
index 7c9fd5733..97f01280c 100644
--- a/README.md
+++ b/README.md
@@ -19,23 +19,24 @@ MinDoc 的前身是 [SmartWiki](https://github.com/lifei6671/SmartWiki) 文档
### 开发&维护&使用 悉知
-感谢作者 [lifei6671](https://github.com/lifei6671) 创造了MinDoc,并持续维护了很久。
-
-作者因工作等原因,精力有限,无法花费足够的时间来持续维护mindoc,已于北京时间2021年3月23日将mindoc交给社区(github组织[mindoc-org](https://github.com/mindoc-org))维护,期待热心开发者加入[mindoc-org](https://github.com/mindoc-org)一起来维护MinDoc。
-
-遇到问题请提 [Issues](https://github.com/mindoc-org/mindoc/issues ),欢迎使用者和贡献者加入QQ群 `1051164153`
+- 感谢作者 [lifei6671](https://github.com/lifei6671) 创造了MinDoc,并持续维护了很久。
+- 作者因工作等原因,精力有限,无法花费足够的时间来持续维护mindoc,已于北京时间2021年3月23日将mindoc交给社区(github组织[mindoc-org](https://github.com/mindoc-org))维护,期待热心开发者加入[mindoc-org](https://github.com/mindoc-org)一起来维护MinDoc。
+- 遇到问题请提 [Issues](https://github.com/mindoc-org/mindoc/issues ),欢迎使用者和贡献者加入QQ群 `1051164153`
-
-对开发感兴趣请关注 [Development](https://github.com/mindoc-org/mindoc/projects/1):
-- [Todo List](https://github.com/mindoc-org/mindoc/projects/1#column-13554511)
-- [Work in progress](https://github.com/mindoc-org/mindoc/projects/1#column-13554512)
-- [Review in progress](https://github.com/mindoc-org/mindoc/projects/1#column-13554513)
+- 对开发感兴趣请关注 [Development](https://github.com/mindoc-org/mindoc/projects/1):
+ - [Todo List](https://github.com/mindoc-org/mindoc/projects/1#column-13554511)
+ - [Work in progress](https://github.com/mindoc-org/mindoc/projects/1#column-13554512)
+ - [Review in progress](https://github.com/mindoc-org/mindoc/projects/1#column-13554513)
+- Mindoc基于 [beeego](https://github.com/beego/beego) 开发,beego文档地址: https://github.com/beego/beego-doc/tree/main/docs/zh
+- :warning: **特别声明**:
+ - 原作者 [lifei6671](https://github.com/lifei6671) 已于 2021-08-06 删除了个人捐赠信息,参见: [1a179179c1fe4d0d4db95e0b757d863aee5bf395](https://github.com/mindoc-org/mindoc/commit/1a179179c1fe4d0d4db95e0b757d863aee5bf395)
+ - 截止目前(2023-03-27),[mindoc-org](https://github.com/mindoc-org) 暂未发布任何捐赠信息,请勿轻信
---
# 安装与使用
-**如果你的服务器上没有安装golang程序请手动设置一个环境变量如下:键名为 ZONEINFO,值为MinDoc跟目录下的/lib/time/zoneinfo.zip 。**
+~~如果你的服务器上没有安装golang程序请手动设置一个环境变量如下:键名为 ZONEINFO,值为MinDoc跟目录下的/lib/time/zoneinfo.zip 。~~
更多信息请查看手册: [MinDoc 使用手册](https://www.iminho.me/wiki/docs/mindoc/mindoc-summary.md)
@@ -72,7 +73,7 @@ MinDoc 如果使用MySQL储存数据,则编码必须是`utf8mb4_general_ci`。
### 安装 musl-gcc
```bash
-wget -c http://www.musl-libc.org/releases/musl-1.2.2.tar.gz
+wget -c http://musl.libc.org/releases/musl-1.2.2.tar.gz
tar -xvf musl-1.2.2.tar.gz
cd musl-1.2.2
./configure
@@ -93,6 +94,9 @@ go build -v -o mindoc_linux_musl_amd64 -ldflags="-linkmode external -extldflags
./mindoc_linux_musl_amd64 version
```
+## Windows 上后台运行
+ 使用 [mindoc-daemon](https://github.com/mindoc-org/mindoc-daemon)
+
```ini
#邮件配置-示例
@@ -132,13 +136,13 @@ MINDOC_ENABLE_EXPORT 开启导出(默认为false)
##### Windows
```bash
set MINDOC=//d/mindoc
-docker run -it --name=mindoc --restart=always -v "%MINDOC%":"/mindoc-sync-host" -p 8181:8181 -e MINDOC_ENABLE_EXPORT=true -d registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1-beta.6
+docker run -it --name=mindoc --restart=always -v "%MINDOC%/conf":"/mindoc/conf" -p 8181:8181 -e MINDOC_ENABLE_EXPORT=true -d registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1
```
##### Linux、Mac
```bash
export MINDOC=/home/ubuntu/mindoc-docker
-docker run -it --name=mindoc --restart=always -v "${MINDOC}":"/mindoc-sync-host" -p 8181:8181 -e MINDOC_ENABLE_EXPORT=true -d registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1-beta.6
+docker run -it --name=mindoc --restart=always -v "${MINDOC}/conf":"/mindoc/conf" -p 8181:8181 -e MINDOC_ENABLE_EXPORT=true -d registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1
```
##### 举个栗子-更多环境变量示例(镜像已过期,仅供参考,请以当前镜像为准)
diff --git a/commands/command.go b/commands/command.go
index a35393310..63a01a2a7 100644
--- a/commands/command.go
+++ b/commands/command.go
@@ -20,12 +20,12 @@ import (
beegoCache "github.com/beego/beego/v2/client/cache"
_ "github.com/beego/beego/v2/client/cache/memcache"
"github.com/beego/beego/v2/client/cache/redis"
- _ "github.com/beego/beego/v2/client/cache/redis"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
"github.com/beego/beego/v2/server/web"
"github.com/beego/i18n"
"github.com/howeyc/fsnotify"
+ _ "github.com/lib/pq"
"github.com/lifei6671/gocaptcha"
"github.com/mindoc-org/mindoc/cache"
"github.com/mindoc-org/mindoc/conf"
@@ -84,6 +84,30 @@ func RegisterDataBase() {
if err != nil {
logs.Error("注册默认数据库失败->", err)
}
+ } else if strings.EqualFold(dbadapter, "postgres") {
+ host, _ := web.AppConfig.String("db_host")
+ database, _ := web.AppConfig.String("db_database")
+ username, _ := web.AppConfig.String("db_username")
+ password, _ := web.AppConfig.String("db_password")
+ sslmode, _ := web.AppConfig.String("db_sslmode")
+
+ timezone, _ := web.AppConfig.String("timezone")
+ location, err := time.LoadLocation(timezone)
+ if err == nil {
+ orm.DefaultTimeLoc = location
+ } else {
+ logs.Error("加载时区配置信息失败,请检查是否存在 ZONEINFO 环境变量->", err)
+ }
+
+ port, _ := web.AppConfig.String("db_port")
+
+ dataSource := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", username, password, host, port, database, sslmode)
+
+ if err := orm.RegisterDataBase("default", "postgres", dataSource); err != nil {
+ logs.Error("注册默认数据库失败->", err)
+ os.Exit(1)
+ }
+
} else {
logs.Error("不支持的数据库类型.")
os.Exit(1)
@@ -111,8 +135,9 @@ func RegisterModel() {
new(models.TeamMember),
new(models.TeamRelationship),
new(models.Itemsets),
- new(models.Comment),
- new(models.WorkWeixinAccount),
+ new(models.Comment),
+ new(models.WorkWeixinAccount),
+ new(models.DingTalkAccount),
)
gob.Register(models.Blog{})
gob.Register(models.Document{})
@@ -123,6 +148,7 @@ func RegisterModel() {
// RegisterLogger 注册日志
func RegisterLogger(log string) {
+ logs.Reset()
logs.SetLogFuncCall(true)
_ = logs.SetLogger("console")
logs.EnableFuncCallDepth(true)
@@ -207,7 +233,7 @@ func RegisterCommand() {
}
-//注册模板函数
+// 注册模板函数
func RegisterFunction() {
err := web.AddFuncMap("config", models.GetOptionValue)
@@ -294,7 +320,7 @@ func RegisterFunction() {
}
}
-//解析命令
+// 解析命令
func ResolveCommand(args []string) {
flagSet := flag.NewFlagSet("MinDoc command: ", flag.ExitOnError)
flagSet.StringVar(&conf.ConfigurationFile, "config", "", "MinDoc configuration file.")
@@ -343,6 +369,10 @@ func ResolveCommand(args []string) {
web.BConfig.WebConfig.StaticDir["/uploads"] = uploads
web.BConfig.WebConfig.ViewsPath = conf.WorkingDir("views")
web.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteDefaultMode
+ var upload_file_size = conf.GetUploadFileSize()
+ if upload_file_size > web.BConfig.MaxUploadSize {
+ web.BConfig.MaxUploadSize = upload_file_size
+ }
fonts := conf.WorkingDir("static", "fonts")
@@ -362,7 +392,7 @@ func ResolveCommand(args []string) {
}
-//注册缓存管道
+// 注册缓存管道
func RegisterCache() {
isOpenCache := web.AppConfig.DefaultBool("cache", false)
if !isOpenCache {
@@ -461,7 +491,7 @@ func RegisterCache() {
logs.Info("缓存初始化完成.")
}
-//自动加载配置文件.修改了监听端口号和数据库配置无法自动生效.
+// 自动加载配置文件.修改了监听端口号和数据库配置无法自动生效.
func RegisterAutoLoadConfig() {
if conf.AutoLoadDelay > 0 {
@@ -502,7 +532,7 @@ func RegisterAutoLoadConfig() {
}
}
-//注册错误处理方法.
+// 注册错误处理方法.
func RegisterError() {
web.ErrorHandler("404", func(writer http.ResponseWriter, request *http.Request) {
var buf bytes.Buffer
diff --git a/conf/app.conf.example b/conf/app.conf.example
index 70e70018d..aaffcb448 100644
--- a/conf/app.conf.example
+++ b/conf/app.conf.example
@@ -50,16 +50,20 @@ sessiongcmaxlifetime="${MINDOC_SESSION_MAX_LIFETIME||3600}"
#时区设置
timezone = Asia/Shanghai
-
-
####################MySQL 数据库配置###########################
-#支持MySQL和sqlite3两种数据库,如果是sqlite3 则 db_database 标识数据库的物理目录
+#支持MySQL,sqlite3,postgres三种数据库,如果是sqlite3 则 db_database 标识数据库的物理目录
db_adapter="${MINDOC_DB_ADAPTER||sqlite3}"
db_host="${MINDOC_DB_HOST||127.0.0.1}"
db_port="${MINDOC_DB_PORT||3306}"
db_database="${MINDOC_DB_DATABASE||./database/mindoc.db}"
db_username="${MINDOC_DB_USERNAME||root}"
db_password="${MINDOC_DB_PASSWORD||123456}"
+#是否使用SSL,支持posgres,可选的值有:
+#disable - No SSL
+#require - Always SSL (skip verification)
+#verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA)
+#verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate)
+db_sslmode="${MINDOC_DB_SSLMODE||disable}"
####################sqlite3 数据库配置###########################
#db_adapter=sqlite3
@@ -77,7 +81,9 @@ token_size=12
#上传文件的后缀,如果不限制后缀可以设置为 *
upload_file_ext=txt|doc|docx|xls|xlsx|ppt|pptx|pdf|7z|rar|jpg|jpeg|png|gif
-#上传的文件大小限制,如果不填写,默认不限制,单位可以是 GB KB MB
+#上传的文件大小限制
+# - 如果不填写, 则默认1GB,如果希望超过1GB,必须带单位
+# - 如果填写,单位可以是 TB、GB、MB、KB,不带单位表示字节
upload_file_size=10MB
####################邮件配置######################
@@ -119,23 +125,27 @@ baidumapkey=
################Active Directory/LDAP################
#是否启用ldap
-ldap_enable=false
+ldap_enable=${MINDOC_LDAP_ENABLE||false}
+#ldap协议(ldap/ldaps)
+ldap_scheme="${MINDOC_LDAP_SCHEME||ldap}"
#ldap主机名
-ldap_host=ad.example.com
+ldap_host="${MINDOC_LDAP_HOST||127.0.0.1}"
#ldap端口
-ldap_port=3268
+ldap_port=${MINDOC_LDAP_PORT||389}
#ldap内哪个属性作为用户名
-ldap_attribute=sAMAccountName
+ldap_attribute="${MINDOC_LDAP_ATTRIBUTE||sAMAccountName}"
+#ldap内哪个属性作为邮箱
+ldap_mail="${MINDOC_LDAP_MAIL||mail}"
#搜索范围
-ldap_base=DC=example,DC=com
+ldap_base="${MINDOC_LDAP_BASE||dc=example,dc=com}"
#第一次绑定ldap用户dn
-ldap_user=CN=ldap helper,OU=example.com,DC=example,DC=com
+ldap_user="${MINDOC_LDAP_USER||cn=ldap helper,ou=example.com,dc=example,dc=com}"
#第一次绑定ldap用户密码
-ldap_password=superSecret
+ldap_password="${MINDOC_LDAP_PASSWORD||xxx}"
#自动注册用户角色:0 超级管理员 /1 管理员/ 2 普通用户
-ldap_user_role=2
+ldap_user_role=${MINDOC_LDAP_USER_ROLE||2}
#ldap搜索filter规则,AD服务器: objectClass=User, openldap服务器: objectClass=posixAccount ,也可以定义为其他属性,如: title=mindoc
-ldap_filter=objectClass=posixAccount
+ldap_filter="${MINDOC_LDAP_FILTER||objectClass=posixAccount}"
############# HTTP自定义接口登录 ################
http_login_url=
@@ -222,15 +232,6 @@ dingtalk_app_key="${MINDOC_DINGTALK_APPKEY}"
# 钉钉AppSecret
dingtalk_app_secret="${MINDOC_DINGTALK_APPSECRET}"
-# 钉钉登录默认只读账号
-dingtalk_tmp_reader="${MINDOC_DINGTALK_READER}"
-
-# 钉钉扫码登录Key
-dingtalk_qr_key="${MINDOC_DINGTALK_QRKEY}"
-
-# 钉钉扫码登录Secret
-dingtalk_qr_secret="${MINDOC_DINGTALK_QRSECRET}"
-
########企业微信登录配置##############
# 企业ID
@@ -242,8 +243,5 @@ workweixin_agentid="${MINDOC_WORKWEIXIN_AGENTID}"
# 应用密钥
workweixin_secret="${MINDOC_WORKWEIXIN_SECRET}"
-# 通讯录密钥
-workweixin_contact_secret="${MINDOC_WORKWEIXIN_CONTACT_SECRET}"
-
# i18n config
default_lang="zh-cn"
diff --git a/conf/enumerate.go b/conf/enumerate.go
index 507f564ad..c4a986b06 100644
--- a/conf/enumerate.go
+++ b/conf/enumerate.go
@@ -19,7 +19,7 @@ const CaptchaSessionName = "__captcha__"
const RegexpEmail = "^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
-//允许用户名中出现点号
+// 允许用户名中出现点号
const RegexpAccount = `^[a-zA-Z0-9][a-zA-Z0-9\.-]{2,50}$`
// PageSize 默认分页条数.
@@ -35,7 +35,7 @@ const (
MemberGeneralRole
)
-//系统角色
+// 系统角色
type SystemRole int
const (
@@ -51,7 +51,7 @@ const (
BookRoleNoSpecific
)
-//项目角色
+// 项目角色
type BookRole int
const (
@@ -90,23 +90,23 @@ func GetDatabasePrefix() string {
return web.AppConfig.DefaultString("db_prefix", "md_")
}
-//获取默认头像
+// 获取默认头像
func GetDefaultAvatar() string {
return URLForWithCdnImage(web.AppConfig.DefaultString("avatar", "/static/images/headimgurl.jpg"))
}
-//获取阅读令牌长度.
+// 获取阅读令牌长度.
func GetTokenSize() int {
return web.AppConfig.DefaultInt("token_size", 12)
}
-//获取默认文档封面.
+// 获取默认文档封面.
func GetDefaultCover() string {
return URLForWithCdnImage(web.AppConfig.DefaultString("cover", "/static/images/book.jpg"))
}
-//获取允许的商城文件的类型.
+// 获取允许的商城文件的类型.
func GetUploadFileExt() []string {
ext := web.AppConfig.DefaultString("upload_file_ext", "png|jpg|jpeg|gif|txt|doc|docx|pdf")
@@ -128,9 +128,9 @@ func GetUploadFileExt() []string {
func GetUploadFileSize() int64 {
size := web.AppConfig.DefaultString("upload_file_size", "0")
- if strings.HasSuffix(size, "MB") {
+ if strings.HasSuffix(size, "TB") {
if s, e := strconv.ParseInt(size[0:len(size)-2], 10, 64); e == nil {
- return s * 1024 * 1024
+ return s * 1024 * 1024 * 1024 * 1024
}
}
if strings.HasSuffix(size, "GB") {
@@ -138,28 +138,33 @@ func GetUploadFileSize() int64 {
return s * 1024 * 1024 * 1024
}
}
+ if strings.HasSuffix(size, "MB") {
+ if s, e := strconv.ParseInt(size[0:len(size)-2], 10, 64); e == nil {
+ return s * 1024 * 1024
+ }
+ }
if strings.HasSuffix(size, "KB") {
if s, e := strconv.ParseInt(size[0:len(size)-2], 10, 64); e == nil {
return s * 1024
}
}
if s, e := strconv.ParseInt(size, 10, 64); e == nil {
- return s * 1024
+ return s
}
return 0
}
-//是否启用导出
+// 是否启用导出
func GetEnableExport() bool {
return web.AppConfig.DefaultBool("enable_export", true)
}
-//是否启用iframe
+// 是否启用iframe
func GetEnableIframe() bool {
return web.AppConfig.DefaultBool("enable_iframe", false)
}
-//同一项目导出线程的并发数
+// 同一项目导出线程的并发数
func GetExportProcessNum() int {
exportProcessNum := web.AppConfig.DefaultInt("export_process_num", 1)
@@ -169,7 +174,7 @@ func GetExportProcessNum() int {
return exportProcessNum
}
-//导出项目队列的并发数量
+// 导出项目队列的并发数量
func GetExportLimitNum() int {
exportLimitNum := web.AppConfig.DefaultInt("export_limit_num", 1)
@@ -179,7 +184,7 @@ func GetExportLimitNum() int {
return exportLimitNum
}
-//等待导出队列的长度
+// 等待导出队列的长度
func GetExportQueueLimitNum() int {
exportQueueLimitNum := web.AppConfig.DefaultInt("export_queue_limit_num", 10)
@@ -189,14 +194,14 @@ func GetExportQueueLimitNum() int {
return exportQueueLimitNum
}
-//默认导出项目的缓存目录
+// 默认导出项目的缓存目录
func GetExportOutputPath() string {
exportOutputPath := filepath.Join(web.AppConfig.DefaultString("export_output_path", filepath.Join(WorkingDirectory, "cache")), "books")
return exportOutputPath
}
-//判断是否是允许商城的文件类型.
+// 判断是否是允许商城的文件类型.
func IsAllowUploadFileExt(ext string) bool {
if strings.HasPrefix(ext, ".") {
@@ -215,7 +220,7 @@ func IsAllowUploadFileExt(ext string) bool {
return false
}
-//读取配置文件值
+// 读取配置文件值
func CONF(key string, value ...string) string {
defaultValue := ""
if len(value) > 0 {
@@ -224,7 +229,7 @@ func CONF(key string, value ...string) string {
return web.AppConfig.DefaultString(key, defaultValue)
}
-//重写生成URL的方法,加上完整的域名
+// 重写生成URL的方法,加上完整的域名
func URLFor(endpoint string, values ...interface{}) string {
baseUrl := web.AppConfig.DefaultString("baseurl", "")
pathUrl := web.URLFor(endpoint, values...)
diff --git a/conf/lang/en-us.ini b/conf/lang/en-us.ini
index a09a76302..c6a7b715a 100644
--- a/conf/lang/en-us.ini
+++ b/conf/lang/en-us.ini
@@ -22,7 +22,9 @@ captcha = Captcha
keep_login = Stay signed in
forgot_password = Forgot password?
register = Create New Account
-dingtalk_login = DingTalk QrCode login
+third_party_login = Third Party Login
+dingtalk_login = DingTalk Login
+wecom_login = WeCom Login
account_recovery = Account recovery
new_password = New password
confirm_password = Confirm password
@@ -313,7 +315,7 @@ prev = prev
next = next
no = no
edit_title = Edit Blog
-private_blog_tips = Private blog is accessible only to author and administrator
+private_blog_tips = Private blog, please enter password to access
[doc]
modify_doc = Modify Document
@@ -365,6 +367,7 @@ gfm_task = GFM task
attachment = attachment
json_to_table = Json converted to table
template = template
+draw = draw
close_preview = disable preview
modify_history = modify history
sidebar = sidebar
diff --git a/conf/lang/zh-cn.ini b/conf/lang/zh-cn.ini
index eb2522f5c..f08944bf1 100644
--- a/conf/lang/zh-cn.ini
+++ b/conf/lang/zh-cn.ini
@@ -22,7 +22,9 @@ captcha = 验证码
keep_login = 保持登录
forgot_password = 忘记密码?
register = 立即注册
-dingtalk_login = 扫码登录
+third_party_login = 第三方登录
+dingtalk_login = 钉钉登录
+wecom_login = 企业微信登录
account_recovery = 找回密码
new_password = 新密码
confirm_password = 确认密码
@@ -313,7 +315,7 @@ prev = 上一篇
next = 下一篇
no = 无
edit_title = 编辑文章
-private_blog_tips = 加密文章,仅作者和管理员可访问
+private_blog_tips = 加密文章,请输入密码访问
[doc]
modify_doc = 修改文档
@@ -365,6 +367,7 @@ gfm_task = GFM 任务列表
attachment = 附件
json_to_table = Json转换为表格
template = 模板
+draw = 画图
close_preview = 关闭实时预览
modify_history = 修改历史
sidebar = 边栏
diff --git a/conf/workweixin.go b/conf/workweixin.go
index bae128f7a..36f4da035 100644
--- a/conf/workweixin.go
+++ b/conf/workweixin.go
@@ -1,27 +1,27 @@
package conf
import (
- "github.com/beego/beego/v2/server/web"
+ "github.com/beego/beego/v2/server/web"
)
type WorkWeixinConf struct {
- CorpId string // 企业ID
- AgentId string // 应用ID
- Secret string // 应用密钥
- ContactSecret string // 通讯录密钥
+ CorpId string // 企业ID
+ AgentId string // 应用ID
+ Secret string // 应用密钥
+ // ContactSecret string // 通讯录密钥
}
func GetWorkWeixinConfig() *WorkWeixinConf {
- corpid, _ := web.AppConfig.String("workweixin_corpid")
- agentid, _ := web.AppConfig.String("workweixin_agentid")
- secret, _ := web.AppConfig.String("workweixin_secret")
- contact_secret, _ := web.AppConfig.String("workweixin_contact_secret")
+ corpid, _ := web.AppConfig.String("workweixin_corpid")
+ agentid, _ := web.AppConfig.String("workweixin_agentid")
+ secret, _ := web.AppConfig.String("workweixin_secret")
+ // contact_secret, _ := web.AppConfig.String("workweixin_contact_secret")
- c := &WorkWeixinConf{
- CorpId: corpid,
- AgentId: agentid,
- Secret: secret,
- ContactSecret: contact_secret,
- }
- return c
+ c := &WorkWeixinConf{
+ CorpId: corpid,
+ AgentId: agentid,
+ Secret: secret,
+ // ContactSecret: contact_secret,
+ }
+ return c
}
diff --git a/controllers/AccountController.go b/controllers/AccountController.go
index cb59b1346..57c9bcbbe 100644
--- a/controllers/AccountController.go
+++ b/controllers/AccountController.go
@@ -1,14 +1,18 @@
package controllers
import (
+ "context"
"encoding/json"
- "fmt"
+ "errors"
+ "github.com/mindoc-org/mindoc/cache"
+ "github.com/mindoc-org/mindoc/utils/auth2"
+ "github.com/mindoc-org/mindoc/utils/auth2/dingtalk"
+ "github.com/mindoc-org/mindoc/utils/auth2/wecom"
"html/template"
"math/rand"
+ "net/http"
"net/url"
- "reflect"
"regexp"
- "strconv"
"strings"
"time"
@@ -21,14 +25,11 @@ import (
"github.com/mindoc-org/mindoc/mail"
"github.com/mindoc-org/mindoc/models"
"github.com/mindoc-org/mindoc/utils"
- "github.com/mindoc-org/mindoc/utils/dingtalk"
- "github.com/mindoc-org/mindoc/utils/workweixin"
)
const (
- WorkWeixin_AuthorizeUrlBase = "https://open.weixin.qq.com/connect/oauth2/authorize"
- WorkWeixin_QRConnectUrlBase = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect"
- SessionUserInfoKey = "session-user-info-key"
+ SessionUserInfoKey = "session-user-info-key"
+ AccessTokenCacheKey = "access-token-cache-key"
)
var src = rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -46,7 +47,7 @@ func (c *AccountController) referer() string {
return u
}
-func (c *AccountController) IsInWorkWeixin() (is_in_workweixin bool) {
+func (c *AccountController) IsInWorkWeixin() bool {
ua := c.Ctx.Input.UserAgent()
var wechatRule = regexp.MustCompile(`\bMicroMessenger\/\d+(\.\d+)*\b`)
var wxworkRule = regexp.MustCompile(`\bwxwork\/\d+(\.\d+)*\b`)
@@ -58,15 +59,8 @@ func (c *AccountController) Prepare() {
c.EnableXSRF = web.AppConfig.DefaultBool("enablexsrf", true)
c.Data["xsrfdata"] = template.HTML(c.XSRFFormHTML())
-
c.Data["CanLoginWorkWeixin"] = len(web.AppConfig.DefaultString("workweixin_corpid", "")) > 0
-
- c.Data["corpID"], _ = web.AppConfig.String("dingtalk_corpid")
- c.Data["CanLoginDingTalk"] = len(web.AppConfig.DefaultString("dingtalk_corpid", "")) > 0
- if reflect.ValueOf(c.Data["CanLoginDingTalk"]).Bool() {
- c.Data["ENABLE_QR_DINGTALK"] = true
- }
- c.Data["dingtalk_qr_key"], _ = web.AppConfig.String("dingtalk_qr_key")
+ c.Data["CanLoginDingTalk"] = len(web.AppConfig.DefaultString("dingtalk_app_key", "")) > 0
if !c.EnableXSRF {
return
@@ -163,196 +157,175 @@ func (c *AccountController) Login() {
logs.Error("用户登录 ->", err)
c.JsonResult(500, i18n.Tr(c.Lang, "message.wrong_account_password"), nil)
}
+ return
+ }
+
+ referer := c.referer()
+ u := c.GetString("url")
+ if u == "" {
+ u = referer
+ if u == "" {
+ u = conf.BaseUrl
+ }
} else {
- // 默认登录方式
- login_method := "AccountController.Login"
- var redirect_uri string
- // 企业微信登录检查
- canLoginWorkWeixin := reflect.ValueOf(c.Data["CanLoginWorkWeixin"]).Bool()
- referer := c.referer()
- if canLoginWorkWeixin {
- // 企业微信登录方式
- login_method = "AccountController.WorkWeixinLogin"
- u := c.GetString("url")
- if u == "" {
- u = referer
- if u == "" {
- u = conf.BaseUrl
- }
- } else {
- var schemaRule = regexp.MustCompile(`^https?\:\/\/`)
- if !schemaRule.MatchString(u) {
- u = conf.BaseUrl + u
- }
- }
- redirect_uri = conf.URLFor(login_method, "url", url.PathEscape(u))
- // 是否在企业微信内部打开
- isInWorkWeixin := c.IsInWorkWeixin()
- c.Data["IsInWorkWeixin"] = isInWorkWeixin
- if isInWorkWeixin {
- // 客户端拥有微信标识和企业微信标识
- c.Redirect(redirect_uri, 302)
- return
- } else {
- c.Data["workweixin_login_url"] = redirect_uri
- }
+ var schemaRule = regexp.MustCompile(`^https?\:\/\/`)
+ if !schemaRule.MatchString(u) {
+ u = conf.BaseUrl + u
}
- c.Data["url"] = referer
}
-}
+ c.Data["url"] = referer
-// 钉钉登录
-func (c *AccountController) DingTalkLogin() {
- code := c.GetString("dingtalk_code")
- if code == "" {
- c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_obtain_user_info"), nil)
+ auth2Redirect := "AccountController.Auth2Redirect"
+ if can, _ := c.Data["CanLoginWorkWeixin"].(bool); can {
+ c.Data["workweixin_login_url"] = conf.URLFor(auth2Redirect, ":app", wecom.AppName, "url", url.PathEscape(u))
}
- appKey, _ := web.AppConfig.String("dingtalk_app_key")
- appSecret, _ := web.AppConfig.String("dingtalk_app_secret")
- tmpReader, _ := web.AppConfig.String("dingtalk_tmp_reader")
+ if can, _ := c.Data["CanLoginDingTalk"].(bool); can {
+ c.Data["dingtalk_login_url"] = conf.URLFor(auth2Redirect, ":app", dingtalk.AppName, "url", url.PathEscape(u))
- if appKey == "" || appSecret == "" || tmpReader == "" {
- c.JsonResult(500, i18n.Tr(c.Lang, "message.dingtalk_auto_login_not_enable"), nil)
- c.StopRun()
}
+ return
+}
- dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
- err := dingtalkAgent.GetAccesstoken()
- if err != nil {
- logs.Warn("获取钉钉临时Token失败 ->", err)
- c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
- c.StopRun()
- }
+/*
+Auth2.0 第三方对接思路:
+1. Auth2Redirect: 点击相应第三方接口,路由重定向至第三方提供的Auth2.0地址
+2. Auth2Callback: 第三方回调处理,接收回调的授权码,并获取用户信息
+ 已绑定: 则读取用户信息,直接登录
+ 未绑定: 则弹窗提示(需要敏感信息)
+ a) Auth2BindAccount: 绑定已有账户(用户名+密码)
+ b) Auth2AutoAccount: 自动创建账户,以第三方用户ID作为用户名,密码123456。
+ 用该方式创建的账户,无法使用账号密码登录,需要修改一次密码后才可以进行账号密码登录。
+*/
- userid, err := dingtalkAgent.GetUserIDByCode(code)
- if err != nil {
- logs.Warn("获取钉钉用户ID失败 ->", err)
- c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
- c.StopRun()
+func (c *AccountController) getAuth2Client() (auth2.Client, error) {
+ app := c.Ctx.Input.Param(":app")
+ var client auth2.Client
+ tokenKey := AccessTokenCacheKey + "-" + app
+
+ switch app {
+ case wecom.AppName:
+ if can, _ := c.Data["CanLoginWorkWeixin"].(bool); !can {
+ return nil, errors.New("auth2.client.wecom.disabled")
+ }
+ corpId, _ := web.AppConfig.String("workweixin_corpid")
+ agentId, _ := web.AppConfig.String("workweixin_agentid")
+ secret, _ := web.AppConfig.String("workweixin_secret")
+ client = wecom.NewClient(corpId, agentId, secret)
+
+ case dingtalk.AppName:
+ if can, _ := c.Data["CanLoginDingTalk"].(bool); !can {
+ return nil, errors.New("auth2.client.dingtalk.disabled")
+ }
+
+ appKey, _ := web.AppConfig.String("dingtalk_app_key")
+ appSecret, _ := web.AppConfig.String("dingtalk_app_secret")
+ client = dingtalk.NewClient(appSecret, appKey)
+
+ default:
+ return nil, errors.New("auth2.client.notsupported")
}
- username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
+ var tokenCache auth2.AccessTokenCache
+ err := cache.Get(tokenKey, &tokenCache)
if err != nil {
- logs.Warn("获取钉钉用户信息失败 ->", err)
- c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
- c.StopRun()
+ logs.Info("AccessToken从缓存读取失败")
+ token, err := client.GetAccessToken(context.Background())
+ if err != nil {
+ return client, nil
+ }
+ tokenCache = auth2.NewAccessToken(token)
+ cache.Put(tokenKey, tokenCache, tokenCache.GetExpireIn())
}
- member, err := models.NewMember().TmpLogin(tmpReader)
- if err == nil {
- member.LastLoginTime = time.Now()
- _ = member.Update("last_login_time")
- member.Account = username
- if avatar != "" {
- member.Avatar = avatar
+ // 处理过期Token
+ if tokenCache.IsExpired() {
+ token, err := client.GetAccessToken(context.Background())
+ if err != nil {
+ return client, nil
}
+ tokenCache = auth2.NewAccessToken(token)
+ cache.Put(tokenKey, tokenCache, tokenCache.GetExpireIn())
+ }
+
+ client.SetAccessToken(tokenCache)
+ return client, nil
+}
- c.SetMember(*member)
+func (c *AccountController) parseAuth2CallbackParam() (code, state string) {
+ switch c.Ctx.Input.Param(":app") {
+ case wecom.AppName:
+ code = c.GetString("code")
+ state = c.GetString("state")
+ case dingtalk.AppName:
+ code = c.GetString("authCode")
+ state = c.GetString("state")
}
- c.JsonResult(0, "ok", username)
+
+ logs.Debug("code: ", code)
+ logs.Debug("state: ", state)
+ return
}
-// WorkWeixinLogin 用户企业微信登录
-func (c *AccountController) WorkWeixinLogin() {
- logs.Info("UserAgent: ", c.Ctx.Input.UserAgent()) // debug
+func (c *AccountController) getAuth2Account() (models.Auth2Account, error) {
+ switch c.Ctx.Input.Param(":app") {
+ case wecom.AppName:
+ return models.NewWorkWeixinAccount(), nil
- if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
- u := c.GetString("url")
- if u == "" {
- u = c.Ctx.Request.Header.Get("Referer")
- if u == "" {
- u = conf.URLFor("HomeController.Index")
- }
- }
- // session自动登录时刷新session内容
- member, err := models.NewMember().Find(member.MemberId)
- if err != nil {
- c.DelSession(conf.LoginSessionName)
- c.SetMember(models.Member{})
- c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
- } else {
- c.SetMember(*member)
- }
- c.Redirect(u, 302)
+ case dingtalk.AppName:
+ return models.NewDingTalkAccount(), nil
}
- var remember CookieRemember
- // 如果 Cookie 中存在登录信息
- if cookie, ok := c.GetSecureCookie(conf.GetAppKey(), "login"); ok {
- if err := utils.Decode(cookie, &remember); err == nil {
- if member, err := models.NewMember().Find(remember.MemberId); err == nil {
- c.SetMember(*member)
- c.LoggedIn(false)
- c.StopRun()
- }
- }
+
+ return nil, errors.New("auth2.account.notsupported")
+}
+
+// Auth2Redirect 第三方auth2.0登录: 钉钉、企业微信
+func (c *AccountController) Auth2Redirect() {
+ client, err := c.getAuth2Client()
+ if err != nil {
+ c.DelSession(conf.LoginSessionName)
+ c.SetMember(models.Member{})
+ c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+ c.StopRun()
+ return
}
- if c.Ctx.Input.IsPost() {
- // account := c.GetString("account")
- // password := c.GetString("password")
- // captcha := c.GetString("code")
- // isRemember := c.GetString("is_remember")
- c.JsonResult(400, "request method not allowed", nil)
- } else {
- var callback_u string
- u := c.GetString("url")
- if u == "" {
- u = c.referer()
- }
- if u != "" {
- var schemaRule = regexp.MustCompile(`^https?\:\/\/`)
- if !schemaRule.MatchString(u) {
- u = strings.TrimRight(conf.BaseUrl, "/") + strings.TrimLeft(u, "/")
- }
- }
- if u == "" {
- callback_u = conf.URLFor("AccountController.WorkWeixinLoginCallback")
- } else {
- callback_u = conf.URLFor("AccountController.WorkWeixinLoginCallback", "url", url.PathEscape(u))
- }
- logs.Info("callback_u: ", callback_u) // debug
-
- state := "mindoc"
- workweixinConf := conf.GetWorkWeixinConfig()
- appid := workweixinConf.CorpId
- agentid := workweixinConf.AgentId
- var redirect_uri string
-
- isInWorkWeixin := c.IsInWorkWeixin()
- c.Data["IsInWorkWeixin"] = isInWorkWeixin
- if isInWorkWeixin {
- // 企业微信内-网页授权登录
- urlFmt := "%s?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=%s#wechat_redirect"
- redirect_uri = fmt.Sprintf(urlFmt, WorkWeixin_AuthorizeUrlBase, appid, url.PathEscape(callback_u), state)
- } else {
- // 浏览器内-扫码授权登录
- urlFmt := "%s?appid=%s&agentid=%s&redirect_uri=%s&state=%s"
- redirect_uri = fmt.Sprintf(urlFmt, WorkWeixin_QRConnectUrlBase, appid, agentid, url.PathEscape(callback_u), state)
+ app := c.Ctx.Input.Param(":app")
+ var isAppBrowser bool
+ switch app {
+ case wecom.AppName:
+ isAppBrowser = c.IsInWorkWeixin()
+ }
+
+ var callback string
+ u := c.GetString("url")
+ if u == "" {
+ u = c.referer()
+ callback = conf.URLFor("AccountController.Auth2Callback", ":app", app)
+ }
+ if u != "" {
+ var schemaRule = regexp.MustCompile(`^https?\:\/\/`)
+ if !schemaRule.MatchString(u) {
+ u = strings.TrimRight(conf.BaseUrl, "/") + strings.TrimLeft(u, "/")
}
- logs.Info("redirect_uri: ", redirect_uri) // debug
- c.Redirect(redirect_uri, 302)
+ callback = conf.URLFor("AccountController.Auth2Callback", ":app", app, "url", url.PathEscape(u))
}
-}
-/*
-思路:
-1. 浏览器打开
- 用户名+密码 登录 与企业微信没有交集
- 手机企业微信登录->扫码页面->扫码后获取用户信息, 判断是否绑定了企业微信
- 已绑定,则读取用户信息,直接登录
- 未绑定,则弹窗提示[未绑定企业微信,请先在企业微信中打开,完成绑定]
-2. 企业微信打开->自动登录->判断是否绑定了企业微信
- 已绑定,则读取用户信息,直接登录
- 未绑定,则弹窗提示
- 是否已有账户(用户名+密码方式)
- 有: 弹窗输入[用户名+密码+验证码]校验
- 无: 直接以企业UserId作为用户名(小写),创建随机密码
-*/
+ logs.Debug("callback: ", callback) // debug
+ c.Redirect(client.BuildURL(callback, isAppBrowser), http.StatusFound)
+}
-// WorkWeixinLoginCallback 用户企业微信登录-回调
-func (c *AccountController) WorkWeixinLoginCallback() {
- c.TplName = "account/workweixin-login-callback.tpl"
+// Auth2Callback 第三方auth2.0回调
+func (c *AccountController) Auth2Callback() {
+ client, err := c.getAuth2Client()
+ if err != nil {
+ c.DelSession(conf.LoginSessionName)
+ c.SetMember(models.Member{})
+ c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+ c.StopRun()
+ logs.Error(err)
+ return
+ }
if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
u := c.GetString("url")
@@ -385,356 +358,782 @@ func (c *AccountController) WorkWeixinLoginCallback() {
}
}
+ c.TplName = "account/auth2_callback.tpl"
+ bindExisted := "false"
+ errMsg := ""
+ userInfoJson := "{}"
+ defer func() {
+ c.Data["bind_existed"] = template.JS(bindExisted)
+ logs.Debug("bind_existed: ", bindExisted)
+ c.Data["error_msg"] = template.JS(errMsg)
+ c.Data["user_info_json"] = template.JS(userInfoJson)
+ c.Data["app"] = template.JS(c.Ctx.Input.Param(":app"))
+ }()
+
// 请求参数获取
- req_code := c.GetString("code")
- logs.Warning("req_code: ", req_code)
- req_state := c.GetString("state")
- logs.Warning("req_state: ", req_state)
- var user_info_json string
- var error_msg string
- var bind_existed string
- if len(req_code) > 0 && req_state == "mindoc" {
- // 获取当前应用的access_token
- access_token, ok := workweixin.GetAccessToken(false)
- if ok {
- logs.Warning("access_token: ", access_token)
- // 获取当前请求的userid
- user_id, ok := workweixin.RequestUserId(access_token, req_code)
- if ok {
- logs.Warning("user_id: ", user_id)
- // 获取通讯录应用的access_token
- contact_access_token, ok := workweixin.GetAccessToken(true)
- if ok {
- logs.Warning("contact_access_token: ", contact_access_token)
- user_info, err_msg, ok := workweixin.RequestUserInfo(contact_access_token, user_id)
- if ok {
- // [-------所有字段-Debug----------
- // user_info.UserId
- // user_info.Name
- // user_info.HideMobile
- // user_info.Mobile
- // user_info.Department
- // user_info.Email
- // user_info.IsLeaderInDept
- // user_info.IsLeader
- // user_info.Avatar
- // user_info.Alias
- // user_info.Status
- // user_info.MainDepartment
- // -----------------------------]
- // logs.Debug("user_info.UserId: ", user_info.UserId)
- // logs.Debug("user_info.Name: ", user_info.Name)
- json_info, _ := json.Marshal(user_info)
- user_info_json = string(json_info)
- // 查询系统现有数据,是否绑定了当前请求用户的企业微信
- member, err := models.NewWorkWeixinAccount().ExistedMember(user_info.UserId)
- if err == nil {
- member.LastLoginTime = time.Now()
- _ = member.Update("last_login_time")
-
- c.SetMember(*member)
-
- var remember CookieRemember
- remember.MemberId = member.MemberId
- remember.Account = member.Account
- remember.Time = time.Now()
- v, err := utils.Encode(remember)
- if err == nil {
- c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
- }
- bind_existed = "true"
- error_msg = ""
- u := c.GetString("url")
- if u == "" {
- u = conf.URLFor("HomeController.Index")
- }
- c.Redirect(u, 302)
- } else {
- if err == orm.ErrNoRows {
- c.SetSession(SessionUserInfoKey, user_info)
- bind_existed = "false"
- error_msg = ""
- } else {
- logs.Error("Error: ", err)
- error_msg = "数据库错误: " + err.Error()
- }
- }
- //
- } else {
- error_msg = "获取用户信息失败: " + err_msg
- }
- } else {
- error_msg = "通讯录访问凭据获取失败: " + contact_access_token
- }
+ code, state := c.parseAuth2CallbackParam()
+ if err := client.ValidateCallback(state); err != nil {
+ c.DelSession(conf.LoginSessionName)
+ c.SetMember(models.Member{})
+ c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+ errMsg = err.Error()
+ logs.Error(err)
+ return
+ }
+
+ userInfo, err := client.GetUserInfo(context.Background(), code)
+ if err != nil {
+ c.DelSession(conf.LoginSessionName)
+ c.SetMember(models.Member{})
+ c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+ errMsg = err.Error()
+ logs.Error(err)
+ return
+ }
+
+ account, err := c.getAuth2Account()
+ if err != nil {
+ logs.Error("获取Auth2用户失败 ->", err)
+ c.JsonResult(500, "不支持的第三方用户", nil)
+ return
+ }
+
+ member, err := account.ExistedMember(userInfo.UserId)
+ if err != nil {
+ if err == orm.ErrNoRows {
+ if userInfo.Mobile == "" {
+ errMsg = "请到应用浏览器中登录,并授权获取敏感信息。"
} else {
- error_msg = "获取用户Id失败: " + user_id
+ jsonInfo, _ := json.Marshal(userInfo)
+ userInfoJson = string(jsonInfo)
+ errMsg = ""
+ c.SetSession(SessionUserInfoKey, userInfo)
}
} else {
- error_msg = "应用凭据获取失败: " + access_token
+ logs.Error("Error: ", err)
+ errMsg = "登录错误: " + err.Error()
}
- } else {
- error_msg = "参数错误"
- }
- if user_info_json == "" {
- user_info_json = "{}"
- }
- if bind_existed == "" {
- bind_existed = "null"
- }
- // refer & doc:
- // - https://golang.org/pkg/html/template/#HTML
- // - https://stackoverflow.com/questions/24411880/go-html-templates-can-i-stop-the-templates-package-inserting-quotes-around-stri
- // - https://stackoverflow.com/questions/38035176/insert-javascript-snippet-inside-template-with-beego-golang
- c.Data["bind_existed"] = template.JS(bind_existed)
- logs.Debug("bind_existed: ", bind_existed)
- c.Data["error_msg"] = template.JS(error_msg)
- c.Data["user_info_json"] = template.JS(user_info_json)
- /*
- // 调试: 显示源码
- result, err := c.RenderString()
- if err != nil {
- logs.Error(err)
- } else {
- logs.Warning(result)
- }
- */
-}
+ return
+ }
-// WorkWeixinLoginBind 用户企业微信登录-绑定
-func (c *AccountController) WorkWeixinLoginBind() {
- if user_info, ok := c.GetSession(SessionUserInfoKey).(workweixin.WorkWeixinUserInfo); ok && len(user_info.UserId) > 0 {
- req_account := c.GetString("account")
- req_password := c.GetString("password")
- if req_account == "" || req_password == "" {
- c.JsonResult(400, "账号或密码不能为空")
- } else {
- member, err := models.NewMember().Login(req_account, req_password)
- if err == nil {
- account := models.NewWorkWeixinAccount()
- account.MemberId = member.MemberId
- account.WorkWeixin_UserId = user_info.UserId
- member.CreateAt = 0
- ormer := orm.NewOrm()
- o, err := ormer.Begin()
- if err != nil {
- logs.Error("开启事物时出错 -> ", err)
- c.JsonResult(500, "开启事物时出错: ", err.Error())
- }
- if err := account.AddBind(ormer); err != nil {
- o.Rollback()
- c.JsonResult(500, "绑定失败,数据库错误: "+err.Error())
- } else {
- member.LastLoginTime = time.Now()
- member.RealName = user_info.Name
- member.Avatar = user_info.Avatar
- if len(member.Avatar) < 1 {
- member.Avatar = conf.GetDefaultAvatar()
- }
- member.Email = user_info.Email
- member.Phone = user_info.Mobile
- if _, err := ormer.Update(member, "last_login_time", "real_name", "avatar", "email", "phone"); err != nil {
- o.Rollback()
- logs.Error("保存用户信息失败=>", err)
- c.JsonResult(500, "绑定失败,现有账户信息更新失败: "+err.Error())
- } else {
- if err := o.Commit(); err != nil {
- logs.Error("提交事物时出错 -> ", err)
- c.JsonResult(500, "提交事物时出错: ", err.Error())
- } else {
- c.DelSession(SessionUserInfoKey)
- c.SetMember(*member)
-
- var remember CookieRemember
- remember.MemberId = member.MemberId
- remember.Account = member.Account
- remember.Time = time.Now()
- v, err := utils.Encode(remember)
- if err == nil {
- c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
- c.JsonResult(0, "绑定成功", nil)
- } else {
- c.JsonResult(500, "绑定成功, 但自动登录失败, 请返回首页重新登录", nil)
- }
- }
- }
+ bindExisted = "true"
+ errMsg = ""
- }
+ member.LastLoginTime = time.Now()
+ _ = member.Update("last_login_time")
- } else {
- logs.Error("用户登录 ->", err)
- c.JsonResult(500, "账号或密码错误", nil)
- }
- c.JsonResult(500, "TODO: 绑定以后账号功能开发中")
- }
- } else {
- if ok {
- c.DelSession(SessionUserInfoKey)
- }
- c.JsonResult(400, "请求错误, 请从首页重新登录")
+ c.SetMember(*member)
+ remember.MemberId = member.MemberId
+ remember.Account = member.Account
+ remember.Time = time.Now()
+ v, err := utils.Encode(remember)
+ if err == nil {
+ c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
}
+ u := c.GetString("url")
+ if u == "" {
+ u = conf.URLFor("HomeController.Index")
+ }
+ c.Redirect(u, 302)
}
-// WorkWeixinLoginIgnore 用户企业微信登录-忽略
-func (c *AccountController) WorkWeixinLoginIgnore() {
- if user_info, ok := c.GetSession(SessionUserInfoKey).(workweixin.WorkWeixinUserInfo); ok && len(user_info.UserId) > 0 {
+// Auth2BindAccount 第三方auth2.0绑定已有账号
+func (c *AccountController) Auth2BindAccount() {
+ userInfo, ok := c.GetSession(SessionUserInfoKey).(auth2.UserInfo)
+ if !ok || len(userInfo.UserId) <= 0 {
c.DelSession(SessionUserInfoKey)
- member := models.NewMember()
+ c.JsonResult(400, "请求错误, 请从首页重新登录")
+ return
+ }
- if _, err := member.FindByAccount(user_info.UserId); err == nil && member.MemberId > 0 {
- c.JsonResult(400, "账号已存在")
- }
+ account := c.GetString("account")
+ password := c.GetString("password")
+ if account == "" || password == "" {
+ c.JsonResult(400, "账号或密码不能为空")
+ return
+ }
- ormer := orm.NewOrm()
- o, err := ormer.Begin()
- if err != nil {
- logs.Error("开启事物时出错 -> ", err)
- c.JsonResult(500, "开启事物时出错: ", err.Error())
- }
+ member, err := models.NewMember().Login(account, password)
+ if err != nil {
+ logs.Error("用户登录 ->", err)
+ c.JsonResult(500, "账号或密码错误", nil)
+ return
+ }
- member.Account = user_info.UserId
- member.RealName = user_info.Name
- var rnd = rand.New(src)
- // fmt.Sprintf("%x", rnd.Uint64())
- // strconv.FormatUint(rnd.Uint64(), 16)
- member.Password = user_info.UserId + strconv.FormatUint(rnd.Uint64(), 16)
- member.Password = "pathea.2020" // 强制设置默认密码,不然无法修改密码(因为目前修改密码需要知道当前密码)
- hash, err := utils.PasswordHash(member.Password)
- if err != nil {
- logs.Error("加密用户密码失败 =>", err)
- c.JsonResult(500, "加密用户密码失败"+err.Error())
- } else {
- logs.Error("member.Password: ", member.Password)
- logs.Error("hash: ", hash)
- member.Password = hash
- }
- member.Role = conf.MemberGeneralRole
- member.Avatar = user_info.Avatar
- if len(member.Avatar) < 1 {
- member.Avatar = conf.GetDefaultAvatar()
- }
- member.CreateAt = 0
- member.Email = user_info.Email
- member.Phone = user_info.Mobile
- member.Status = 0
- if _, err = ormer.Insert(member); err != nil {
- o.Rollback()
- c.JsonResult(500, "注册失败,数据库错误: "+err.Error())
- } else {
- account := models.NewWorkWeixinAccount()
- account.MemberId = member.MemberId
- account.WorkWeixin_UserId = user_info.UserId
- member.CreateAt = 0
- if err := account.AddBind(ormer); err != nil {
- o.Rollback()
- c.JsonResult(500, "注册失败,数据库错误: "+err.Error())
- } else {
- if err := o.Commit(); err != nil {
- logs.Error("提交事物时出错 -> ", err)
- c.JsonResult(500, "提交事物时出错: ", err.Error())
- } else {
- member.LastLoginTime = time.Now()
- _ = member.Update("last_login_time")
-
- c.SetMember(*member)
-
- var remember CookieRemember
- remember.MemberId = member.MemberId
- remember.Account = member.Account
- remember.Time = time.Now()
- v, err := utils.Encode(remember)
- if err == nil {
- c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
- c.JsonResult(0, "绑定成功", nil)
- } else {
- c.JsonResult(500, "绑定成功, 但自动登录失败, 请返回首页重新登录", nil)
- }
- }
- }
- }
- } else {
- if ok {
- c.DelSession(SessionUserInfoKey)
- }
- c.JsonResult(400, "请求错误, 请从首页重新登录")
+ bindAccount, err := c.getAuth2Account()
+ if err != nil {
+ logs.Error("获取Auth2用户失败 ->", err)
+ c.JsonResult(500, "不支持的第三方用户", nil)
+ return
+ }
+
+ member.CreateAt = 0
+ ormer := orm.NewOrm()
+ o, err := ormer.Begin()
+ if err != nil {
+ logs.Error("开启事务时出错 -> ", err)
+ c.JsonResult(500, "开启事务时出错: ", err.Error())
+ return
+ }
+ if err := bindAccount.AddBind(ormer, userInfo, member); err != nil {
+ logs.Error(err)
+ o.Rollback()
+ c.JsonResult(500, "绑定失败,数据库错误: "+err.Error())
+ return
}
+
+ // 绑定成功之后修改用户信息
+ member.LastLoginTime = time.Now()
+ //member.RealName = user_info.Name
+ //member.Avatar = user_info.Avatar
+ if len(member.Avatar) < 1 {
+ member.Avatar = conf.GetDefaultAvatar()
+ }
+ //member.Email = user_info.Email
+ //member.Phone = user_info.Mobile
+ if _, err := ormer.Update(member, "last_login_time", "real_name", "avatar", "email", "phone"); err != nil {
+ o.Rollback()
+ logs.Error("保存用户信息失败=>", err)
+ c.JsonResult(500, "绑定失败,现有账户信息更新失败: "+err.Error())
+ return
+
+ }
+
+ if err := o.Commit(); err != nil {
+ logs.Error("开启事务时出错 -> ", err)
+ c.JsonResult(500, "开启事务时出错: ", err.Error())
+ return
+ }
+
+ c.DelSession(SessionUserInfoKey)
+ c.SetMember(*member)
+
+ var remember CookieRemember
+ remember.MemberId = member.MemberId
+ remember.Account = member.Account
+ remember.Time = time.Now()
+ v, err := utils.Encode(remember)
+ if err != nil {
+ c.JsonResult(500, "绑定成功, 但自动登录失败, 请返回首页重新登录", nil)
+ return
+ }
+
+ c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
+ c.JsonResult(0, "绑定成功", nil)
}
-// QR二维码登录
-func (c *AccountController) QRLogin() {
- appName := c.Ctx.Input.Param(":app")
-
- switch appName {
- // 钉钉扫码登录
- case "dingtalk":
- code := c.GetString("code")
- state := c.GetString("state")
- if state != "1" || code == "" {
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
- c.StopRun()
- }
- appKey, _ := web.AppConfig.String("dingtalk_qr_key")
- appSecret, _ := web.AppConfig.String("dingtalk_qr_secret")
+// Auth2AutoAccount auth2.0自动创建账号
+func (c *AccountController) Auth2AutoAccount() {
+ app := c.Ctx.Input.Param(":app")
+ logs.Debug("app: ", app)
- qrDingtalk := dingtalk.NewDingtalkQRLogin(appSecret, appKey)
- unionID, err := qrDingtalk.GetUnionIDByCode(code)
- if err != nil {
- logs.Warn("获取钉钉临时UnionID失败 ->", err)
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
- c.StopRun()
- }
+ userInfo, ok := c.GetSession(SessionUserInfoKey).(auth2.UserInfo)
+ if !ok || len(userInfo.UserId) <= 0 {
+ c.DelSession(SessionUserInfoKey)
+ c.JsonResult(400, "请求错误, 请从首页重新登录")
+ return
+ }
- appKey, _ = web.AppConfig.String("dingtalk_app_key")
- appSecret, _ = web.AppConfig.String("dingtalk_app_secret")
- tmpReader, _ := web.AppConfig.String("dingtalk_tmp_reader")
+ c.DelSession(SessionUserInfoKey)
+ member := models.NewMember()
- dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
- err = dingtalkAgent.GetAccesstoken()
- if err != nil {
- logs.Warn("获取钉钉临时Token失败 ->", err)
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
- c.StopRun()
- }
+ if _, err := member.FindByAccount(userInfo.UserId); err == nil && member.MemberId > 0 {
+ c.JsonResult(400, "账号已存在")
+ return
+ }
- userid, err := dingtalkAgent.GetUserIDByUnionID(unionID)
- if err != nil {
- logs.Warn("获取钉钉用户ID失败 ->", err)
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
- c.StopRun()
- }
+ ormer := orm.NewOrm()
+ o, err := ormer.Begin()
+ if err != nil {
+ logs.Error("开启事务时出错 -> ", err)
+ c.JsonResult(500, "开启事务时出错: ", err.Error())
+ return
+ }
- username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
- if err != nil {
- logs.Warn("获取钉钉用户信息失败 ->", err)
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
- c.StopRun()
- }
+ member.Account = userInfo.UserId
+ member.RealName = userInfo.Name
+ member.Password = "123456" // 强制设置默认密码,需修改一次密码后,才可以进行账号密码登录
+ hash, err := utils.PasswordHash(member.Password)
- member, err := models.NewMember().TmpLogin(tmpReader)
- if err == nil {
- member.LastLoginTime = time.Now()
- _ = member.Update("last_login_time")
- member.Account = username
- if avatar != "" {
- member.Avatar = avatar
- }
+ if err != nil {
+ logs.Error("加密用户密码失败 =>", err)
+ c.JsonResult(500, "加密用户密码失败"+err.Error())
+ return
+ }
- c.SetMember(*member)
- c.LoggedIn(false)
- c.StopRun()
- }
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
+ logs.Debug("member.Password: ", member.Password)
+ logs.Debug("hash: ", hash)
+ member.Password = hash
- // 企业微信扫码登录
- case "workweixin":
- //
+ member.Role = conf.MemberGeneralRole
+ member.Avatar = userInfo.Avatar
+ if len(member.Avatar) < 1 {
+ member.Avatar = conf.GetDefaultAvatar()
+ }
+ member.CreateAt = 0
+ member.Email = userInfo.Mail
+ member.Phone = userInfo.Mobile
+ member.Status = 0
+ if _, err = ormer.Insert(member); err != nil {
+ o.Rollback()
+ c.JsonResult(500, "注册失败,数据库错误: "+err.Error())
+ return
+ }
- default:
- c.Redirect(conf.URLFor("AccountController.Login"), 302)
- c.StopRun()
+ account, err := c.getAuth2Account()
+ if err != nil {
+ logs.Error("获取Auth2用户失败 ->", err)
+ c.JsonResult(500, "不支持的第三方用户", nil)
+ return
+ }
+
+ member.CreateAt = 0
+ if err := account.AddBind(ormer, userInfo, member); err != nil {
+ logs.Error(err)
+ o.Rollback()
+ c.JsonResult(500, "注册失败,数据库错误: "+err.Error())
+ return
+ }
+
+ if err := o.Commit(); err != nil {
+ logs.Error("提交事务时出错 -> ", err)
+ c.JsonResult(500, "提交事务时出错: ", err.Error())
+ return
}
+
+ member.LastLoginTime = time.Now()
+ _ = member.Update("last_login_time")
+
+ c.SetMember(*member)
+
+ var remember CookieRemember
+ remember.MemberId = member.MemberId
+ remember.Account = member.Account
+ remember.Time = time.Now()
+ v, err := utils.Encode(remember)
+ if err != nil {
+ c.JsonResult(500, "绑定成功, 但自动登录失败, 请返回首页重新登录", nil)
+ return
+ }
+
+ c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
+ c.JsonResult(0, "绑定成功", nil)
}
+// 钉钉登录
+//func (c *AccountController) DingTalkLogin() {
+// code := c.GetString("dingtalk_code")
+// if code == "" {
+// c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_obtain_user_info"), nil)
+// }
+//
+// appKey, _ := web.AppConfig.String("dingtalk_app_key")
+// appSecret, _ := web.AppConfig.String("dingtalk_app_secret")
+// tmpReader, _ := web.AppConfig.String("dingtalk_tmp_reader")
+//
+// if appKey == "" || appSecret == "" || tmpReader == "" {
+// c.JsonResult(500, i18n.Tr(c.Lang, "message.dingtalk_auto_login_not_enable"), nil)
+// c.StopRun()
+// }
+//
+// dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
+// err := dingtalkAgent.GetAccesstoken()
+// if err != nil {
+// logs.Warn("获取钉钉临时Token失败 ->", err)
+// c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
+// c.StopRun()
+// }
+//
+// userid, err := dingtalkAgent.GetUserIDByCode(code)
+// if err != nil {
+// logs.Warn("获取钉钉用户ID失败 ->", err)
+// c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
+// c.StopRun()
+// }
+//
+// username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
+// if err != nil {
+// logs.Warn("获取钉钉用户信息失败 ->", err)
+// c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
+// c.StopRun()
+// }
+//
+// member, err := models.NewMember().TmpLogin(tmpReader)
+// if err == nil {
+// member.LastLoginTime = time.Now()
+// _ = member.Update("last_login_time")
+// member.Account = username
+// if avatar != "" {
+// member.Avatar = avatar
+// }
+//
+// c.SetMember(*member)
+// }
+// c.JsonResult(0, "ok", username)
+//}
+
+// WorkWeixinLogin 用户企业微信登录
+//func (c *AccountController) WorkWeixinLogin() {
+// logs.Info("UserAgent: ", c.Ctx.Input.UserAgent()) // debug
+//
+// if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
+// u := c.GetString("url")
+// if u == "" {
+// u = c.Ctx.Request.Header.Get("Referer")
+// if u == "" {
+// u = conf.URLFor("HomeController.Index")
+// }
+// }
+// // session自动登录时刷新session内容
+// member, err := models.NewMember().Find(member.MemberId)
+// if err != nil {
+// c.DelSession(conf.LoginSessionName)
+// c.SetMember(models.Member{})
+// c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+// } else {
+// c.SetMember(*member)
+// }
+// c.Redirect(u, 302)
+// }
+// var remember CookieRemember
+// // 如果 Cookie 中存在登录信息
+// if cookie, ok := c.GetSecureCookie(conf.GetAppKey(), "login"); ok {
+// if err := utils.Decode(cookie, &remember); err == nil {
+// if member, err := models.NewMember().Find(remember.MemberId); err == nil {
+// c.SetMember(*member)
+// c.LoggedIn(false)
+// c.StopRun()
+// }
+// }
+// }
+//
+// if c.Ctx.Input.IsPost() {
+// // account := c.GetString("account")
+// // password := c.GetString("password")
+// // captcha := c.GetString("code")
+// // isRemember := c.GetString("is_remember")
+// c.JsonResult(400, "request method not allowed", nil)
+// } else {
+// var callback_u string
+// u := c.GetString("url")
+// if u == "" {
+// u = c.referer()
+// }
+// if u != "" {
+// var schemaRule = regexp.MustCompile(`^https?\:\/\/`)
+// if !schemaRule.MatchString(u) {
+// u = strings.TrimRight(conf.BaseUrl, "/") + strings.TrimLeft(u, "/")
+// }
+// }
+// if u == "" {
+// callback_u = conf.URLFor("AccountController.WorkWeixinLoginCallback")
+// } else {
+// callback_u = conf.URLFor("AccountController.WorkWeixinLoginCallback", "url", url.PathEscape(u))
+// }
+// logs.Info("callback_u: ", callback_u) // debug
+//
+// state := "mindoc"
+// workweixinConf := conf.GetWorkWeixinConfig()
+// appid := workweixinConf.CorpId
+// agentid := workweixinConf.AgentId
+// var redirect_uri string
+//
+// isInWorkWeixin := c.IsInWorkWeixin()
+// c.Data["IsInWorkWeixin"] = isInWorkWeixin
+// if isInWorkWeixin {
+// // 企业微信内-网页授权登录
+// urlFmt := "%s?appid=%s&agentid=%s&redirect_uri=%s&response_type=code&scope=snsapi_privateinfo&state=%s#wechat_redirect"
+// redirect_uri = fmt.Sprintf(urlFmt, WorkWeixin_AuthorizeUrlBase, appid, agentid, url.PathEscape(callback_u), state)
+// } else {
+// // 浏览器内-扫码授权登录
+// urlFmt := "%s?login_type=CorpApp&appid=%s&agentid=%s&redirect_uri=%s&state=%s"
+// redirect_uri = fmt.Sprintf(urlFmt, WorkWeixin_QRConnectUrlBase, appid, agentid, url.PathEscape(callback_u), state)
+// }
+// logs.Info("redirect_uri: ", redirect_uri) // debug
+// c.Redirect(redirect_uri, 302)
+// }
+//}
+
+/*
+思路:
+1. 浏览器打开
+ 用户名+密码 登录 与企业微信没有交集
+ 手机企业微信登录->扫码页面->扫码后获取用户信息, 判断是否绑定了企业微信
+ 已绑定,则读取用户信息,直接登录
+ 未绑定,则弹窗提示[未绑定企业微信,请先在企业微信中打开,完成绑定]
+2. 企业微信打开->自动登录->判断是否绑定了企业微信
+ 已绑定,则读取用户信息,直接登录
+ 未绑定,则弹窗提示
+ 是否已有账户(用户名+密码方式)
+ 有: 弹窗输入[用户名+密码+验证码]校验
+ 无: 直接以企业UserId作为用户名(小写),创建随机密码
+*/
+
+// WorkWeixinLoginCallback 用户企业微信登录-回调
+//func (c *AccountController) WorkWeixinLoginCallback() {
+// c.TplName = "account/auth2_callback.tpl"
+//
+// if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
+// u := c.GetString("url")
+// if u == "" {
+// u = c.Ctx.Request.Header.Get("Referer")
+// }
+// if u == "" {
+// u = conf.URLFor("HomeController.Index")
+// }
+// member, err := models.NewMember().Find(member.MemberId)
+// if err != nil {
+// c.DelSession(conf.LoginSessionName)
+// c.SetMember(models.Member{})
+// c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+// } else {
+// c.SetMember(*member)
+// }
+// c.Redirect(u, 302)
+// }
+//
+// var remember CookieRemember
+// // 如果 Cookie 中存在登录信息
+// if cookie, ok := c.GetSecureCookie(conf.GetAppKey(), "login"); ok {
+// if err := utils.Decode(cookie, &remember); err == nil {
+// if member, err := models.NewMember().Find(remember.MemberId); err == nil {
+// c.SetMember(*member)
+// c.LoggedIn(false)
+// c.StopRun()
+// }
+// }
+// }
+//
+// // 请求参数获取
+// req_code := c.GetString("code")
+// logs.Warning("req_code: ", req_code)
+// req_state := c.GetString("state")
+// logs.Warning("req_state: ", req_state)
+// var user_info_json string
+// var error_msg string
+// var bind_existed string
+// if len(req_code) > 0 && req_state == "mindoc" {
+// // 获取当前应用的access_token
+// access_token, ok := workweixin.GetAccessToken()
+// if ok {
+// logs.Warning("access_token: ", access_token)
+// // 获取当前请求的userid
+// user_id, ticket, ok := workweixin.RequestUserId(access_token, req_code)
+// if ok {
+// logs.Warning("user_id: ", user_id)
+// // 查询系统现有数据,是否绑定了当前请求用户的企业微信
+// member, err := models.NewWorkWeixinAccount().ExistedMember(user_id)
+// if err == nil {
+// member.LastLoginTime = time.Now()
+// _ = member.Update("last_login_time")
+//
+// c.SetMember(*member)
+//
+// var remember CookieRemember
+// remember.MemberId = member.MemberId
+// remember.Account = member.Account
+// remember.Time = time.Now()
+// v, err := utils.Encode(remember)
+// if err == nil {
+// c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
+// }
+// bind_existed = "true"
+// error_msg = ""
+// u := c.GetString("url")
+// if u == "" {
+// u = conf.URLFor("HomeController.Index")
+// }
+// c.Redirect(u, 302)
+// } else if err == orm.ErrNoRows {
+// bind_existed = "false"
+// if ticket == "" {
+// error_msg = "请到企业微信中登录,并授权获取敏感信息。"
+// } else {
+// user_info, err := workweixin.RequestUserPrivateInfo(access_token, user_id, ticket)
+// if err != nil {
+// error_msg = "获取敏感信息错误: " + err.Error()
+// } else {
+// json_info, _ := json.Marshal(user_info)
+// user_info_json = string(json_info)
+// error_msg = ""
+// c.SetSession(SessionUserInfoKey, user_info)
+// }
+// }
+// } else {
+// logs.Error("Error: ", err)
+// error_msg = "登录错误: " + err.Error()
+// }
+// } else {
+// error_msg = "获取用户Id失败: " + user_id
+// }
+// } else {
+// error_msg = "应用凭据获取失败: " + access_token
+// }
+// } else {
+// error_msg = "参数错误"
+// }
+// if user_info_json == "" {
+// user_info_json = "{}"
+// }
+// if bind_existed == "" {
+// bind_existed = "null"
+// }
+// // refer & doc:
+// // - https://golang.org/pkg/html/template/#HTML
+// // - https://stackoverflow.com/questions/24411880/go-html-templates-can-i-stop-the-templates-package-inserting-quotes-around-stri
+// // - https://stackoverflow.com/questions/38035176/insert-javascript-snippet-inside-template-with-beego-golang
+// c.Data["bind_existed"] = template.JS(bind_existed)
+// logs.Debug("bind_existed: ", bind_existed)
+// c.Data["error_msg"] = template.JS(error_msg)
+// c.Data["user_info_json"] = template.JS(user_info_json)
+// /*
+// // 调试: 显示源码
+// result, err := c.RenderString()
+// if err != nil {
+// logs.Error(err)
+// } else {
+// logs.Warning(result)
+// }
+// */
+//}
+
+// WorkWeixinLoginBind 用户企业微信登录-绑定
+//func (c *AccountController) WorkWeixinLoginBind() {
+// if user_info, ok := c.GetSession(SessionUserInfoKey).(workweixin.WorkWeixinUserPrivateInfo); ok && len(user_info.UserId) > 0 {
+// req_account := c.GetString("account")
+// req_password := c.GetString("password")
+// if req_account == "" || req_password == "" {
+// c.JsonResult(400, "账号或密码不能为空")
+// } else {
+// member, err := models.NewMember().Login(req_account, req_password)
+// if err == nil {
+// account := models.NewWorkWeixinAccount()
+// account.MemberId = member.MemberId
+// account.WorkWeixin_UserId = user_info.UserId
+// member.CreateAt = 0
+// ormer := orm.NewOrm()
+// o, err := ormer.Begin()
+// if err != nil {
+// logs.Error("开启事务时出错 -> ", err)
+// c.JsonResult(500, "开启事务时出错: ", err.Error())
+// }
+// if err := account.AddBind(ormer); err != nil {
+// o.Rollback()
+// c.JsonResult(500, "绑定失败,数据库错误: "+err.Error())
+// } else {
+// // 绑定成功之后修改用户信息
+// member.LastLoginTime = time.Now()
+// //member.RealName = user_info.Name
+// //member.Avatar = user_info.Avatar
+// if len(member.Avatar) < 1 {
+// member.Avatar = conf.GetDefaultAvatar()
+// }
+// //member.Email = user_info.Email
+// //member.Phone = user_info.Mobile
+// if _, err := ormer.Update(member, "last_login_time", "real_name", "avatar", "email", "phone"); err != nil {
+// o.Rollback()
+// logs.Error("保存用户信息失败=>", err)
+// c.JsonResult(500, "绑定失败,现有账户信息更新失败: "+err.Error())
+// } else {
+// if err := o.Commit(); err != nil {
+// logs.Error("开启事务时出错 -> ", err)
+// c.JsonResult(500, "开启事务时出错: ", err.Error())
+// } else {
+// c.DelSession(SessionUserInfoKey)
+// c.SetMember(*member)
+//
+// var remember CookieRemember
+// remember.MemberId = member.MemberId
+// remember.Account = member.Account
+// remember.Time = time.Now()
+// v, err := utils.Encode(remember)
+// if err == nil {
+// c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
+// c.JsonResult(0, "绑定成功", nil)
+// } else {
+// c.JsonResult(500, "绑定成功, 但自动登录失败, 请返回首页重新登录", nil)
+// }
+// }
+// }
+//
+// }
+//
+// } else {
+// logs.Error("用户登录 ->", err)
+// c.JsonResult(500, "账号或密码错误", nil)
+// }
+// c.JsonResult(500, "TODO: 绑定以后账号功能开发中")
+// }
+// } else {
+// if ok {
+// c.DelSession(SessionUserInfoKey)
+// }
+// c.JsonResult(400, "请求错误, 请从首页重新登录")
+// }
+//
+//}
+
+// WorkWeixinLoginIgnore 用户企业微信登录-忽略
+//func (c *AccountController) WorkWeixinLoginIgnore() {
+// if user_info, ok := c.GetSession(SessionUserInfoKey).(workweixin.WorkWeixinUserPrivateInfo); ok && len(user_info.UserId) > 0 {
+// c.DelSession(SessionUserInfoKey)
+// member := models.NewMember()
+//
+// if _, err := member.FindByAccount(user_info.UserId); err == nil && member.MemberId > 0 {
+// c.JsonResult(400, "账号已存在")
+// }
+//
+// ormer := orm.NewOrm()
+// o, err := ormer.Begin()
+// if err != nil {
+// logs.Error("开启事务时出错 -> ", err)
+// c.JsonResult(500, "开启事务时出错: ", err.Error())
+// }
+//
+// member.Account = user_info.UserId
+// member.RealName = user_info.Name
+// var rnd = rand.New(src)
+// // fmt.Sprintf("%x", rnd.Uint64())
+// // strconv.FormatUint(rnd.Uint64(), 16)
+// member.Password = user_info.UserId + strconv.FormatUint(rnd.Uint64(), 16)
+// member.Password = "123456" // 强制设置默认密码,需修改一次密码后,才可以进行账号密码登录
+// hash, err := utils.PasswordHash(member.Password)
+// if err != nil {
+// logs.Error("加密用户密码失败 =>", err)
+// c.JsonResult(500, "加密用户密码失败"+err.Error())
+// } else {
+// logs.Error("member.Password: ", member.Password)
+// logs.Error("hash: ", hash)
+// member.Password = hash
+// }
+// member.Role = conf.MemberGeneralRole
+// member.Avatar = user_info.Avatar
+// if len(member.Avatar) < 1 {
+// member.Avatar = conf.GetDefaultAvatar()
+// }
+// member.CreateAt = 0
+// member.Email = user_info.BizMail
+// member.Phone = user_info.Mobile
+// member.Status = 0
+// if _, err = ormer.Insert(member); err != nil {
+// o.Rollback()
+// c.JsonResult(500, "注册失败,数据库错误: "+err.Error())
+// } else {
+// account := models.NewWorkWeixinAccount()
+// account.MemberId = member.MemberId
+// account.WorkWeixin_UserId = user_info.UserId
+// member.CreateAt = 0
+// if err := account.AddBind(ormer); err != nil {
+// o.Rollback()
+// c.JsonResult(500, "注册失败,数据库错误: "+err.Error())
+// } else {
+// if err := o.Commit(); err != nil {
+// logs.Error("提交事务时出错 -> ", err)
+// c.JsonResult(500, "提交事务时出错: ", err.Error())
+// } else {
+// member.LastLoginTime = time.Now()
+// _ = member.Update("last_login_time")
+//
+// c.SetMember(*member)
+//
+// var remember CookieRemember
+// remember.MemberId = member.MemberId
+// remember.Account = member.Account
+// remember.Time = time.Now()
+// v, err := utils.Encode(remember)
+// if err == nil {
+// c.SetSecureCookie(conf.GetAppKey(), "login", v, time.Now().Add(time.Hour*24*30*5).Unix())
+// c.JsonResult(0, "绑定成功", nil)
+// } else {
+// c.JsonResult(500, "绑定成功, 但自动登录失败, 请返回首页重新登录", nil)
+// }
+// }
+// }
+// }
+// } else {
+// if ok {
+// c.DelSession(SessionUserInfoKey)
+// }
+// c.JsonResult(400, "请求错误, 请从首页重新登录")
+// }
+//}
+
+// QR二维码登录
+//func (c *AccountController) QRLogin() {
+// appName := c.Ctx.Input.Param(":app")
+//
+// switch appName {
+// // 钉钉扫码登录
+// case "dingtalk":
+// code := c.GetString("code")
+// state := c.GetString("state")
+// if state != "1" || code == "" {
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+// c.StopRun()
+// }
+// appKey, _ := web.AppConfig.String("dingtalk_qr_key")
+// appSecret, _ := web.AppConfig.String("dingtalk_qr_secret")
+//
+// qrDingtalk := dingtalk.NewDingtalkQRLogin(appSecret, appKey)
+// unionID, err := qrDingtalk.GetUnionIDByCode(code)
+// if err != nil {
+// logs.Warn("获取钉钉临时UnionID失败 ->", err)
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+// c.StopRun()
+// }
+//
+// appKey, _ = web.AppConfig.String("dingtalk_app_key")
+// appSecret, _ = web.AppConfig.String("dingtalk_app_secret")
+// tmpReader, _ := web.AppConfig.String("dingtalk_tmp_reader")
+//
+// dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
+// err = dingtalkAgent.GetAccesstoken()
+// if err != nil {
+// logs.Warn("获取钉钉临时Token失败 ->", err)
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+// c.StopRun()
+// }
+//
+// userid, err := dingtalkAgent.GetUserIDByUnionID(unionID)
+// if err != nil {
+// logs.Warn("获取钉钉用户ID失败 ->", err)
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+// c.StopRun()
+// }
+//
+// username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
+// if err != nil {
+// logs.Warn("获取钉钉用户信息失败 ->", err)
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+// c.StopRun()
+// }
+//
+// member, err := models.NewMember().TmpLogin(tmpReader)
+// if err == nil {
+// member.LastLoginTime = time.Now()
+// _ = member.Update("last_login_time")
+// member.Account = username
+// if avatar != "" {
+// member.Avatar = avatar
+// }
+//
+// c.SetMember(*member)
+// c.LoggedIn(false)
+// c.StopRun()
+// }
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+//
+// // 企业微信扫码登录
+// case "workweixin":
+// //
+//
+// default:
+// c.Redirect(conf.URLFor("AccountController.Login"), 302)
+// c.StopRun()
+// }
+//}
+
// 登录成功后的操作,如重定向到原始请求页面
func (c *AccountController) LoggedIn(isPost bool) interface{} {
diff --git a/controllers/BlogController.go b/controllers/BlogController.go
index 008492f96..c40ff0e17 100644
--- a/controllers/BlogController.go
+++ b/controllers/BlogController.go
@@ -34,7 +34,7 @@ func (c *BlogController) Prepare() {
}
}
-//文章阅读
+// 文章阅读
func (c *BlogController) Index() {
c.Prepare()
c.TplName = "blog/index.tpl"
@@ -56,23 +56,14 @@ func (c *BlogController) Index() {
if blog.BlogStatus == "password" && password != blog.Password {
c.JsonResult(6001, i18n.Tr(c.Lang, "message.blog_pwd_incorrect"))
} else if blog.BlogStatus == "password" && password == blog.Password {
- // If the password is correct, then determine whether the user is correct
- if c.Member != nil && (blog.MemberId == c.Member.MemberId || c.Member.IsAdministrator()) {
- /* Private blog is accessible only to author and administrator.
- Anonymous users are not allowed access. */
- // Store the session value
- _ = c.CruSession.Set(context.TODO(), blogReadSession, blogId)
- c.JsonResult(0, "OK")
- } else {
- c.JsonResult(6002, i18n.Tr(c.Lang, "blog.private_blog_tips"))
- }
+ // Store the session value for the next GET request.
+ _ = c.CruSession.Set(context.TODO(), blogReadSession, blogId)
+ c.JsonResult(0, "OK")
} else {
c.JsonResult(0, "OK")
}
- } else if blog.BlogStatus == "password" &&
- (c.CruSession.Get(context.TODO(), blogReadSession) == nil || // Read session doesn't exist
- c.Member == nil || // Anonymous, Not Allow
- (blog.MemberId != c.Member.MemberId && !c.Member.IsAdministrator())) { // User isn't author or administrator
+ } else if blog.BlogStatus == "password" && c.CruSession.Get(context.TODO(), blogReadSession) == nil && // Read session doesn't exist
+ (c.Member == nil || (blog.MemberId != c.Member.MemberId && !c.Member.IsAdministrator())) { // User isn't author or administrator
//如果不存在已输入密码的标记
c.TplName = "blog/index_password.tpl"
}
@@ -98,7 +89,7 @@ func (c *BlogController) Index() {
}
}
-//文章列表
+// 文章列表
func (c *BlogController) List() {
c.Prepare()
c.TplName = "blog/list.tpl"
@@ -130,7 +121,7 @@ func (c *BlogController) List() {
c.Data["Lists"] = blogList
}
-//管理后台文章列表
+// 管理后台文章列表
func (c *BlogController) ManageList() {
c.Prepare()
c.TplName = "blog/manage_list.tpl"
@@ -153,7 +144,7 @@ func (c *BlogController) ManageList() {
}
-//文章设置
+// 文章设置
func (c *BlogController) ManageSetting() {
c.Prepare()
c.TplName = "blog/manage_setting.tpl"
@@ -290,7 +281,7 @@ func (c *BlogController) ManageSetting() {
}
}
-//文章创建或编辑
+// 文章创建或编辑
func (c *BlogController) ManageEdit() {
c.Prepare()
c.TplName = "blog/manage_edit.tpl"
@@ -403,7 +394,7 @@ func (c *BlogController) ManageEdit() {
c.Data["Model"] = blog
}
-//删除文章
+// 删除文章
func (c *BlogController) ManageDelete() {
c.Prepare()
blogId, _ := c.GetInt("blog_id", 0)
@@ -624,7 +615,7 @@ func (c *BlogController) RemoveAttachment() {
c.JsonResult(0, "ok", attach)
}
-//下载附件
+// 下载附件
func (c *BlogController) Download() {
c.Prepare()
diff --git a/controllers/BookController.go b/controllers/BookController.go
index 23ddd6665..0a4b2860d 100644
--- a/controllers/BookController.go
+++ b/controllers/BookController.go
@@ -126,7 +126,7 @@ func (c *BookController) Setting() {
}
-//保存项目信息
+// 保存项目信息
func (c *BookController) SaveBook() {
bookResult, err := c.IsPermission()
@@ -164,8 +164,8 @@ func (c *BookController) SaveBook() {
if !models.NewItemsets().Exist(itemId) {
c.JsonResult(6006, i18n.Tr(c.Lang, "message.project_space_not_exist"))
}
- if editor != "markdown" && editor != "html" && editor != "new_html" {
- editor = "markdown"
+ if editor != EditorMarkdown && editor != EditorCherryMarkdown && editor != EditorHtml && editor != EditorNewHtml {
+ editor = EditorMarkdown
}
book.BookName = bookName
@@ -174,6 +174,9 @@ func (c *BookController) SaveBook() {
book.Publisher = publisher
//book.Label = tag
book.Editor = editor
+ if editor == EditorCherryMarkdown {
+ book.Theme = "cherry"
+ }
book.HistoryCount = historyCount
book.IsDownload = 0
book.BookPassword = strings.TrimSpace(c.GetString("bPassword"))
@@ -216,7 +219,7 @@ func (c *BookController) SaveBook() {
c.JsonResult(0, "ok", bookResult)
}
-//设置项目私有状态.
+// 设置项目私有状态.
func (c *BookController) PrivatelyOwned() {
status := c.GetString("status")
@@ -296,7 +299,7 @@ func (c *BookController) Transfer() {
c.JsonResult(0, "ok")
}
-//上传项目封面.
+// 上传项目封面.
func (c *BookController) UploadCover() {
bookResult, err := c.IsPermission()
@@ -544,7 +547,7 @@ func (c *BookController) Create() {
c.JsonResult(6001, "error")
}
-//复制项目
+// 复制项目
func (c *BookController) Copy() {
if c.Ctx.Input.IsPost() {
//检查是否有复制项目的权限
@@ -622,6 +625,9 @@ func (c *BookController) Import() {
tempPath = filepath.Join(tempPath, moreFile.Filename)
err = c.SaveToFile("import-file", tempPath)
+ if err != nil {
+ c.JsonResult(6004, i18n.Tr(c.Lang, "message.upload_failed"))
+ }
book := models.NewBook()
@@ -724,7 +730,7 @@ func (c *BookController) Delete() {
c.JsonResult(0, "ok")
}
-//发布项目.
+// 发布项目.
func (c *BookController) Release() {
c.Prepare()
@@ -763,7 +769,7 @@ func (c *BookController) Release() {
c.JsonResult(0, i18n.Tr(c.Lang, "message.publish_to_queue"))
}
-//文档排序.
+// 文档排序.
func (c *BookController) SaveSort() {
c.Prepare()
@@ -924,7 +930,7 @@ func (c *BookController) TeamAdd() {
c.JsonResult(0, "OK", teamRel)
}
-//删除项目的团队.
+// 删除项目的团队.
func (c *BookController) TeamDelete() {
c.Prepare()
@@ -955,7 +961,7 @@ func (c *BookController) TeamDelete() {
c.JsonResult(0, "OK")
}
-//团队搜索.
+// 团队搜索.
func (c *BookController) TeamSearch() {
c.Prepare()
@@ -976,7 +982,7 @@ func (c *BookController) TeamSearch() {
}
-//项目空间搜索.
+// 项目空间搜索.
func (c *BookController) ItemsetsSearch() {
c.Prepare()
diff --git a/controllers/CommentController.go b/controllers/CommentController.go
index 487c855bf..352af04ea 100644
--- a/controllers/CommentController.go
+++ b/controllers/CommentController.go
@@ -22,8 +22,8 @@ func (c *CommentController) Lists() {
page := pagination.PageUtil(int(count), pageIndex, conf.PageSize, comments)
var data struct {
- DocId int `json:"doc_id"`
- Page pagination.Page `json:"page"`
+ DocId int `json:"doc_id"`
+ Page pagination.Page `json:"page"`
}
data.DocId = docid
data.Page = page
@@ -43,6 +43,9 @@ func (c *CommentController) Create() {
m := models.NewComment()
m.DocumentId = id
+ if c.Member == nil {
+ c.JsonResult(1, "请先登录,再评论")
+ }
if len(c.Member.RealName) != 0 {
m.Author = c.Member.RealName
} else {
@@ -56,7 +59,7 @@ func (c *CommentController) Create() {
m.Insert()
var data struct {
- DocId int `json:"doc_id"`
+ DocId int `json:"doc_id"`
}
data.DocId = id
diff --git a/controllers/DocumentController.go b/controllers/DocumentController.go
index 6339b5a94..4483ddcac 100644
--- a/controllers/DocumentController.go
+++ b/controllers/DocumentController.go
@@ -65,8 +65,12 @@ func (c *DocumentController) Index() {
selected = doc.DocumentId
c.Data["Title"] = doc.DocumentName
c.Data["Content"] = template.HTML(doc.Release)
-
c.Data["Description"] = utils.AutoSummary(doc.Release, 120)
+ c.Data["FoldSetting"] = "first"
+
+ if bookResult.Editor == EditorCherryMarkdown {
+ c.Data["MarkdownTheme"] = doc.MarkdownTheme
+ }
if bookResult.IsDisplayComment {
// 获取评论、分页
@@ -78,6 +82,7 @@ func (c *DocumentController) Index() {
} else {
c.Data["Title"] = i18n.Tr(c.Lang, "blog.summary")
c.Data["Content"] = template.HTML(blackfriday.Run([]byte(bookResult.Description)))
+ c.Data["FoldSetting"] = "closed"
}
tree, err := models.NewDocument().CreateDocumentTreeForHtml(bookResult.BookId, selected)
@@ -187,13 +192,15 @@ func (c *DocumentController) Read() {
if c.IsAjax() {
var data struct {
- DocId int `json:"doc_id"`
- DocIdentify string `json:"doc_identify"`
- DocTitle string `json:"doc_title"`
- Body string `json:"body"`
- Title string `json:"title"`
- Version int64 `json:"version"`
- ViewCount int `json:"view_count"`
+ DocId int `json:"doc_id"`
+ DocIdentify string `json:"doc_identify"`
+ DocTitle string `json:"doc_title"`
+ Body string `json:"body"`
+ Title string `json:"title"`
+ Version int64 `json:"version"`
+ ViewCount int `json:"view_count"`
+ MarkdownTheme string `json:"markdown_theme"`
+ IsMarkdown bool `json:"is_markdown"`
}
data.DocId = doc.DocumentId
data.DocIdentify = doc.Identify
@@ -202,7 +209,10 @@ func (c *DocumentController) Read() {
data.Title = doc.DocumentName + " - Powered by MinDoc"
data.Version = doc.Version
data.ViewCount = doc.ViewCount
-
+ data.MarkdownTheme = doc.MarkdownTheme
+ if bookResult.Editor == EditorCherryMarkdown {
+ data.IsMarkdown = true
+ }
c.JsonResult(0, "ok", data)
} else {
c.Data["DocumentId"] = doc.DocumentId
@@ -230,6 +240,15 @@ func (c *DocumentController) Read() {
c.Data["Title"] = doc.DocumentName
c.Data["Content"] = template.HTML(doc.Release)
c.Data["ViewCount"] = doc.ViewCount
+ c.Data["FoldSetting"] = "closed"
+ if bookResult.Editor == EditorCherryMarkdown {
+ c.Data["MarkdownTheme"] = doc.MarkdownTheme
+ }
+ if doc.IsOpen == 1 {
+ c.Data["FoldSetting"] = "open"
+ } else if doc.IsOpen == 2 {
+ c.Data["FoldSetting"] = "empty"
+ }
}
// 编辑文档
@@ -269,16 +288,7 @@ func (c *DocumentController) Edit() {
}
}
- // 根据不同编辑器类型加载编辑器
- if bookResult.Editor == "markdown" {
- c.TplName = "document/markdown_edit_template.tpl"
- } else if bookResult.Editor == "html" {
- c.TplName = "document/html_edit_template.tpl"
- } else if bookResult.Editor == "new_html" {
- c.TplName = "document/new_html_edit_template.tpl"
- } else {
- c.TplName = "document/" + bookResult.Editor + "_edit_template.tpl"
- }
+ c.TplName = fmt.Sprintf("document/%s_edit_template.tpl", bookResult.Editor)
c.Data["Model"] = bookResult
@@ -767,6 +777,7 @@ func (c *DocumentController) Content() {
if c.Ctx.Input.IsPost() {
markdown := strings.TrimSpace(c.GetString("markdown", ""))
content := c.GetString("html")
+ markdownTheme := c.GetString("markdown_theme", "theme__light")
version, _ := c.GetInt64("version", 0)
isCover := c.GetString("cover")
@@ -801,6 +812,7 @@ func (c *DocumentController) Content() {
doc.Markdown = content
} else {
doc.Markdown = markdown
+ doc.MarkdownTheme = markdownTheme
}
doc.Version = time.Now().Unix()
@@ -895,8 +907,8 @@ func (c *DocumentController) Export() {
bookResult.Cover = conf.URLForWithCdnImage(bookResult.Cover)
}
- if output == "markdown" {
- if bookResult.Editor != "markdown" {
+ if output == Markdown {
+ if bookResult.Editor != EditorMarkdown && bookResult.Editor != EditorCherryMarkdown {
c.ShowErrorPage(500, i18n.Tr(c.Lang, "message.cur_project_not_support_md"))
}
p, err := bookResult.ExportMarkdown(c.CruSession.SessionID(context.TODO()))
@@ -1148,7 +1160,7 @@ func (c *DocumentController) DeleteHistory() {
c.JsonResult(0, "ok")
}
-//通过文档历史恢复文档
+// 通过文档历史恢复文档
func (c *DocumentController) RestoreHistory() {
c.Prepare()
@@ -1215,7 +1227,7 @@ func (c *DocumentController) Compare() {
identify := c.Ctx.Input.Param(":key")
bookId := 0
- editor := "markdown"
+ editor := EditorMarkdown
// 如果是超级管理员则忽略权限判断
if c.Member.IsAdministrator() {
@@ -1261,7 +1273,7 @@ func (c *DocumentController) Compare() {
c.Data["HistoryId"] = historyId
c.Data["DocumentId"] = doc.DocumentId
- if editor == "markdown" {
+ if editor == EditorMarkdown || editor == EditorCherryMarkdown {
c.Data["HistoryContent"] = history.Markdown
c.Data["Content"] = doc.Markdown
} else {
diff --git a/controllers/ItemsetsController.go b/controllers/ItemsetsController.go
index ef129111b..e9625d49b 100644
--- a/controllers/ItemsetsController.go
+++ b/controllers/ItemsetsController.go
@@ -1,6 +1,8 @@
package controllers
import (
+ "math"
+
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
"github.com/mindoc-org/mindoc/conf"
@@ -24,7 +26,7 @@ func (c *ItemsetsController) Prepare() {
func (c *ItemsetsController) Index() {
c.Prepare()
c.TplName = "items/index.tpl"
- pageSize := 18
+ pageSize := 16
pageIndex, _ := c.GetInt("page", 0)
@@ -33,7 +35,6 @@ func (c *ItemsetsController) Index() {
if err != nil && err != orm.ErrNoRows {
c.ShowErrorPage(500, err.Error())
}
- c.Data["TotalPages"] = pageIndex
if err == orm.ErrNoRows || len(items) <= 0 {
c.Data["Lists"] = items
c.Data["PageHtml"] = ""
@@ -46,7 +47,7 @@ func (c *ItemsetsController) Index() {
} else {
c.Data["PageHtml"] = ""
}
-
+ c.Data["TotalPages"] = int(math.Ceil(float64(totalCount) / float64(pageSize)))
c.Data["Lists"] = items
}
@@ -85,6 +86,7 @@ func (c *ItemsetsController) List() {
} else {
c.Data["PageHtml"] = ""
}
+ c.Data["TotalPages"] = int(math.Ceil(float64(totalCount) / float64(pageSize)))
c.Data["Lists"] = searchResult
c.Data["Model"] = item
diff --git a/controllers/SettingController.go b/controllers/SettingController.go
index 762af330f..b79204047 100644
--- a/controllers/SettingController.go
+++ b/controllers/SettingController.go
@@ -79,6 +79,9 @@ func (c *SettingController) Password() {
c.JsonResult(6007, i18n.Tr(c.Lang, "message.pwd_encrypt_failed"))
}
c.Member.Password = pwd
+ if c.Member.AuthMethod == "" {
+ c.Member.AuthMethod = "local"
+ }
if err := c.Member.Update(); err != nil {
c.JsonResult(6008, err.Error())
}
diff --git a/controllers/const.go b/controllers/const.go
new file mode 100644
index 000000000..83b664e35
--- /dev/null
+++ b/controllers/const.go
@@ -0,0 +1,9 @@
+package controllers
+
+const (
+ Markdown = "markdown"
+ EditorMarkdown = "markdown"
+ EditorCherryMarkdown = "cherry_markdown"
+ EditorHtml = "html"
+ EditorNewHtml = "new_html"
+)
diff --git a/dev-win-build.cmd b/dev-win-build.cmd
new file mode 100644
index 000000000..5dcb191f7
--- /dev/null
+++ b/dev-win-build.cmd
@@ -0,0 +1 @@
+go build -v -ldflags "-linkmode external -extldflags '-static' -w" -o mindoc_windows_amd64.exe main.go
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index a46c4f197..e5877aa59 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,14 +1,19 @@
version: "3"
services:
mindoc:
- image: registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1-beta.6
+ image: registry.cn-hangzhou.aliyuncs.com/mindoc-org/mindoc:v2.1
container_name: mindoc
privileged: false
restart: always
ports:
- 8181:8181
volumes:
- - /var/www/mindoc://mindoc-sync-host
+ - /var/www/mindoc/conf://mindoc/conf
+ - /var/www/mindoc/static://mindoc/static
+ - /var/www/mindoc/views://mindoc/views
+ - /var/www/mindoc/uploads://mindoc/uploads
+ - /var/www/mindoc/runtime://mindoc/runtime
+ - /var/www/mindoc/database://mindoc/database
environment:
- MINDOC_RUN_MODE=prod
- MINDOC_DB_ADAPTER=sqlite3
diff --git a/go.mod b/go.mod
index 3418db85c..d1698fdeb 100644
--- a/go.mod
+++ b/go.mod
@@ -3,28 +3,51 @@ module github.com/mindoc-org/mindoc
go 1.18
require (
- github.com/PuerkitoBio/goquery v1.4.1
- github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5
+ github.com/PuerkitoBio/goquery v1.8.0
+ github.com/beego/beego/v2 v2.0.5
github.com/beego/i18n v0.0.0-20161101132742-e9308947f407
- github.com/boombuler/barcode v1.0.0
+ github.com/boombuler/barcode v1.0.1
+ github.com/go-ldap/ldap/v3 v3.4.4
github.com/howeyc/fsnotify v0.9.0
- github.com/kardianos/service v1.1.0
- github.com/lifei6671/gocaptcha v0.1.1
+ github.com/kardianos/service v1.2.1
+ github.com/lib/pq v1.10.5
+ github.com/lifei6671/gocaptcha v0.2.0
github.com/mattn/go-runewidth v0.0.13
- github.com/mattn/go-sqlite3 v2.0.3+incompatible
+ github.com/mattn/go-sqlite3 v1.14.15
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/russross/blackfriday/v2 v2.1.0
- gopkg.in/ldap.v2 v2.5.1
)
require (
- github.com/Unknwon/goconfig v0.0.0-20200908083735-df7de6a44db8 // indirect
- github.com/andybalholm/cascadia v1.2.0 // indirect
- github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
- github.com/lib/pq v1.7.0 // indirect
- github.com/smartystreets/goconvey v1.6.4 // indirect
- gopkg.in/asn1-ber.v1 v1.0.0-00010101000000-000000000000 // indirect
- gopkg.in/yaml.v2 v2.3.0 // indirect
+ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
+ github.com/Unknwon/goconfig v1.0.0 // indirect
+ github.com/andybalholm/cascadia v1.3.1 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect
+ github.com/cespare/xxhash/v2 v2.1.2 // indirect
+ github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
+ github.com/go-redis/redis/v7 v7.4.1 // indirect
+ github.com/go-sql-driver/mysql v1.6.0 // indirect
+ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+ github.com/golang/protobuf v1.5.2 // indirect
+ github.com/gomodule/redigo v2.0.0+incompatible // indirect
+ github.com/hashicorp/golang-lru v0.5.4 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/prometheus/client_golang v1.13.0 // indirect
+ github.com/prometheus/client_model v0.2.0 // indirect
+ github.com/prometheus/common v0.37.0 // indirect
+ github.com/prometheus/procfs v0.8.0 // indirect
+ github.com/rivo/uniseg v0.3.4 // indirect
+ github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
+ github.com/smartystreets/goconvey v1.7.2 // indirect
+ golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect
+ golang.org/x/image v0.5.0 // indirect
+ golang.org/x/net v0.7.0 // indirect
+ golang.org/x/sys v0.5.0 // indirect
+ golang.org/x/text v0.7.0 // indirect
+ google.golang.org/protobuf v1.28.1 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
-
-replace gopkg.in/asn1-ber.v1 => github.com/go-asn1-ber/asn1-ber v1.5.0
diff --git a/go.sum b/go.sum
index 3eca66958..524b4168b 100644
--- a/go.sum
+++ b/go.sum
@@ -1,158 +1,218 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
-github.com/PuerkitoBio/goquery v1.4.1 h1:smcIRGdYm/w7JSbcdeLHEMzxmsBQvl8lhf0dSw2nzMI=
-github.com/PuerkitoBio/goquery v1.4.1/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA=
-github.com/Unknwon/goconfig v0.0.0-20200908083735-df7de6a44db8 h1:1TrMV1HmBApBbM+Hy7RCKZD6UlYWYIPPfoeXomG7+zE=
-github.com/Unknwon/goconfig v0.0.0-20200908083735-df7de6a44db8/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
+github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
+github.com/Unknwon/goconfig v1.0.0 h1:9IAu/BYbSLQi8puFjUQApZTxIHqSwrj5d8vpP8vTq4A=
+github.com/Unknwon/goconfig v1.0.0/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
-github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
-github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
-github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
-github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5 h1:i0swsv6hmoF6pkeG2S/dvOWwOKFPGDKhrmTlWH6I1nM=
-github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5/go.mod h1:JlRUJ/NVNygorqjyt7/lQ8R++KSE0qXvxeIfbnIUd7Q=
-github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
+github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
+github.com/beego/beego/v2 v2.0.5 h1:fa2TBWfKGDs35Ck9an9SVnpS0zM8sRTXlW8rFjpeYlE=
+github.com/beego/beego/v2 v2.0.5/go.mod h1:CH2/JIaB4ceGYVQlYqTAFft4pVk/ol1ZkakUrUvAyns=
github.com/beego/i18n v0.0.0-20161101132742-e9308947f407 h1:WtJfx5HqASTQp7HfiZldnin8KQV2futplF3duGp5PGc=
github.com/beego/i18n v0.0.0-20161101132742-e9308947f407/go.mod h1:KLeFCpAMq2+50NkXC8iiJxLLiiTfTqrGtKEVm+2fk7s=
-github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
-github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
-github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
-github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
-github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
-github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
+github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
+github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw=
+github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
-github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/couchbase/go-couchbase v0.0.0-20210126152612-8e416c37c8ef/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=
-github.com/couchbase/gomemcached v0.1.2-0.20210126151728-840240974836/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo=
-github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
-github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
-github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
-github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
-github.com/go-asn1-ber/asn1-ber v1.5.0 h1:/S4hO/AO6tLMlPX0oftGSOcdGJJN/MuYzfgWRMn199E=
-github.com/go-asn1-ber/asn1-ber v1.5.0/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
+github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
+github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-redis/redis v6.14.2+incompatible h1:UE9pLhzmWf+xHNmZsoccjXosPicuiNaInPgym8nzfg0=
-github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
-github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
-github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
-github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
-github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
+github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY=
github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kardianos/service v1.1.0 h1:QV2SiEeWK42P0aEmGcsAgjApw/lRxkwopvT+Gu6t1/0=
-github.com/kardianos/service v1.1.0/go.mod h1:RrJI2xn5vve/r32U5suTbeaSGoMU6GbNPoj36CVYcHc=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kardianos/service v1.2.1 h1:AYndMsehS+ywIS6RB9KOlcXzteWUzxgMgBymJD7+BYk=
+github.com/kardianos/service v1.2.1/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
-github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lifei6671/gocaptcha v0.1.1 h1:5cvU3w0bK8eJm1P6AiQoPuicoZVAgKKpREBxXF9IaHo=
-github.com/lifei6671/gocaptcha v0.1.1/go.mod h1:6QlTU2WzFhzqylAJWSo3OANfKCraGccJwbK01P5fFmI=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lifei6671/gocaptcha v0.2.0 h1:CwMjGitq5MsYtWODQhlphdl7WhDdD243y1O2d3l8yFU=
+github.com/lifei6671/gocaptcha v0.2.0/go.mod h1:mcUWn1eB+kHOBHLQdmWAQ83bhEGrFTnGMqRCY7sFgUc=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
-github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
+github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
-github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
-github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
-github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
-github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -161,164 +221,367 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
-github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
+github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
+github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
+github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=
+github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
-github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
-github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
-github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
-github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
+github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
+github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
+github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
-github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
-github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
-github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
-go.etcd.io/etcd v3.3.25+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
-go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo=
+golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
+golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
-gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
-gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/main.go b/main.go
index abdbf6736..0edfe0162 100644
--- a/main.go
+++ b/main.go
@@ -2,8 +2,12 @@ package main
import (
"fmt"
+ "io/ioutil"
"log"
"os"
+ "path/filepath"
+ "runtime"
+ "strings"
_ "github.com/beego/beego/v2/server/web/session/memcache"
_ "github.com/beego/beego/v2/server/web/session/mysql"
@@ -15,6 +19,21 @@ import (
_ "github.com/mindoc-org/mindoc/routers"
)
+func isViaDaemonUnix() bool {
+ parentPid := os.Getppid()
+
+ cmdLineBytes, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", parentPid))
+ if err != nil {
+ return false
+ }
+
+ cmdLine := string(cmdLineBytes)
+ executable := strings.Split(cmdLine, " ")[0]
+ fmt.Printf("Parent executable: %s\n", executable)
+ filename := filepath.Base(executable)
+ return strings.Contains(filename, "mindoc-daemon")
+}
+
func main() {
if len(os.Args) >= 3 && os.Args[1] == "service" {
@@ -30,14 +49,19 @@ func main() {
d := daemon.NewDaemon()
- s, err := service.New(d, d.Config())
+ if runtime.GOOS != "windows" && !isViaDaemonUnix() {
+ s, err := service.New(d, d.Config())
- if err != nil {
- fmt.Println("Create service error => ", err)
- os.Exit(1)
- }
+ if err != nil {
+ fmt.Println("Create service error => ", err)
+ os.Exit(1)
+ }
- if err := s.Run(); err != nil {
- log.Fatal("启动程序失败 ->", err)
+ if err := s.Run(); err != nil {
+ log.Fatal("启动程序失败 ->", err)
+ }
+ } else {
+ d.Run()
}
+
}
diff --git a/models/AttachmentModel.go b/models/AttachmentModel.go
index eaf882864..8e2d45ce9 100644
--- a/models/AttachmentModel.go
+++ b/models/AttachmentModel.go
@@ -17,18 +17,18 @@ import (
// Attachment struct .
type Attachment struct {
AttachmentId int `orm:"column(attachment_id);pk;auto;unique" json:"attachment_id"`
- BookId int `orm:"column(book_id);type(int)" json:"book_id"`
- DocumentId int `orm:"column(document_id);type(int);null" json:"doc_id"`
- FileName string `orm:"column(file_name);size(255)" json:"file_name"`
- FilePath string `orm:"column(file_path);size(2000)" json:"file_path"`
- FileSize float64 `orm:"column(file_size);type(float)" json:"file_size"`
- HttpPath string `orm:"column(http_path);size(2000)" json:"http_path"`
- FileExt string `orm:"column(file_ext);size(50)" json:"file_ext"`
- CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
- CreateAt int `orm:"column(create_at);type(int)" json:"create_at"`
+ BookId int `orm:"column(book_id);type(int);description(所属book id)" json:"book_id"`
+ DocumentId int `orm:"column(document_id);type(int);null;description(所属文档id)" json:"doc_id"`
+ FileName string `orm:"column(file_name);size(255);description(文件名称)" json:"file_name"`
+ FilePath string `orm:"column(file_path);size(2000);description(文件路径)" json:"file_path"`
+ FileSize float64 `orm:"column(file_size);type(float);description(文件大小 字节)" json:"file_size"`
+ HttpPath string `orm:"column(http_path);size(2000);description(文件路径)" json:"http_path"`
+ FileExt string `orm:"column(file_ext);size(50);description(文件后缀)" json:"file_ext"`
+ CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add;description(创建时间)" json:"create_time"`
+ CreateAt int `orm:"column(create_at);type(int);description(创建人id)" json:"create_at"`
}
-// TableName 获取对应数据库表名.
+// TableName 获取对应上传附件数据库表名.
func (m *Attachment) TableName() string {
return "attachment"
}
diff --git a/models/Auth2Account.go b/models/Auth2Account.go
new file mode 100644
index 000000000..a5ff751e7
--- /dev/null
+++ b/models/Auth2Account.go
@@ -0,0 +1,185 @@
+// Package models .
+package models
+
+import (
+ "errors"
+ "github.com/mindoc-org/mindoc/utils/auth2"
+ "time"
+
+ "github.com/beego/beego/v2/client/orm"
+ "github.com/beego/beego/v2/core/logs"
+ "github.com/mindoc-org/mindoc/conf"
+)
+
+var (
+ _ Auth2Account = (*WorkWeixinAccount)(nil)
+ _ Auth2Account = (*DingTalkAccount)(nil)
+)
+
+type Auth2Account interface {
+ ExistedMember(id string) (*Member, error)
+ AddBind(o orm.Ormer, userInfo auth2.UserInfo, member *Member) error
+}
+
+func NewWorkWeixinAccount() *WorkWeixinAccount {
+ return &WorkWeixinAccount{}
+}
+
+type WorkWeixinAccount struct {
+ MemberId int `orm:"column(member_id);type(int);default(-1);index" json:"member_id"`
+ UserDbId int `orm:"pk;auto;unique;column(user_db_id)" json:"user_db_id"`
+ WorkWeixin_UserId string `orm:"size(100);unique;column(workweixin_user_id)" json:"workweixin_user_id"`
+ // WorkWeixin_Name string `orm:"size(255);column(workweixin_name)" json:"workweixin_name"`
+ // WorkWeixin_Phone string `orm:"size(25);column(workweixin_phone)" json:"workweixin_phone"`
+ // WorkWeixin_Email string `orm:"size(255);column(workweixin_email)" json:"workweixin_email"`
+ // WorkWeixin_Status int `orm:"type(int);column(status)" json:"status"`
+ // WorkWeixin_Avatar string `orm:"size(1024);column(avatar)" json:"avatar"`
+ CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
+ CreateAt int `orm:"type(int);column(create_at)" json:"create_at"`
+ LastLoginTime time.Time `orm:"type(datetime);column(last_login_time);null" json:"last_login_time"`
+}
+
+// TableName 获取对应数据库表名.
+func (m *WorkWeixinAccount) TableName() string {
+ return "workweixin_accounts"
+}
+
+// TableEngine 获取数据使用的引擎.
+func (m *WorkWeixinAccount) TableEngine() string {
+ return "INNODB"
+}
+
+func (m *WorkWeixinAccount) TableNameWithPrefix() string {
+ return conf.GetDatabasePrefix() + m.TableName()
+}
+
+func (m *WorkWeixinAccount) ExistedMember(workweixin_user_id string) (*Member, error) {
+ o := orm.NewOrm()
+ account := NewWorkWeixinAccount()
+ member := NewMember()
+ err := o.QueryTable(m.TableNameWithPrefix()).Filter("workweixin_user_id", workweixin_user_id).One(account)
+ if err != nil {
+ return member, err
+ }
+
+ member, err = member.Find(account.MemberId)
+ if err != nil {
+ return member, err
+ }
+
+ if member.Status != 0 {
+ return member, errors.New("receive_account_disabled")
+ }
+
+ return member, nil
+
+}
+
+// AddBind 添加一个用户.
+func (m *WorkWeixinAccount) AddBind(o orm.Ormer, userInfo auth2.UserInfo, member *Member) error {
+ tmpM := NewWorkWeixinAccount()
+ err := o.QueryTable(m.TableNameWithPrefix()).Filter("workweixin_user_id", userInfo.UserId).One(tmpM)
+ if err == nil {
+ tmpM.MemberId = member.MemberId
+ _, err = o.Update(tmpM)
+ if err != nil {
+ logs.Error("保存用户数据到数据时失败 =>", err)
+ return errors.New("用户信息绑定失败, 数据库错误")
+ }
+ return nil
+ }
+
+ m.MemberId = member.MemberId
+ m.WorkWeixin_UserId = userInfo.UserId
+
+ if c, err := o.QueryTable(m.TableNameWithPrefix()).Filter("member_id", m.MemberId).Count(); err == nil && c > 0 {
+ return errors.New("已绑定,不可重复绑定")
+ }
+
+ _, err = o.Insert(m)
+ if err != nil {
+ logs.Error("保存用户数据到数据时失败 =>", err)
+ return errors.New("用户信息绑定失败, 数据库错误")
+ }
+
+ return nil
+}
+
+func NewDingTalkAccount() *DingTalkAccount {
+ return &DingTalkAccount{}
+}
+
+type DingTalkAccount struct {
+ MemberId int `orm:"column(member_id);type(int);default(-1);index" json:"member_id"`
+ UserDbId int `orm:"pk;auto;unique;column(user_db_id)" json:"user_db_id"`
+ Dingtalk_UserId string `orm:"size(100);unique;column(dingtalk_user_id)" json:"dingtalk_user_id"`
+ CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
+ CreateAt int `orm:"type(int);column(create_at)" json:"create_at"`
+ LastLoginTime time.Time `orm:"type(datetime);column(last_login_time);null" json:"last_login_time"`
+}
+
+// TableName 获取对应数据库表名.
+func (m *DingTalkAccount) TableName() string {
+ return "dingtalk_accounts"
+}
+
+// TableEngine 获取数据使用的引擎.
+func (m *DingTalkAccount) TableEngine() string {
+ return "INNODB"
+}
+
+func (m *DingTalkAccount) TableNameWithPrefix() string {
+ return conf.GetDatabasePrefix() + m.TableName()
+}
+
+func (m *DingTalkAccount) ExistedMember(userid string) (*Member, error) {
+ o := orm.NewOrm()
+ account := NewDingTalkAccount()
+ member := NewMember()
+ err := o.QueryTable(m.TableNameWithPrefix()).Filter("dingtalk_user_id", userid).One(account)
+ if err != nil {
+ return member, err
+ }
+
+ member, err = member.Find(account.MemberId)
+ if err != nil {
+ return member, err
+ }
+
+ if member.Status != 0 {
+ return member, errors.New("receive_account_disabled")
+ }
+
+ return member, nil
+
+}
+
+// AddBind 添加一个用户.
+func (m *DingTalkAccount) AddBind(o orm.Ormer, userInfo auth2.UserInfo, member *Member) error {
+ tmpM := NewDingTalkAccount()
+ err := o.QueryTable(m.TableNameWithPrefix()).Filter("dingtalk_user_id", userInfo.UserId).One(tmpM)
+ if err == nil {
+ tmpM.MemberId = member.MemberId
+ _, err = o.Update(tmpM)
+ if err != nil {
+ logs.Error("保存用户数据到数据时失败 =>", err)
+ return errors.New("用户信息绑定失败, 数据库错误")
+ }
+ return nil
+ }
+
+ m.Dingtalk_UserId = userInfo.UserId
+ m.MemberId = member.MemberId
+
+ if c, err := o.QueryTable(m.TableNameWithPrefix()).Filter("member_id", m.MemberId).Count(); err == nil && c > 0 {
+ return errors.New("已绑定,不可重复绑定")
+ }
+
+ _, err = o.Insert(m)
+ if err != nil {
+ logs.Error("保存用户数据到数据时失败 =>", err)
+ return errors.New("用户信息绑定失败, 数据库错误")
+ }
+
+ return nil
+}
diff --git a/models/Blog.go b/models/Blog.go
index 7e8e5d191..679d56946 100644
--- a/models/Blog.go
+++ b/models/Blog.go
@@ -19,19 +19,19 @@ import (
type Blog struct {
BlogId int `orm:"pk;auto;unique;column(blog_id)" json:"blog_id"`
//文章标题
- BlogTitle string `orm:"column(blog_title);size(500)" json:"blog_title"`
+ BlogTitle string `orm:"column(blog_title);size(500);description(文章标题)" json:"blog_title"`
//文章标识
- BlogIdentify string `orm:"column(blog_identify);size(100);unique" json:"blog_identify"`
+ BlogIdentify string `orm:"column(blog_identify);size(100);unique;description(文章标识)" json:"blog_identify"`
//排序序号
- OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"`
+ OrderIndex int `orm:"column(order_index);type(int);default(0);description(排序序号)" json:"order_index"`
//所属用户
- MemberId int `orm:"column(member_id);type(int);default(0);index" json:"member_id"`
+ MemberId int `orm:"column(member_id);type(int);default(0);index;description(所属用户)" json:"member_id"`
//用户头像
MemberAvatar string `orm:"-" json:"member_avatar"`
//文章类型:0 普通文章/1 链接文章
- BlogType int `orm:"column(blog_type);type(int);default(0)" json:"blog_type"`
+ BlogType int `orm:"column(blog_type);type(int);default(0);description(文章类型: 0普通文章/1 链接文章)" json:"blog_type"`
//链接到的项目中的文档ID
- DocumentId int `orm:"column(document_id);type(int);default(0)" json:"document_id"`
+ DocumentId int `orm:"column(document_id);type(int);default(0);description(链接到的项目中的文档ID)" json:"document_id"`
//文章的标识
DocumentIdentify string `orm:"-" json:"document_identify"`
//关联文档的项目标识
@@ -39,25 +39,25 @@ type Blog struct {
//关联文档的项目ID
BookId int `orm:"-" json:"book_id"`
//文章摘要
- BlogExcerpt string `orm:"column(blog_excerpt);size(1500)" json:"blog_excerpt"`
+ BlogExcerpt string `orm:"column(blog_excerpt);size(1500);description(文章摘要)" json:"blog_excerpt"`
//文章内容
- BlogContent string `orm:"column(blog_content);type(text);null" json:"blog_content"`
+ BlogContent string `orm:"column(blog_content);type(text);null;description(文章内容)" json:"blog_content"`
//发布后的文章内容
- BlogRelease string `orm:"column(blog_release);type(text);null" json:"blog_release"`
+ BlogRelease string `orm:"column(blog_release);type(text);null;description(发布后的文章内容)" json:"blog_release"`
//文章当前的状态,枚举enum(’publish’,’draft’,’password’)值,publish为已 发表,draft为草稿,password 为私人内容(不会被公开) 。默认为publish。
- BlogStatus string `orm:"column(blog_status);size(100);default(publish)" json:"blog_status"`
+ BlogStatus string `orm:"column(blog_status);size(100);default(publish);description(状态:publish为已发表-默认,draft:草稿,password :私人内容-不会被公开)" json:"blog_status"`
//文章密码,varchar(100)值。文章编辑才可为文章设定一个密码,凭这个密码才能对文章进行重新强加或修改。
- Password string `orm:"column(password);size(100)" json:"-"`
+ Password string `orm:"column(password);size(100);description(文章密码)" json:"-"`
//最后修改时间
- Modified time.Time `orm:"column(modify_time);type(datetime);auto_now" json:"modify_time"`
+ Modified time.Time `orm:"column(modify_time);type(datetime);auto_now;description(最后修改时间)" json:"modify_time"`
//修改人id
- ModifyAt int `orm:"column(modify_at);type(int)" json:"-"`
+ ModifyAt int `orm:"column(modify_at);type(int);description(修改人id)" json:"-"`
ModifyRealName string `orm:"-" json:"modify_real_name"`
//创建时间
- Created time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
+ Created time.Time `orm:"column(create_time);type(datetime);auto_now_add;description(创建时间)" json:"create_time"`
CreateName string `orm:"-" json:"create_name"`
//版本号
- Version int64 `orm:"type(bigint);column(version)" json:"version"`
+ Version int64 `orm:"type(bigint);column(version);description(版本号)" json:"version"`
//附件列表
AttachList []*Attachment `orm:"-" json:"attach_list"`
}
diff --git a/models/BookModel.go b/models/BookModel.go
index 8d8aee472..d46d2ff5c 100644
--- a/models/BookModel.go
+++ b/models/BookModel.go
@@ -36,53 +36,53 @@ var once = sync.Once{}
type Book struct {
BookId int `orm:"pk;auto;unique;column(book_id)" json:"book_id"`
// BookName 项目名称.
- BookName string `orm:"column(book_name);size(500)" json:"book_name"`
+ BookName string `orm:"column(book_name);size(500);description(名称)" json:"book_name"`
//所属项目空间
- ItemId int `orm:"column(item_id);type(int);default(1)" json:"item_id"`
+ ItemId int `orm:"column(item_id);type(int);default(1);description(所属项目空间id)" json:"item_id"`
// Identify 项目唯一标识.
- Identify string `orm:"column(identify);size(100);unique" json:"identify"`
+ Identify string `orm:"column(identify);size(100);unique;description(唯一标识)" json:"identify"`
//是否是自动发布 0 否/1 是
- AutoRelease int `orm:"column(auto_release);type(int);default(0)" json:"auto_release"`
+ AutoRelease int `orm:"column(auto_release);type(int);default(0);description(是否是自动发布 0 否/1 是)" json:"auto_release"`
//是否开启下载功能 0 是/1 否
- IsDownload int `orm:"column(is_download);type(int);default(0)" json:"is_download"`
- OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"`
+ IsDownload int `orm:"column(is_download);type(int);default(0);description(是否开启下载功能 0 是/1 否)" json:"is_download"`
+ OrderIndex int `orm:"column(order_index);type(int);default(0);description(排序)" json:"order_index"`
// Description 项目描述.
- Description string `orm:"column(description);size(2000)" json:"description"`
+ Description string `orm:"column(description);size(2000);description(项目描述)" json:"description"`
//发行公司
- Publisher string `orm:"column(publisher);size(500)" json:"publisher"`
- Label string `orm:"column(label);size(500)" json:"label"`
+ Publisher string `orm:"column(publisher);size(500);description(发行公司)" json:"publisher"`
+ Label string `orm:"column(label);size(500);description(所属标签)" json:"label"`
// PrivatelyOwned 项目私有: 0 公开/ 1 私有
- PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"`
+ PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0);description(项目私有: 0 公开/ 1 私有)" json:"privately_owned"`
// 当项目是私有时的访问Token.
- PrivateToken string `orm:"column(private_token);size(500);null" json:"private_token"`
+ PrivateToken string `orm:"column(private_token);size(500);null;description(当项目是私有时的访问Token)" json:"private_token"`
//访问密码.
- BookPassword string `orm:"column(book_password);size(500);null" json:"book_password"`
+ BookPassword string `orm:"column(book_password);size(500);null;description(访问密码)" json:"book_password"`
//状态:0 正常/1 已删除
- Status int `orm:"column(status);type(int);default(0)" json:"status"`
+ Status int `orm:"column(status);type(int);default(0);description(状态:0 正常/1 已删除)" json:"status"`
//默认的编辑器.
- Editor string `orm:"column(editor);size(50)" json:"editor"`
+ Editor string `orm:"column(editor);size(50);description(默认的编辑器 markdown/html)" json:"editor"`
// DocCount 包含文档数量.
- DocCount int `orm:"column(doc_count);type(int)" json:"doc_count"`
+ DocCount int `orm:"column(doc_count);type(int);description(包含文档数量)" json:"doc_count"`
// CommentStatus 评论设置的状态:open 为允许所有人评论,closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论.
- CommentStatus string `orm:"column(comment_status);size(20);default(open)" json:"comment_status"`
- CommentCount int `orm:"column(comment_count);type(int)" json:"comment_count"`
+ CommentStatus string `orm:"column(comment_status);size(20);default(open);description(评论设置的状态:open 为允许所有人评论,closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论.)" json:"comment_status"`
+ CommentCount int `orm:"column(comment_count);type(int);description(评论数量)" json:"comment_count"`
//封面地址
- Cover string `orm:"column(cover);size(1000)" json:"cover"`
+ Cover string `orm:"column(cover);size(1000);description(封面地址)" json:"cover"`
//主题风格
- Theme string `orm:"column(theme);size(255);default(default)" json:"theme"`
+ Theme string `orm:"column(theme);size(255);default(default);description(主题风格)" json:"theme"`
// CreateTime 创建时间 .
- CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
+ CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add;description(创建时间)" json:"create_time"`
//每个文档保存的历史记录数量,0 为不限制
- HistoryCount int `orm:"column(history_count);type(int);default(0)" json:"history_count"`
+ HistoryCount int `orm:"column(history_count);type(int);default(0);description(每个文档保存的历史记录数量,0 为不限制)" json:"history_count"`
//是否启用分享,0启用/1不启用
- IsEnableShare int `orm:"column(is_enable_share);type(int);default(0)" json:"is_enable_share"`
- MemberId int `orm:"column(member_id);size(100)" json:"member_id"`
- ModifyTime time.Time `orm:"type(datetime);column(modify_time);null;auto_now" json:"modify_time"`
- Version int64 `orm:"type(bigint);column(version)" json:"version"`
+ IsEnableShare int `orm:"column(is_enable_share);type(int);default(0);description(是否启用分享,0启用/1不启用)" json:"is_enable_share"`
+ MemberId int `orm:"column(member_id);size(100);description(作者id)" json:"member_id"`
+ ModifyTime time.Time `orm:"type(datetime);column(modify_time);null;auto_now;description(修改时间)" json:"modify_time"`
+ Version int64 `orm:"type(bigint);column(version);description(版本)" json:"version"`
//是否使用第一篇文章项目为默认首页,0 否/1 是
- IsUseFirstDocument int `orm:"column(is_use_first_document);type(int);default(0)" json:"is_use_first_document"`
+ IsUseFirstDocument int `orm:"column(is_use_first_document);type(int);default(0);description(是否使用第一篇文章项目为默认首页,0 否/1 是)" json:"is_use_first_document"`
//是否开启自动保存:0 否/1 是
- AutoSave int `orm:"column(auto_save);type(tinyint);default(0)" json:"auto_save"`
+ AutoSave int `orm:"column(auto_save);type(tinyint);default(0);description(是否开启自动保存:0 否/1 是)" json:"auto_save"`
}
func (book *Book) String() string {
@@ -115,7 +115,7 @@ func NewBook() *Book {
return &Book{}
}
-//添加一个项目
+// 添加一个项目
func (book *Book) Insert(lang string) error {
o := orm.NewOrm()
// o.Begin()
@@ -167,7 +167,7 @@ func (book *Book) Find(id int, cols ...string) (*Book, error) {
return book, err
}
-//更新一个项目
+// 更新一个项目
func (book *Book) Update(cols ...string) error {
o := orm.NewOrm()
@@ -188,7 +188,7 @@ func (book *Book) Update(cols ...string) error {
return err
}
-//复制项目
+// 复制项目
func (book *Book) Copy(identify string) error {
o := orm.NewOrm()
@@ -290,7 +290,7 @@ func (book *Book) Copy(identify string) error {
return nil
}
-//递归的复制文档
+// 递归的复制文档
func recursiveInsertDocument(docs []*Document, o orm.TxOrmer, bookId int, parentId int) error {
for _, doc := range docs {
@@ -333,7 +333,7 @@ func recursiveInsertDocument(docs []*Document, o orm.TxOrmer, bookId int, parent
return nil
}
-//根据指定字段查询结果集.
+// 根据指定字段查询结果集.
func (book *Book) FindByField(field string, value interface{}, cols ...string) ([]*Book, error) {
o := orm.NewOrm()
@@ -343,7 +343,7 @@ func (book *Book) FindByField(field string, value interface{}, cols ...string) (
return books, err
}
-//根据指定字段查询一个结果.
+// 根据指定字段查询一个结果.
func (book *Book) FindByFieldFirst(field string, value interface{}) (*Book, error) {
o := orm.NewOrm()
@@ -353,7 +353,7 @@ func (book *Book) FindByFieldFirst(field string, value interface{}) (*Book, erro
}
-//根据项目标识查询项目
+// 根据项目标识查询项目
func (book *Book) FindByIdentify(identify string, cols ...string) (*Book, error) {
o := orm.NewOrm()
@@ -362,7 +362,7 @@ func (book *Book) FindByIdentify(identify string, cols ...string) (*Book, error)
return book, err
}
-//分页查询指定用户的项目
+// 分页查询指定用户的项目
func (book *Book) FindToPager(pageIndex, pageSize, memberId int, lang string) (books []*BookResult, totalCount int, err error) {
o := orm.NewOrm()
@@ -393,7 +393,7 @@ FROM md_books AS book
// " LEFT JOIN " + relationship.TableNameWithPrefix() + " AS rel ON book.book_id=rel.book_id AND rel.member_id = ?" +
// " LEFT JOIN " + relationship.TableNameWithPrefix() + " AS rel1 ON book.book_id=rel1.book_id AND rel1.role_id=0" +
// " LEFT JOIN " + NewMember().TableNameWithPrefix() + " AS m ON rel1.member_id=m.member_id " +
- // " WHERE rel.relationship_id > 0 ORDER BY book.order_index DESC,book.book_id DESC LIMIT " + fmt.Sprintf("%d,%d", offset, pageSize)
+ // " WHERE rel.relationship_id > 0 ORDER BY book.order_index DESC,book.book_id DESC LIMIT " + fmt.Sprintf("%d,%d", pageSize, offset)
sql2 := `SELECT
book.*,
@@ -410,9 +410,9 @@ FROM md_books AS book
LEFT JOIN md_relationship AS rel1 ON book.book_id = rel1.book_id AND rel1.role_id = 0
LEFT JOIN md_members AS m ON rel1.member_id = m.member_id
WHERE rel.role_id >= 0 or team.role_id >= 0
-ORDER BY book.order_index, book.book_id DESC limit ?,?`
+ORDER BY book.order_index, book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql2, memberId, memberId, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql2, memberId, memberId, pageSize, offset).QueryRows(&books)
if err != nil {
logs.Error("分页查询项目列表 => ", err)
return
@@ -521,7 +521,7 @@ func (book *Book) ThoroughDeleteBook(id int) error {
}
-//分页查找系统首页数据.
+// 分页查找系统首页数据.
func (book *Book) FindForHomeToPager(pageIndex, pageSize, memberId int) (books []*BookResult, totalCount int, err error) {
o := orm.NewOrm()
@@ -550,9 +550,9 @@ WHERE book.privately_owned = 0 or rel.role_id >=0 or team.role_id >=0`
as t group by book_id) as team on team.book_id=book.book_id
LEFT JOIN md_relationship AS rel1 ON rel1.book_id = book.book_id AND rel1.role_id = 0
LEFT JOIN md_members AS mdmb ON rel1.member_id = mdmb.member_id
-WHERE book.privately_owned = 0 or rel.role_id >=0 or team.role_id >=0 ORDER BY order_index desc,book.book_id DESC LIMIT ?,?`
+WHERE book.privately_owned = 0 or rel.role_id >=0 or team.role_id >=0 ORDER BY order_index desc,book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql2, memberId, memberId, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql2, memberId, memberId, pageSize, offset).QueryRows(&books)
} else {
count, err1 := o.QueryTable(book.TableNameWithPrefix()).Filter("privately_owned", 0).Count()
@@ -566,15 +566,15 @@ WHERE book.privately_owned = 0 or rel.role_id >=0 or team.role_id >=0 ORDER BY o
sql := `SELECT book.*,rel.*,mdmb.account AS create_name,mdmb.real_name FROM md_books AS book
LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.role_id = 0
LEFT JOIN md_members AS mdmb ON rel.member_id = mdmb.member_id
- WHERE book.privately_owned = 0 ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
+ WHERE book.privately_owned = 0 ORDER BY order_index DESC ,book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql, pageSize, offset).QueryRows(&books)
}
return
}
-//分页全局搜索.
+// 分页全局搜索.
func (book *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, memberId int) (books []*BookResult, totalCount int, err error) {
o := orm.NewOrm()
@@ -604,9 +604,9 @@ WHERE (relationship_id > 0 OR book.privately_owned = 0 or team.team_member_id >
LEFT JOIN md_relationship AS rel1 ON rel1.book_id = book.book_id AND rel1.role_id = 0
LEFT JOIN md_members AS mdmb ON rel1.member_id = mdmb.member_id
WHERE (rel.relationship_id > 0 OR book.privately_owned = 0 or team.team_member_id > 0)
- AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
+ AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql2, memberId, memberId, keyword, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql2, memberId, memberId, keyword, pageSize, offset).QueryRows(&books)
return
@@ -622,9 +622,9 @@ WHERE (relationship_id > 0 OR book.privately_owned = 0 or team.team_member_id >
sql := `SELECT book.*,rel.*,mdmb.account AS create_name FROM md_books AS book
LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.role_id = 0
LEFT JOIN md_members AS mdmb ON rel.member_id = mdmb.member_id
- WHERE book.privately_owned = 0 AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
+ WHERE book.privately_owned = 0 AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql, keyword, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql, keyword, pageSize, offset).QueryRows(&books)
return
@@ -665,7 +665,7 @@ func (book *Book) ReleaseContent(bookId int, lang string) {
})
}
-//重置文档数量
+// 重置文档数量
func (book *Book) ResetDocumentNumber(bookId int) {
o := orm.NewOrm()
@@ -1038,8 +1038,6 @@ func (book *Book) ImportWordBook(docxPath string, lang string) (err error) {
doc.DocumentName = strings.TrimSpace(docName)
- doc.DocumentId = book.MemberId
-
if err := doc.InsertOrUpdate("document_name", "book_id", "markdown", "content"); err != nil {
logs.Error(doc.DocumentId, err)
}
diff --git a/models/BookResult.go b/models/BookResult.go
index 9647f6e33..0ea535bcb 100644
--- a/models/BookResult.go
+++ b/models/BookResult.go
@@ -176,16 +176,16 @@ func (m *BookResult) FindToPager(pageIndex, pageSize int) (books []*BookResult,
FROM md_books AS book
LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.role_id = 0
LEFT JOIN md_members AS m ON rel.member_id = m.member_id
- ORDER BY book.order_index DESC ,book.book_id DESC LIMIT ?,?`
+ ORDER BY book.order_index DESC ,book.book_id DESC limit ? offset ?`
offset := (pageIndex - 1) * pageSize
- _, err = o.Raw(sql, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql, pageSize, offset).QueryRows(&books)
return
}
-//实体转换
+// 实体转换
func (m *BookResult) ToBookResult(book Book) *BookResult {
m.BookId = book.BookId
@@ -214,6 +214,7 @@ func (m *BookResult) ToBookResult(book Book) *BookResult {
m.IsDownload = book.IsDownload == 0
m.AutoSave = book.AutoSave == 1
m.ItemId = book.ItemId
+ m.RoleId = conf.BookRoleNoSpecific
if book.Theme == "" {
m.Theme = "default"
@@ -249,12 +250,13 @@ func (m *BookResult) ToBookResult(book Book) *BookResult {
} else if m.CommentStatus == "group_only" {
// todo
} else {
- m.IsDisplayComment = false;
+ m.IsDisplayComment = false
}
+
return m
}
-//后台转换
+// 后台转换
func BackgroundConvert(sessionId string, bookResult *BookResult) error {
if err := converter.CheckConvertCommand(); err != nil {
@@ -274,7 +276,7 @@ func BackgroundConvert(sessionId string, bookResult *BookResult) error {
return nil
}
-//导出PDF、word等格式
+// 导出PDF、word等格式
func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) {
convertBookResult := ConvertBookResult{}
@@ -521,7 +523,7 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) {
return convertBookResult, nil
}
-//导出Markdown原始文件
+// 导出Markdown原始文件
func (m *BookResult) ExportMarkdown(sessionId string) (string, error) {
outputPath := filepath.Join(conf.WorkingDirectory, "uploads", "books", strconv.Itoa(m.BookId), "book.zip")
@@ -546,7 +548,7 @@ func (m *BookResult) ExportMarkdown(sessionId string) (string, error) {
return outputPath, nil
}
-//递归导出Markdown文档
+// 递归导出Markdown文档
func exportMarkdown(p string, parentId int, bookId int, baseDir string, bookUrl string) error {
o := orm.NewOrm()
@@ -709,7 +711,7 @@ func recursiveJoinDocumentIdentify(parentDocId int, identify string) string {
return identify
}
-//查询项目的第一篇文档
+// 查询项目的第一篇文档
func (m *BookResult) FindFirstDocumentByBookId(bookId int) (*Document, error) {
o := orm.NewOrm()
diff --git a/models/DocumentHistory.go b/models/DocumentHistory.go
index 5f3c7b2b8..1d026e1c5 100644
--- a/models/DocumentHistory.go
+++ b/models/DocumentHistory.go
@@ -10,18 +10,18 @@ import (
type DocumentHistory struct {
HistoryId int `orm:"column(history_id);pk;auto;unique" json:"history_id"`
- Action string `orm:"column(action);size(255)" json:"action"`
- ActionName string `orm:"column(action_name);size(255)" json:"action_name"`
- DocumentId int `orm:"column(document_id);type(int);index" json:"doc_id"`
- DocumentName string `orm:"column(document_name);size(500)" json:"doc_name"`
- ParentId int `orm:"column(parent_id);type(int);index;default(0)" json:"parent_id"`
- Markdown string `orm:"column(markdown);type(text);null" json:"markdown"`
- Content string `orm:"column(content);type(text);null" json:"content"`
- MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
- ModifyTime time.Time `orm:"column(modify_time);type(datetime);auto_now" json:"modify_time"`
- ModifyAt int `orm:"column(modify_at);type(int)" json:"-"`
- Version int64 `orm:"type(bigint);column(version)" json:"version"`
- IsOpen int `orm:"column(is_open);type(int);default(0)" json:"is_open"`
+ Action string `orm:"column(action);size(255);description(modify)" json:"action"`
+ ActionName string `orm:"column(action_name);size(255);description(修改文档)" json:"action_name"`
+ DocumentId int `orm:"column(document_id);type(int);index;description(关联文档id)" json:"doc_id"`
+ DocumentName string `orm:"column(document_name);size(500);description(关联文档id)" json:"doc_name"`
+ ParentId int `orm:"column(parent_id);type(int);index;default(0);description(父级文档id)" json:"parent_id"`
+ Markdown string `orm:"column(markdown);type(text);null;description(文档内容)" json:"markdown"`
+ Content string `orm:"column(content);type(text);null;description(文档内容)" json:"content"`
+ MemberId int `orm:"column(member_id);type(int);description(作者id)" json:"member_id"`
+ ModifyTime time.Time `orm:"column(modify_time);type(datetime);auto_now;description(修改时间)" json:"modify_time"`
+ ModifyAt int `orm:"column(modify_at);type(int);description(修改人id)" json:"-"`
+ Version int64 `orm:"type(bigint);column(version);description(版本)" json:"version"`
+ IsOpen int `orm:"column(is_open);type(int);default(0);description(是否展开子目录 0:阅读时关闭节点 1:阅读时展开节点 2:空目录 单击时会展开下级节点)" json:"is_open"`
}
type DocumentHistorySimpleResult struct {
@@ -165,9 +165,9 @@ func (m *DocumentHistory) FindToPager(docId, pageIndex, pageSize int) (docs []*D
FROM md_document_history AS history
LEFT JOIN md_members AS m1 ON history.member_id = m1.member_id
LEFT JOIN md_members AS m2 ON history.modify_at = m2.member_id
-WHERE history.document_id = ? ORDER BY history.history_id DESC LIMIT ?,?;`
+WHERE history.document_id = ? ORDER BY history.history_id DESC limit ? offset ?;`
- _, err = o.Raw(sql, docId, offset, pageSize).QueryRows(&docs)
+ _, err = o.Raw(sql, docId, pageSize, offset).QueryRows(&docs)
if err != nil {
return
diff --git a/models/DocumentModel.go b/models/DocumentModel.go
index f0ed549cc..58a9ff098 100644
--- a/models/DocumentModel.go
+++ b/models/DocumentModel.go
@@ -24,37 +24,31 @@ import (
// Document struct.
type Document struct {
- DocumentId int `orm:"pk;auto;unique;column(document_id)" json:"doc_id"`
- DocumentName string `orm:"column(document_name);size(500)" json:"doc_name"`
- // Identify 文档唯一标识
- Identify string `orm:"column(identify);size(100);index;null;default(null)" json:"identify"`
- BookId int `orm:"column(book_id);type(int);index" json:"book_id"`
- ParentId int `orm:"column(parent_id);type(int);index;default(0)" json:"parent_id"`
- OrderSort int `orm:"column(order_sort);default(0);type(int);index" json:"order_sort"`
- // Markdown markdown格式文档.
- Markdown string `orm:"column(markdown);type(text);null" json:"markdown"`
- // Release 发布后的Html格式内容.
- Release string `orm:"column(release);type(text);null" json:"release"`
- // Content 未发布的 Html 格式内容.
- Content string `orm:"column(content);type(text);null" json:"content"`
- CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
- MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
- ModifyTime time.Time `orm:"column(modify_time);type(datetime);auto_now" json:"modify_time"`
- ModifyAt int `orm:"column(modify_at);type(int)" json:"-"`
- Version int64 `orm:"column(version);type(bigint);" json:"version"`
- //是否展开子目录:0 否/1 是 /2 空间节点,单击时展开下一级
- IsOpen int `orm:"column(is_open);type(int);default(0)" json:"is_open"`
- ViewCount int `orm:"column(view_count);type(int)" json:"view_count"`
- AttachList []*Attachment `orm:"-" json:"attach"`
+ DocumentId int `orm:"pk;auto;unique;column(document_id)" json:"doc_id"`
+ DocumentName string `orm:"column(document_name);size(500);description(文档名称)" json:"doc_name"`
+ Identify string `orm:"column(identify);size(100);index;null;default(null);description(唯一标识)" json:"identify"` // Identify 文档唯一标识
+ BookId int `orm:"column(book_id);type(int);index;description(关联bools表主键)" json:"book_id"`
+ ParentId int `orm:"column(parent_id);type(int);index;default(0);description(父级文档)" json:"parent_id"`
+ OrderSort int `orm:"column(order_sort);default(0);type(int);index;description(排序从小到大排序)" json:"order_sort"`
+ Markdown string `orm:"column(markdown);type(text);null;description(markdown内容)" json:"markdown"` // Markdown markdown格式文档.
+ MarkdownTheme string `orm:"column(markdown_theme);size(50);default(theme__light);description(markdown主题)" json:"markdown_theme"`
+ Release string `orm:"column(release);type(text);null;description(文章内容)" json:"release"` // Release 发布后的Html格式内容.
+ Content string `orm:"column(content);type(text);null;description(文章内容)" json:"content"` // Content 未发布的 Html 格式内容.
+ CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add;description(创建时间)" json:"create_time"`
+ MemberId int `orm:"column(member_id);type(int);description(关系用户id)" json:"member_id"`
+ ModifyTime time.Time `orm:"column(modify_time);type(datetime);auto_now;description(修改时间)" json:"modify_time"`
+ ModifyAt int `orm:"column(modify_at);type(int);description(修改人id)" json:"-"`
+ Version int64 `orm:"column(version);type(bigint);description(版本,关联历史文档里的version)" json:"version"`
+ IsOpen int `orm:"column(is_open);type(int);default(0);description(是否展开子目录 0:阅读时关闭节点 1:阅读时展开节点 2:空目录 单击时会展开下级节点)" json:"is_open"` //是否展开子目录:0 否/1 是 /2 空间节点,单击时展开下一级
+ ViewCount int `orm:"column(view_count);type(int);description(浏览量)" json:"view_count"`
+ AttachList []*Attachment `orm:"-" json:"attach"`
//i18n
Lang string `orm:"-"`
}
// 多字段唯一键
func (item *Document) TableUnique() [][]string {
- return [][]string{
- []string{"book_id", "identify"},
- }
+ return [][]string{{"book_id", "identify"}}
}
// TableName 获取对应数据库表名.
@@ -77,7 +71,7 @@ func NewDocument() *Document {
}
}
-//根据文档ID查询指定文档.
+// 根据文档ID查询指定文档.
func (item *Document) Find(id int) (*Document, error) {
if id <= 0 {
return item, ErrInvalidParameter
@@ -94,7 +88,7 @@ func (item *Document) Find(id int) (*Document, error) {
return item, nil
}
-//插入和更新文档.
+// 插入和更新文档.
func (item *Document) InsertOrUpdate(cols ...string) error {
o := orm.NewOrm()
item.DocumentName = utils.StripTags(item.DocumentName)
@@ -126,7 +120,7 @@ func (item *Document) InsertOrUpdate(cols ...string) error {
return nil
}
-//根据文档识别编号和项目id获取一篇文档
+// 根据文档识别编号和项目id获取一篇文档
func (item *Document) FindByIdentityFirst(identify string, bookId int) (*Document, error) {
o := orm.NewOrm()
@@ -135,7 +129,7 @@ func (item *Document) FindByIdentityFirst(identify string, bookId int) (*Documen
return item, err
}
-//递归删除一个文档.
+// 递归删除一个文档.
func (item *Document) RecursiveDocument(docId int) error {
o := orm.NewOrm()
@@ -163,7 +157,7 @@ func (item *Document) RecursiveDocument(docId int) error {
return nil
}
-//将文档写入缓存
+// 将文档写入缓存
func (item *Document) PutToCache() {
go func(m Document) {
@@ -181,7 +175,7 @@ func (item *Document) PutToCache() {
}(*item)
}
-//清除缓存
+// 清除缓存
func (item *Document) RemoveCache() {
go func(m Document) {
cache.Put("Document.Id."+strconv.Itoa(m.DocumentId), m, time.Second*3600)
@@ -192,7 +186,7 @@ func (item *Document) RemoveCache() {
}(*item)
}
-//从缓存获取
+// 从缓存获取
func (item *Document) FromCacheById(id int) (*Document, error) {
if err := cache.Get("Document.Id."+strconv.Itoa(id), &item); err == nil && item.DocumentId > 0 {
@@ -211,7 +205,7 @@ func (item *Document) FromCacheById(id int) (*Document, error) {
return item, err
}
-//根据文档标识从缓存中查询文档
+// 根据文档标识从缓存中查询文档
func (item *Document) FromCacheByIdentify(identify string, bookId int) (*Document, error) {
key := fmt.Sprintf("Document.BookId.%d.Identify.%s", bookId, identify)
@@ -229,7 +223,7 @@ func (item *Document) FromCacheByIdentify(identify string, bookId int) (*Documen
return item.FindByIdentityFirst(identify, bookId)
}
-//根据项目ID查询文档列表.
+// 根据项目ID查询文档列表.
func (item *Document) FindListByBookId(bookId int) (docs []*Document, err error) {
o := orm.NewOrm()
@@ -238,14 +232,14 @@ func (item *Document) FindListByBookId(bookId int) (docs []*Document, err error)
return
}
-//判断文章是否存在
+// 判断文章是否存在
func (item *Document) IsExist(documentId int) bool {
o := orm.NewOrm()
return o.QueryTable(item.TableNameWithPrefix()).Filter("document_id", documentId).Exist()
}
-//发布单篇文档
+// 发布单篇文档
func (item *Document) ReleaseContent() error {
item.Release = strings.TrimSpace(item.Content)
@@ -267,127 +261,136 @@ func (item *Document) ReleaseContent() error {
return nil
}
-//处理文档的外链,附件,底部编辑信息等.
+// Processor 调用位置两处:
+// 1. 项目发布和文档发布: 处理文档的外链,附件,底部编辑信息等;
+// 2. 文档阅读:可以修复存在问题的文档,使其能正常显示附件下载和文档作者信息等。
func (item *Document) Processor() *Document {
if item.Release != "" {
item.Release = utils.SafetyProcessor(item.Release)
+ } else {
+ // Release内容为空,直接赋值文档标签,保证附件下载正常
+ item.Release = "
"
+ }
- //安全过滤,移除危险标签和属性
- if docQuery, err := goquery.NewDocumentFromReader(bytes.NewBufferString(item.Release)); err == nil {
+ // Next: 生成文档的一些附加信息
+ if docQuery, err := goquery.NewDocumentFromReader(bytes.NewBufferString(item.Release)); err == nil {
+ //处理附件
+ if selector := docQuery.Find("div.attach-list").First(); selector.Size() <= 0 {
//处理附件
- if selector := docQuery.Find("div.attach-list").First(); selector.Size() <= 0 {
- //处理附件
- attachList, err := NewAttachment().FindListByDocumentId(item.DocumentId)
- if err == nil && len(attachList) > 0 {
- content := bytes.NewBufferString("" + i18n.Tr(item.Lang, "doc.attachment") + "")
- for _, attach := range attachList {
- if strings.HasPrefix(attach.HttpPath, "/") {
- attach.HttpPath = strings.TrimSuffix(conf.BaseUrl, "/") + attach.HttpPath
- }
- li := fmt.Sprintf("- %s
", attach.HttpPath, attach.FileName, attach.FileName)
-
- content.WriteString(li)
+ attachList, err := NewAttachment().FindListByDocumentId(item.DocumentId)
+ if err == nil && len(attachList) > 0 {
+ content := bytes.NewBufferString("" + i18n.Tr(item.Lang, "doc.attachment") + "")
+ for _, attach := range attachList {
+ if strings.HasPrefix(attach.HttpPath, "/") {
+ attach.HttpPath = strings.TrimSuffix(conf.BaseUrl, "/") + attach.HttpPath
}
- content.WriteString("
")
- if docQuery == nil {
- docQuery, err = goquery.NewDocumentFromReader(content)
- } else {
- if selector := docQuery.Find("div.wiki-bottom").First(); selector.Size() > 0 {
- selector.BeforeHtml(content.String())
- } else if selector := docQuery.Find("div.markdown-article").First(); selector.Size() > 0 {
- selector.AppendHtml(content.String())
- } else if selector := docQuery.Find("article.markdown-article-inner").First(); selector.Size() > 0 {
- selector.AppendHtml(content.String())
- }
+ li := fmt.Sprintf("- %s
", attach.HttpPath, attach.FileName, attach.FileName)
+
+ content.WriteString(li)
+ }
+ content.WriteString("
")
+ if docQuery == nil {
+ docQuery, err = goquery.NewDocumentFromReader(content)
+ if err != nil {
+ logs.Error("goquery->NewDocumentFromReader err:%+v", err)
+ }
+ } else {
+ if selector := docQuery.Find("div.wiki-bottom").First(); selector.Size() > 0 {
+ selector.BeforeHtml(content.String()) //This branch should be a compatible branch.
+ } else if selector := docQuery.Find("div.markdown-article").First(); selector.Size() > 0 {
+ selector.AppendHtml(content.String()) //The document produced by the editor of Markdown will have this tag.class.
+ } else if selector := docQuery.Find("div.whole-article-wrap").First(); selector.Size() > 0 {
+ selector.AppendHtml(content.String()) //All documents should have this tag.
}
}
}
+ }
- //处理了文档底部信息
- if selector := docQuery.Find("div.wiki-bottom").First(); selector.Size() <= 0 && item.MemberId > 0 {
- //处理文档结尾信息
- docCreator, err := NewMember().Find(item.MemberId, "real_name", "account")
- release := ""
+ //处理了文档底部信息
+ if selector := docQuery.Find("div.wiki-bottom").First(); selector.Size() <= 0 && item.MemberId > 0 {
+ //处理文档结尾信息
+ docCreator, err := NewMember().Find(item.MemberId, "real_name", "account")
+ release := "
"
+
+ release += i18n.Tr(item.Lang, "doc.ft_author")
+ if err == nil && docCreator != nil {
+ if docCreator.RealName != "" {
+ release += docCreator.RealName
+ } else {
+ release += docCreator.Account
+ }
+ }
+ release += " " + i18n.Tr(item.Lang, "doc.ft_create_time") + item.CreateTime.Local().Format("2006-01-02 15:04") + "
"
- release += i18n.Tr(item.Lang, "doc.ft_author")
- if err == nil && docCreator != nil {
- if docCreator.RealName != "" {
- release += docCreator.RealName
+ if item.ModifyAt > 0 {
+ docModify, err := NewMember().Find(item.ModifyAt, "real_name", "account")
+ if err == nil {
+ if docModify.RealName != "" {
+ release += i18n.Tr(item.Lang, "doc.ft_last_editor") + docModify.RealName
} else {
- release += docCreator.Account
+ release += i18n.Tr(item.Lang, "doc.ft_last_editor") + docModify.Account
}
}
- release += " " + i18n.Tr(item.Lang, "doc.ft_create_time") + item.CreateTime.Local().Format("2006-01-02 15:04") + "
"
-
- if item.ModifyAt > 0 {
- docModify, err := NewMember().Find(item.ModifyAt, "real_name", "account")
- if err == nil {
- if docModify.RealName != "" {
- release += i18n.Tr(item.Lang, "doc.ft_last_editor") + docModify.RealName
- } else {
- release += i18n.Tr(item.Lang, "doc.ft_last_editor") + docModify.Account
- }
- }
- }
- release += " " + i18n.Tr(item.Lang, "doc.ft_update_time") + item.ModifyTime.Local().Format("2006-01-02 15:04") + "
"
- release += "
"
+ }
+ release += " " + i18n.Tr(item.Lang, "doc.ft_update_time") + item.ModifyTime.Local().Format("2006-01-02 15:04") + "
"
+ release += "
"
- if selector := docQuery.Find("div.markdown-article").First(); selector.Size() > 0 {
- selector.AppendHtml(release)
- } else if selector := docQuery.Find("article.markdown-article-inner").First(); selector.Size() > 0 {
- selector.First().AppendHtml(release)
- }
+ if selector := docQuery.Find("div.markdown-article").First(); selector.Size() > 0 {
+ selector.AppendHtml(release)
+ } else if selector := docQuery.Find("div.whole-article-wrap").First(); selector.Size() > 0 {
+ selector.AppendHtml(release)
}
- cdnimg, _ := web.AppConfig.String("cdnimg")
+ }
+ cdnimg, _ := web.AppConfig.String("cdnimg")
- docQuery.Find("img").Each(func(i int, selection *goquery.Selection) {
+ docQuery.Find("img").Each(func(i int, selection *goquery.Selection) {
- if src, ok := selection.Attr("src"); ok {
- src = strings.TrimSpace(strings.ToLower(src))
- //过滤掉没有链接的图片标签
- if src == "" || strings.HasPrefix(src, "data:text/html") {
- selection.Remove()
- return
- }
+ if src, ok := selection.Attr("src"); ok {
+ src = strings.TrimSpace(strings.ToLower(src))
+ //过滤掉没有链接的图片标签
+ if src == "" || strings.HasPrefix(src, "data:text/html") {
+ selection.Remove()
+ return
+ }
- //设置图片为CDN地址
- if cdnimg != "" && strings.HasPrefix(src, "/uploads/") {
- selection.SetAttr("src", utils.JoinURI(cdnimg, src))
- }
+ //设置图片为CDN地址
+ if cdnimg != "" && strings.HasPrefix(src, "/uploads/") {
+ selection.SetAttr("src", utils.JoinURI(cdnimg, src))
+ }
+ }
+ selection.RemoveAttr("onerror").RemoveAttr("onload")
+ })
+ //过滤A标签的非法连接
+ docQuery.Find("a").Each(func(i int, selection *goquery.Selection) {
+ if val, exists := selection.Attr("href"); exists {
+ if val == "" {
+ selection.SetAttr("href", "#")
+ return
}
- selection.RemoveAttr("onerror").RemoveAttr("onload")
- })
- //过滤A标签的非法连接
- docQuery.Find("a").Each(func(i int, selection *goquery.Selection) {
- if val, exists := selection.Attr("href"); exists {
- if val == "" {
- selection.SetAttr("href", "#")
- return
- }
- val = strings.Replace(strings.ToLower(val), " ", "", -1)
- //移除危险脚本链接
- if strings.HasPrefix(val, "data:text/html") ||
- strings.HasPrefix(val, "vbscript:") ||
- strings.HasPrefix(val, "javascript:") ||
- strings.HasPrefix(val, "javascript:") {
- selection.SetAttr("href", "#")
- }
+ val = strings.Replace(strings.ToLower(val), " ", "", -1)
+ //移除危险脚本链接
+ if strings.HasPrefix(val, "data:text/html") ||
+ strings.HasPrefix(val, "vbscript:") ||
+ strings.HasPrefix(val, "javascript:") ||
+ strings.HasPrefix(val, "javascript:") {
+ selection.SetAttr("href", "#")
}
- //移除所有 onerror 属性
- selection.RemoveAttr("onerror").RemoveAttr("onload").RemoveAttr("onclick")
- })
+ }
+ //移除所有 onerror 属性
+ selection.RemoveAttr("onerror").RemoveAttr("onload").RemoveAttr("onclick")
+ })
- docQuery.Find("script").Remove()
- docQuery.Find("link").Remove()
- docQuery.Find("vbscript").Remove()
+ docQuery.Find("script").Remove()
+ docQuery.Find("link").Remove()
+ docQuery.Find("vbscript").Remove()
- if html, err := docQuery.Html(); err == nil {
- item.Release = strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(html), ""), "")
- }
+ if html, err := docQuery.Html(); err == nil {
+ item.Release = strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(html), ""), "")
}
}
+
return item
}
diff --git a/models/DocumentSearchResult.go b/models/DocumentSearchResult.go
index afb751de6..5be74055c 100644
--- a/models/DocumentSearchResult.go
+++ b/models/DocumentSearchResult.go
@@ -96,7 +96,7 @@ WHERE book.privately_owned = 0 AND (book.book_name LIKE ? OR book.description LI
WHERE blog.blog_status = 'public' AND (blog.blog_release LIKE ? OR blog.blog_title LIKE ?)
) AS union_table
ORDER BY create_time DESC
-LIMIT ?, ?;`
+LIMIT ? OFFSET ?;`
err = o.Raw(sql1, keyword, keyword).QueryRow(&totalCount)
if err != nil {
@@ -128,7 +128,7 @@ WHERE book.privately_owned = 0 AND (book.book_name LIKE ? OR book.description LI
totalCount += c
- _, err = o.Raw(sql2, keyword, keyword, keyword, keyword, keyword, keyword, offset, pageSize).QueryRows(&searchResult)
+ _, err = o.Raw(sql2, keyword, keyword, keyword, keyword, keyword, keyword, pageSize, offset).QueryRows(&searchResult)
if err != nil {
logs.Error("查询搜索结果失败 -> ", err)
return
@@ -224,7 +224,7 @@ FROM (
(blog.blog_release LIKE ? OR blog.blog_title LIKE ?)
) AS union_table
ORDER BY create_time DESC
-LIMIT ?, ?;`
+LIMIT ? OFFSET ?;`
err = o.Raw(sql1, memberId, memberId, keyword, keyword).QueryRow(&totalCount)
if err != nil {
@@ -262,7 +262,7 @@ WHERE (book.privately_owned = 0 OR rel1.relationship_id > 0 or team.team_member_
totalCount += c
- _, err = o.Raw(sql2, memberId, memberId, keyword, keyword, memberId, memberId, keyword, keyword, memberId, keyword, keyword, offset, pageSize).QueryRows(&searchResult)
+ _, err = o.Raw(sql2, memberId, memberId, keyword, keyword, memberId, memberId, keyword, keyword, memberId, keyword, keyword, pageSize, offset).QueryRows(&searchResult)
if err != nil {
return
}
diff --git a/models/Itemsets.go b/models/Itemsets.go
index 07b8894f2..fe0531575 100644
--- a/models/Itemsets.go
+++ b/models/Itemsets.go
@@ -15,13 +15,13 @@ import (
//项目空间
type Itemsets struct {
ItemId int `orm:"column(item_id);pk;auto;unique" json:"item_id"`
- ItemName string `orm:"column(item_name);size(500)" json:"item_name"`
- ItemKey string `orm:"column(item_key);size(100);unique" json:"item_key"`
- Description string `orm:"column(description);type(text);null" json:"description"`
- MemberId int `orm:"column(member_id);size(100)" json:"member_id"`
- CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
- ModifyTime time.Time `orm:"column(modify_time);type(datetime);null;auto_now" json:"modify_time"`
- ModifyAt int `orm:"column(modify_at);type(int)" json:"modify_at"`
+ ItemName string `orm:"column(item_name);size(500);description(项目空间名称)" json:"item_name"`
+ ItemKey string `orm:"column(item_key);size(100);unique;description(项目空间标识)" json:"item_key"`
+ Description string `orm:"column(description);type(text);null;description(描述)" json:"description"`
+ MemberId int `orm:"column(member_id);size(100);description(所属用户)" json:"member_id"`
+ CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add;description(创建时间)" json:"create_time"`
+ ModifyTime time.Time `orm:"column(modify_time);type(datetime);null;auto_now;description(修改时间)" json:"modify_time"`
+ ModifyAt int `orm:"column(modify_at);type(int);description(修改人id)" json:"modify_at"`
BookNumber int `orm:"-" json:"book_number"`
CreateTimeString string `orm:"-" json:"create_time_string"`
@@ -246,9 +246,9 @@ as t group by book_id) as team
LEFT JOIN md_relationship AS rel1 ON rel1.book_id = book.book_id AND rel1.role_id = 0
LEFT JOIN md_members AS mdmb ON rel1.member_id = mdmb.member_id
WHERE book.item_id = ? AND (book.privately_owned = 0 or rel.role_id >= 0 or team.role_id >= 0)
- ORDER BY order_index desc,book.book_id DESC LIMIT ?,?`
+ ORDER BY order_index desc,book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql2, memberId, memberId, item.ItemId, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql2, memberId, memberId, item.ItemId, pageSize, offset).QueryRows(&books)
return
@@ -264,9 +264,9 @@ as t group by book_id) as team
sql := `SELECT book.*,rel.*,mdmb.account AS create_name FROM md_books AS book
LEFT JOIN md_relationship AS rel ON rel.book_id = book.book_id AND rel.role_id = 0
LEFT JOIN md_members AS mdmb ON rel.member_id = mdmb.member_id
- WHERE book.item_id = ? AND book.privately_owned = 0 ORDER BY order_index desc,book.book_id DESC LIMIT ?,?`
+ WHERE book.item_id = ? AND book.privately_owned = 0 ORDER BY order_index desc,book.book_id DESC limit ? offset ?`
- _, err = o.Raw(sql, item.ItemId, offset, pageSize).QueryRows(&books)
+ _, err = o.Raw(sql, item.ItemId, pageSize, offset).QueryRows(&books)
return
diff --git a/models/LabelModel.go b/models/LabelModel.go
index 49a8ebf81..9645b62a7 100644
--- a/models/LabelModel.go
+++ b/models/LabelModel.go
@@ -9,9 +9,9 @@ import (
)
type Label struct {
- LabelId int `orm:"column(label_id);pk;auto;unique;" json:"label_id"`
- LabelName string `orm:"column(label_name);size(50);unique" json:"label_name"`
- BookNumber int `orm:"column(book_number)" json:"book_number"`
+ LabelId int `orm:"column(label_id);pk;auto;unique;description(项目标签id)" json:"label_id"`
+ LabelName string `orm:"column(label_name);size(50);unique;description(项目标签名称)" json:"label_name"`
+ BookNumber int `orm:"column(book_number);description(包涵项目数量)" json:"book_number"`
}
// TableName 获取对应数据库表名.
diff --git a/models/Member.go b/models/Member.go
index 49916e242..d217cd720 100644
--- a/models/Member.go
+++ b/models/Member.go
@@ -3,11 +3,13 @@ package models
import (
"crypto/md5"
+ "crypto/tls"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
+ "net"
"net/http"
"net/url"
"regexp"
@@ -15,7 +17,7 @@ import (
"strings"
"time"
- "gopkg.in/ldap.v2"
+ "github.com/go-ldap/ldap/v3"
"math"
@@ -27,24 +29,26 @@ import (
"github.com/mindoc-org/mindoc/utils"
)
+var LdapDefaultTimeout = 8 * time.Second
+
type Member struct {
MemberId int `orm:"pk;auto;unique;column(member_id)" json:"member_id"`
- Account string `orm:"size(100);unique;column(account)" json:"account"`
- RealName string `orm:"size(255);column(real_name)" json:"real_name"`
- Password string `orm:"size(1000);column(password)" json:"-"`
+ Account string `orm:"size(100);unique;column(account);description(登录名)" json:"account"`
+ RealName string `orm:"size(255);column(real_name);description(真实姓名)" json:"real_name"`
+ Password string `orm:"size(1000);column(password);description(密码)" json:"-"`
//认证方式: local 本地数据库 /ldap LDAP
- AuthMethod string `orm:"column(auth_method);default(local);size(50);" json:"auth_method"`
- Description string `orm:"column(description);size(2000)" json:"description"`
- Email string `orm:"size(100);column(email);unique" json:"email"`
- Phone string `orm:"size(255);column(phone);null;default(null)" json:"phone"`
- Avatar string `orm:"size(1000);column(avatar)" json:"avatar"`
+ AuthMethod string `orm:"column(auth_method);default(local);size(50);description(授权方式 local:本地校验 ldap:LDAP用户校验)" json:"auth_method"`
+ Description string `orm:"column(description);size(2000);description(描述)" json:"description"`
+ Email string `orm:"size(100);column(email);unique;description(邮箱)" json:"email"`
+ Phone string `orm:"size(255);column(phone);null;default(null);description(手机)" json:"phone"`
+ Avatar string `orm:"size(1000);column(avatar);description(头像)" json:"avatar"`
//用户角色:0 超级管理员 /1 管理员/ 2 普通用户 .
- Role conf.SystemRole `orm:"column(role);type(int);default(1);index" json:"role"`
+ Role conf.SystemRole `orm:"column(role);type(int);default(1);index;description(用户角色: 0:超级管理员 1:管理员 2:普通用户)" json:"role"`
RoleName string `orm:"-" json:"role_name"`
- Status int `orm:"column(status);type(int);default(0)" json:"status"` //用户状态:0 正常/1 禁用
- CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
- CreateAt int `orm:"type(int);column(create_at)" json:"create_at"`
- LastLoginTime time.Time `orm:"type(datetime);column(last_login_time);null" json:"last_login_time"`
+ Status int `orm:"column(status);type(int);default(0);description(状态 0:启用 1:禁用)" json:"status"` //用户状态:0 正常/1 禁用
+ CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add;description(创建时间)" json:"create_time"`
+ CreateAt int `orm:"type(int);column(create_at);description(创建人id)" json:"create_at"`
+ LastLoginTime time.Time `orm:"type(datetime);column(last_login_time);null;description(最后登录时间)" json:"last_login_time"`
//i18n
Lang string `orm:"-"`
}
@@ -90,7 +94,6 @@ func (m *Member) Login(account string, password string) (*Member, error) {
}
switch member.AuthMethod {
- case "":
case "local":
ok, err := utils.PasswordVerify(member.Password, password)
if ok && err == nil {
@@ -109,24 +112,34 @@ func (m *Member) Login(account string, password string) (*Member, error) {
}
// TmpLogin 用于钉钉临时登录
-func (m *Member) TmpLogin(account string) (*Member, error) {
- o := orm.NewOrm()
- member := &Member{}
- err := o.Raw("select * from md_members where account = ? and status = 0 limit 1;", account).QueryRow(member)
- if err != nil {
- return member, ErrorMemberPasswordError
- }
- return member, nil
-}
-
-//ldapLogin 通过LDAP登陆
+//func (m *Member) TmpLogin(account string) (*Member, error) {
+// o := orm.NewOrm()
+// member := &Member{}
+// err := o.Raw("select * from md_members where account = ? and status = 0 limit 1;", account).QueryRow(member)
+// if err != nil {
+// return member, ErrorMemberPasswordError
+// }
+// return member, nil
+//}
+
+// ldapLogin 通过LDAP登陆
func (m *Member) ldapLogin(account string, password string) (*Member, error) {
if !web.AppConfig.DefaultBool("ldap_enable", false) {
return m, ErrMemberAuthMethodInvalid
}
var err error
- ldaphost, _ := web.AppConfig.String("ldap_host")
- lc, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldaphost, web.AppConfig.DefaultInt("ldap_port", 3268)))
+ var ldapOpt ldap.DialOpt
+ ldap_scheme := web.AppConfig.DefaultString("ldap_scheme", "ldap")
+ dialer := net.Dialer{Timeout: LdapDefaultTimeout}
+ if ldap_scheme == "ldaps" {
+ ldapOpt = ldap.DialWithTLSDialer(&tls.Config{InsecureSkipVerify: true}, &dialer)
+ } else {
+ ldapOpt = ldap.DialWithDialer(&dialer)
+ }
+ ldap_host, _ := web.AppConfig.String("ldap_host")
+ ldap_port := web.AppConfig.DefaultInt("ldap_port", 3268)
+ ldap_url := fmt.Sprintf("%s://%s:%d", ldap_scheme, ldap_host, ldap_port)
+ lc, err := ldap.DialURL(ldap_url, ldapOpt)
if err != nil {
logs.Error("绑定 LDAP 用户失败 ->", err)
return m, ErrLDAPConnect
@@ -141,13 +154,23 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) {
}
ldapbase, _ := web.AppConfig.String("ldap_base")
ldapfilter, _ := web.AppConfig.String("ldap_filter")
- ldapattr, _ := web.AppConfig.String("ldap_attribute")
+ ldapaccount, _ := web.AppConfig.String("ldap_account")
+ ldapmail, _ := web.AppConfig.String("ldap_mail")
+ // 判断account是否是email
+ isEmail := false
+ var email string
+ ldapattr := ldapaccount
+ if ok, err := regexp.MatchString(conf.RegexpEmail, account); ok && err == nil {
+ isEmail = true
+ email = account
+ ldapattr = ldapmail
+ }
searchRequest := ldap.NewSearchRequest(
ldapbase,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
- //修改objectClass通过配置文件获取值
+ // 修改objectClass通过配置文件获取值
fmt.Sprintf("(&(%s)(%s=%s))", ldapfilter, ldapattr, account),
- []string{"dn", "mail"},
+ []string{"dn", "mail", "cn", "ou", "sAMAccountName"},
nil,
)
searchResult, err := lc.Search(searchRequest)
@@ -164,10 +187,33 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) {
logs.Error("绑定 LDAP 用户失败 ->", err)
return m, ErrorMemberPasswordError
}
+
+ ldap_cn := searchResult.Entries[0].GetAttributeValue("cn")
+ ldap_mail := searchResult.Entries[0].GetAttributeValue(ldapmail) // "mail"
+ ldap_account := searchResult.Entries[0].GetAttributeValue(ldapaccount) // "sAMAccountName"
+
+ m.RealName = ldap_cn
+ m.Account = ldap_account
+ m.AuthMethod = "ldap"
+ // 如果ldap配置了email
+ if len(ldap_mail) > 0 && strings.Contains(ldap_mail, "@") {
+ // 如果member已配置email
+ if len(m.Email) > 0 {
+ // 如果member配置的email和ldap配置的email不同
+ if m.Email != ldap_mail {
+ return m, fmt.Errorf("ldap配置的email(%s)与数据库中已有email({%s})不同, 请联系管理员修改", ldap_mail, m.Email)
+ }
+ } else {
+ // 如果member未配置email,则用ldap的email配置
+ m.Email = ldap_mail
+ }
+ } else {
+ // 如果ldap未配置email,则直接绑定到member
+ if isEmail {
+ m.Email = email
+ }
+ }
if m.MemberId <= 0 {
- m.Account = account
- m.Email = searchResult.Entries[0].GetAttributeValue("mail")
- m.AuthMethod = "ldap"
m.Avatar = "/static/images/headimgurl.jpg"
m.Role = conf.SystemRole(web.AppConfig.DefaultInt("ldap_user_role", 2))
m.CreateTime = time.Now()
@@ -178,6 +224,14 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) {
return m, ErrorMemberPasswordError
}
m.ResolveRoleName()
+ } else {
+ // 更新ldap信息
+ err = m.Update("account", "real_name", "email", "auth_method")
+ if err != nil {
+ logs.Error("LDAP更新用户信息失败", err)
+ return m, errors.New("LDAP更新用户信息失败")
+ }
+ m.ResolveRoleName()
}
return m, nil
}
@@ -338,7 +392,7 @@ func (m *Member) ResolveRoleName() {
}
}
-//根据账号查找用户.
+// 根据账号查找用户.
func (m *Member) FindByAccount(account string) (*Member, error) {
o := orm.NewOrm()
@@ -350,7 +404,7 @@ func (m *Member) FindByAccount(account string) (*Member, error) {
return m, err
}
-//批量查询用户
+// 批量查询用户
func (m *Member) FindByAccountList(accounts ...string) ([]*Member, error) {
o := orm.NewOrm()
@@ -365,7 +419,7 @@ func (m *Member) FindByAccountList(accounts ...string) ([]*Member, error) {
return members, err
}
-//分页查找用户.
+// 分页查找用户.
func (m *Member) FindToPager(pageIndex, pageSize int) ([]*Member, int, error) {
o := orm.NewOrm()
@@ -399,7 +453,7 @@ func (m *Member) IsAdministrator() bool {
return m.Role == 0 || m.Role == 1
}
-//根据指定字段查找用户.
+// 根据指定字段查找用户.
func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, error) {
o := orm.NewOrm()
@@ -408,7 +462,7 @@ func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, err
return m, err
}
-//校验用户.
+// 校验用户.
func (m *Member) Valid(is_hash_password bool) error {
//邮箱不能为空
@@ -464,22 +518,31 @@ func (m *Member) Valid(is_hash_password bool) error {
return nil
}
-//删除一个用户.
+// 删除一个用户.
func (m *Member) Delete(oldId int, newId int) error {
ormer := orm.NewOrm()
o, err := ormer.Begin()
-
if err != nil {
return err
}
+ _, err = o.Raw("DELETE FROM md_dingtalk_accounts WHERE member_id = ?", oldId).Exec()
+ if err != nil {
+ o.Rollback()
+ return err
+ }
+ _, err = o.Raw("DELETE FROM md_workweixin_accounts WHERE member_id = ?", oldId).Exec()
+ if err != nil {
+ o.Rollback()
+ return err
+ }
_, err = o.Raw("DELETE FROM md_members WHERE member_id = ?", oldId).Exec()
if err != nil {
o.Rollback()
return err
}
- _, err = o.Raw("UPDATE md_attachment SET `create_at` = ? WHERE `create_at` = ?", newId, oldId).Exec()
+ _, err = o.Raw("UPDATE md_attachment SET create_at = ? WHERE create_at = ?", newId, oldId).Exec()
if err != nil {
o.Rollback()
diff --git a/models/MemberResult.go b/models/MemberResult.go
index 3926ae0ae..8688e85b2 100644
--- a/models/MemberResult.go
+++ b/models/MemberResult.go
@@ -72,7 +72,7 @@ func (m *MemberRelationshipResult) FindForUsersByBookId(lang string, bookId, pag
var members []*MemberRelationshipResult
- sql1 := "SELECT * FROM md_relationship AS rel LEFT JOIN md_members as mdmb ON rel.member_id = mdmb.member_id WHERE rel.book_id = ? ORDER BY rel.relationship_id DESC LIMIT ?,?"
+ sql1 := "SELECT * FROM md_relationship AS rel LEFT JOIN md_members as mdmb ON rel.member_id = mdmb.member_id WHERE rel.book_id = ? ORDER BY rel.relationship_id DESC limit ? offset ?"
sql2 := "SELECT count(*) AS total_count FROM md_relationship AS rel LEFT JOIN md_members as mdmb ON rel.member_id = mdmb.member_id WHERE rel.book_id = ?"
@@ -86,7 +86,7 @@ func (m *MemberRelationshipResult) FindForUsersByBookId(lang string, bookId, pag
offset := (pageIndex - 1) * pageSize
- _, err = o.Raw(sql1, bookId, offset, pageSize).QueryRows(&members)
+ _, err = o.Raw(sql1, bookId, pageSize, offset).QueryRows(&members)
if err != nil {
return members, 0, err
diff --git a/models/Relationship.go b/models/Relationship.go
index 7f9fe801f..8de89c334 100644
--- a/models/Relationship.go
+++ b/models/Relationship.go
@@ -10,13 +10,13 @@ import (
type Relationship struct {
RelationshipId int `orm:"pk;auto;unique;column(relationship_id)" json:"relationship_id"`
- MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
- BookId int `orm:"column(book_id);type(int)" json:"book_id"`
+ MemberId int `orm:"column(member_id);type(int);description(作者id)" json:"member_id"`
+ BookId int `orm:"column(book_id);type(int);description(所属项目id)" json:"book_id"`
// RoleId 角色:0 创始人(创始人不能被移除) / 1 管理员/2 编辑者/3 观察者
- RoleId conf.BookRole `orm:"column(role_id);type(int)" json:"role_id"`
+ RoleId conf.BookRole `orm:"column(role_id);type(int);description(角色-配置文件里写死:0 创始人-不能被移除 / 1 管理员/2 编辑者/3 观察者)" json:"role_id"`
}
-// TableName 获取对应数据库表名.
+// TableName 获取对应数据库表名. 用户和项目的关联表
func (m *Relationship) TableName() string {
return "relationship"
}
diff --git a/models/Team.go b/models/Team.go
index c7226d761..a980376e9 100644
--- a/models/Team.go
+++ b/models/Team.go
@@ -12,10 +12,10 @@ import (
//团队.
type Team struct {
TeamId int `orm:"column(team_id);pk;auto;unique;" json:"team_id"`
- TeamName string `orm:"column(team_name);size(255)" json:"team_name"`
- MemberId int `orm:"column(member_id);type(int);" json:"member_id"`
- IsDelete bool `orm:"column(is_delete);default(0)" json:"is_delete"`
- CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
+ TeamName string `orm:"column(team_name);size(255);description(团队名称)" json:"team_name"`
+ MemberId int `orm:"column(member_id);type(int);description(创建人id)" json:"member_id"`
+ IsDelete bool `orm:"column(is_delete);default(false);description(是否删除 false:否 true:是)" json:"is_delete"`
+ CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add;description(创建时间)" json:"create_time"`
MemberCount int `orm:"-" json:"member_count"`
BookCount int `orm:"-" json:"book_count"`
MemberName string `orm:"-" json:"member_name"`
diff --git a/models/TeamMember.go b/models/TeamMember.go
index 4243638c7..acfe4a867 100644
--- a/models/TeamMember.go
+++ b/models/TeamMember.go
@@ -11,10 +11,10 @@ import (
type TeamMember struct {
TeamMemberId int `orm:"column(team_member_id);pk;auto;unique;" json:"team_member_id"`
- TeamId int `orm:"column(team_id);type(int)" json:"team_id"`
- MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
+ TeamId int `orm:"column(team_id);type(int);description(团队id)" json:"team_id"`
+ MemberId int `orm:"column(member_id);type(int);description(成员id)" json:"member_id"`
// RoleId 角色:0 创始人(创始人不能被移除) / 1 管理员/2 编辑者/3 观察者
- RoleId conf.BookRole `orm:"column(role_id);type(int)" json:"role_id"`
+ RoleId conf.BookRole `orm:"column(role_id);type(int);description(RoleId 角色:0 创始人-创始人不能被移除 / 1 管理员/2 编辑者/3 观察者)" json:"role_id"`
RoleName string `orm:"-" json:"role_name"`
Account string `orm:"-" json:"account"`
RealName string `orm:"-" json:"real_name"`
diff --git a/models/TeamRelationship.go b/models/TeamRelationship.go
index e6e82a7f4..90fd57884 100644
--- a/models/TeamRelationship.go
+++ b/models/TeamRelationship.go
@@ -11,9 +11,9 @@ import (
type TeamRelationship struct {
TeamRelationshipId int `orm:"column(team_relationship_id);pk;auto;unique;" json:"team_relationship_id"`
- BookId int `orm:"column(book_id)" json:"book_id"`
- TeamId int `orm:"column(team_id)" json:"team_id"`
- CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
+ BookId int `orm:"column(book_id);description(项目id)" json:"book_id"`
+ TeamId int `orm:"column(team_id);description(团队id)" json:"team_id"`
+ CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add;description(创建时间)" json:"create_time"`
TeamName string `orm:"-" json:"team_name"`
MemberCount int `orm:"-" json:"member_count"`
BookMemberId int `orm:"-" json:"book_member_id"`
diff --git a/models/WorkWeixinAccount.go b/models/WorkWeixinAccount.go
deleted file mode 100644
index 8e3b04ce6..000000000
--- a/models/WorkWeixinAccount.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Package models .
-package models
-
-import (
- "errors"
- "time"
-
- "github.com/beego/beego/v2/client/orm"
- "github.com/beego/beego/v2/core/logs"
- "github.com/mindoc-org/mindoc/conf"
-)
-
-type WorkWeixinAccount struct {
- MemberId int `orm:"column(member_id);type(int);default(-1);index" json:"member_id"`
- UserDbId int `orm:"pk;auto;unique;column(user_db_id)" json:"user_db_id"`
- WorkWeixin_UserId string `orm:"size(100);unique;column(workweixin_user_id)" json:"workweixin_user_id"`
- // WorkWeixin_Name string `orm:"size(255);column(workweixin_name)" json:"workweixin_name"`
- // WorkWeixin_Phone string `orm:"size(25);column(workweixin_phone)" json:"workweixin_phone"`
- // WorkWeixin_Email string `orm:"size(255);column(workweixin_email)" json:"workweixin_email"`
- // WorkWeixin_Status int `orm:"type(int);column(status)" json:"status"`
- // WorkWeixin_Avatar string `orm:"size(1024);column(avatar)" json:"avatar"`
- CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
- CreateAt int `orm:"type(int);column(create_at)" json:"create_at"`
- LastLoginTime time.Time `orm:"type(datetime);column(last_login_time);null" json:"last_login_time"`
-}
-
-// TableName 获取对应数据库表名.
-func (m *WorkWeixinAccount) TableName() string {
- return "workweixin_accounts"
-}
-
-// TableEngine 获取数据使用的引擎.
-func (m *WorkWeixinAccount) TableEngine() string {
- return "INNODB"
-}
-
-func (m *WorkWeixinAccount) TableNameWithPrefix() string {
- return conf.GetDatabasePrefix() + m.TableName()
-}
-
-func NewWorkWeixinAccount() *WorkWeixinAccount {
- return &WorkWeixinAccount{}
-}
-
-func (a *WorkWeixinAccount) ExistedMember(workweixin_user_id string) (*Member, error) {
- o := orm.NewOrm()
- account := NewWorkWeixinAccount()
- member := NewMember()
- err := o.QueryTable(a.TableNameWithPrefix()).Filter("workweixin_user_id", workweixin_user_id).One(account)
- if err == nil {
- if member, err = member.Find(account.MemberId); err == nil {
- return member, nil
- } else {
- return member, err
- }
- } else {
- return member, err
- }
-}
-
-// Add 添加一个用户.
-func (a *WorkWeixinAccount) AddBind(o orm.Ormer) error {
- if c, err := o.QueryTable(a.TableNameWithPrefix()).Filter("member_id", a.MemberId).Count(); err == nil && c > 0 {
- return errors.New("已绑定,不可重复绑定")
- }
-
- _, err := o.Insert(a)
- if err != nil {
- logs.Error("保存用户数据到数据时失败 =>", err)
- return errors.New("用户信息绑定失败, 数据库错误")
- }
-
- return nil
-}
diff --git a/routers/router.go b/routers/router.go
index f30c8593f..a69961806 100644
--- a/routers/router.go
+++ b/routers/router.go
@@ -123,12 +123,13 @@ func init() {
web.Router("/", &controllers.HomeController{}, "*:Index")
web.Router("/login", &controllers.AccountController{}, "*:Login")
- web.Router("/dingtalk_login", &controllers.AccountController{}, "*:DingTalkLogin")
- web.Router("/workweixin-login", &controllers.AccountController{}, "*:WorkWeixinLogin")
- web.Router("/workweixin-callback", &controllers.AccountController{}, "*:WorkWeixinLoginCallback")
- web.Router("/workweixin-bind", &controllers.AccountController{}, "*:WorkWeixinLoginBind")
- web.Router("/workweixin-ignore", &controllers.AccountController{}, "*:WorkWeixinLoginIgnore")
- web.Router("/qrlogin/:app", &controllers.AccountController{}, "*:QRLogin")
+ web.Router("/auth2/redirect/:app", &controllers.AccountController{}, "*:Auth2Redirect")
+ web.Router("/auth2/callback/:app", &controllers.AccountController{}, "*:Auth2Callback")
+ web.Router("/auth2/account/bind/:app", &controllers.AccountController{}, "*:Auth2BindAccount")
+ web.Router("/auth2/account/auto/:app", &controllers.AccountController{}, "*:Auth2AutoAccount")
+
+ //web.Router("/dingtalk_login", &controllers.AccountController{}, "*:DingTalkLogin")
+ //web.Router("/qrlogin/:app", &controllers.AccountController{}, "*:QRLogin")
web.Router("/logout", &controllers.AccountController{}, "*:Logout")
web.Router("/register", &controllers.AccountController{}, "*:Register")
web.Router("/find_password", &controllers.AccountController{}, "*:FindPassword")
diff --git a/start.sh b/start.sh
index 0a9533945..98b4fc7c0 100644
--- a/start.sh
+++ b/start.sh
@@ -1,36 +1,31 @@
#!/bin/bash
set -eux
+# 默认资源
+if [ ! -d "/mindoc/conf" ]; then mkdir -p "/mindoc/conf" ; fi
+if [[ -z "$(ls -A -- "/mindoc/conf")" ]] ; then cp -r "/mindoc/__default_assets__/conf" "/mindoc/" ; fi
+
+if [ ! -d "/mindoc/static" ]; then mkdir -p "/mindoc/static" ; fi
+if [[ -z "$(ls -A -- "/mindoc/static")" ]] ; then cp -r "/mindoc/__default_assets__/static" "/mindoc/" ; fi
+
+if [ ! -d "/mindoc/views" ]; then mkdir -p "/mindoc/views" ; fi
+if [[ -z "$(ls -A -- "/mindoc/views")" ]] ; then cp -r "/mindoc/__default_assets__/views" "/mindoc/" ; fi
+
+if [ ! -d "/mindoc/uploads" ]; then mkdir -p "/mindoc/uploads" ; fi
+if [[ -z "$(ls -A -- "/mindoc/uploads")" ]] ; then cp -r "/mindoc/__default_assets__/uploads" "/mindoc/" ; fi
+
+# 如果配置文件不存在就复制
+cp --no-clobber /mindoc/conf/app.conf.example /mindoc/conf/app.conf
+
# 数据库等初始化
/mindoc/mindoc_linux_amd64 install
-# 导出同步检查
-mkdir -p /mindoc-sync-host
-if ! [ -f "/mindoc-sync-host/sync.sh" ]; then
- # 同步方向: docker->HOST 或 HOST -> docker
- # echo "export MINDOC_SYNC=" >> /mindoc-sync-host/sync.sh # 不同步
- echo "export MINDOC_SYNC=docker2host" >> /mindoc-sync-host/sync.sh # 默认 docker->HOST
-
- # 同步内容
- # conf: 配置
- # database: sqlite方式数据库
- # runtime: 运行时数据(日志等)
- # static: 静态文件
- # uploads: 上传文件
- # views: 页面视图
- # echo "export SYNC_LIST='conf;database;runtime;static;uploads;views'" >> /mindoc-sync-host/sync.sh # 同步所有内容
- # echo "export SYNC_LIST=" >> /mindoc-sync-host/sync.sh # 不同步任何内容
- echo "export SYNC_LIST='conf;database;uploads'" >> /mindoc-sync-host/sync.sh # 同步conf、database、uploads
-
- # 同步操作(sync/copy/sync --dry-run 等,具体参考rclone文档,host2docker务必谨慎操作)
- # echo "export SYNC_ACTION=sync --dry-run" >> /mindoc-sync-host/sync.sh # 无操作且仅显示同步文件信息(--dry-run)
- echo "export SYNC_ACTION=sync" >> /mindoc-sync-host/sync.sh # 默认同步
-
- # 同步脚本
- echo "source /mindoc/sync_host.sh" >> /mindoc-sync-host/sync.sh
-fi
-# 同步操作
-source /mindoc-sync-host/sync.sh
-
# 运行
-/mindoc/mindoc_linux_amd64
\ No newline at end of file
+/mindoc/mindoc_linux_amd64
+
+# # Debug Dockerfile
+# while [ 1 ]
+# do
+# echo "log ..."
+# sleep 5s
+# done
\ No newline at end of file
diff --git a/static/cherry/addons/cherry-code-block-mermaid-plugin.d.ts b/static/cherry/addons/cherry-code-block-mermaid-plugin.d.ts
new file mode 100644
index 000000000..0c17a69ca
--- /dev/null
+++ b/static/cherry/addons/cherry-code-block-mermaid-plugin.d.ts
@@ -0,0 +1,31 @@
+export default class MermaidCodeEngine {
+ static TYPE: string;
+ static install(cherryOptions: any, ...args: any[]): void;
+ constructor(mermaidOptions?: {});
+ mermaidAPIRefs: any;
+ options: {
+ theme: string;
+ altFontFamily: string;
+ fontFamily: string;
+ themeCSS: string;
+ flowchart: {
+ useMaxWidth: boolean;
+ };
+ sequence: {
+ useMaxWidth: boolean;
+ };
+ startOnLoad: boolean;
+ logLevel: number;
+ };
+ dom: any;
+ mermaidCanvas: any;
+ mountMermaidCanvas($engine: any): void;
+ /**
+ * 转换svg为img,如果出错则直出svg
+ * @param {string} svgCode
+ * @param {string} graphId
+ * @returns {string}
+ */
+ convertMermaidSvgToImg(svgCode: string, graphId: string): string;
+ render(src: any, sign: any, $engine: any): boolean;
+}
diff --git a/static/cherry/addons/cherry-code-block-mermaid-plugin.js b/static/cherry/addons/cherry-code-block-mermaid-plugin.js
new file mode 100644
index 000000000..dc24e6b8e
--- /dev/null
+++ b/static/cherry/addons/cherry-code-block-mermaid-plugin.js
@@ -0,0 +1 @@
+!function(t,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(t=t||self).CherryCodeBlockMermaidPlugin=r()}(this,(function(){"use strict";var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function r(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function e(t,r){return t(r={exports:{}},r.exports),r.exports}var n,o,i=function(t){return t&&t.Math==Math&&t},a=i("object"==typeof globalThis&&globalThis)||i("object"==typeof window&&window)||i("object"==typeof self&&self)||i("object"==typeof t&&t)||function(){return this}()||Function("return this")(),u=function(t){try{return!!t()}catch(t){return!0}},c=!u((function(){var t=function(){}.bind();return"function"!=typeof t||t.hasOwnProperty("prototype")})),f=Function.prototype,s=f.apply,l=f.call,p="object"==typeof Reflect&&Reflect.apply||(c?l.bind(s):function(){return l.apply(s,arguments)}),v=Function.prototype,y=v.bind,d=v.call,h=c&&y.bind(d,d),b=c?function(t){return t&&h(t)}:function(t){return t&&function(){return d.apply(t,arguments)}},m=function(t){return"function"==typeof t},g=!u((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),w=Function.prototype.call,_=c?w.bind(w):function(){return w.apply(w,arguments)},O={}.propertyIsEnumerable,j=Object.getOwnPropertyDescriptor,S={f:j&&!O.call({1:2},1)?function(t){var r=j(this,t);return!!r&&r.enumerable}:O},P=function(t,r){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:r}},x=b({}.toString),A=b("".slice),T=function(t){return A(x(t),8,-1)},E=a.Object,F=b("".split),M=u((function(){return!E("z").propertyIsEnumerable(0)}))?function(t){return"String"==T(t)?F(t,""):E(t)}:E,I=a.TypeError,L=function(t){if(null==t)throw I("Can't call method on "+t);return t},C=function(t){return M(L(t))},k=function(t){return"object"==typeof t?null!==t:m(t)},R={},z=function(t){return m(t)?t:void 0},D=function(t,r){return arguments.length<2?z(R[t])||z(a[t]):R[t]&&R[t][r]||a[t]&&a[t][r]},B=b({}.isPrototypeOf),N=D("navigator","userAgent")||"",G=a.process,U=a.Deno,V=G&&G.versions||U&&U.version,$=V&&V.v8;$&&(o=(n=$.split("."))[0]>0&&n[0]<4?1:+(n[0]+n[1])),!o&&N&&(!(n=N.match(/Edge\/(\d+)/))||n[1]>=74)&&(n=N.match(/Chrome\/(\d+)/))&&(o=+n[1]);var W=o,q=!!Object.getOwnPropertySymbols&&!u((function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&W&&W<41})),H=q&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Y=a.Object,J=H?function(t){return"symbol"==typeof t}:function(t){var r=D("Symbol");return m(r)&&B(r.prototype,Y(t))},X=a.String,K=function(t){try{return X(t)}catch(t){return"Object"}},Q=a.TypeError,Z=function(t){if(m(t))return t;throw Q(K(t)+" is not a function")},tt=a.TypeError,rt=Object.defineProperty,et=a["__core-js_shared__"]||function(t,r){try{rt(a,t,{value:r,configurable:!0,writable:!0})}catch(e){a[t]=r}return r}("__core-js_shared__",{}),nt=e((function(t){(t.exports=function(t,r){return et[t]||(et[t]=void 0!==r?r:{})})("versions",[]).push({version:"3.22.6",mode:"pure",copyright:"© 2014-2022 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.22.6/LICENSE",source:"https://github.com/zloirock/core-js"})})),ot=a.Object,it=function(t){return ot(L(t))},at=b({}.hasOwnProperty),ut=Object.hasOwn||function(t,r){return at(it(t),r)},ct=0,ft=Math.random(),st=b(1..toString),lt=function(t){return"Symbol("+(void 0===t?"":t)+")_"+st(++ct+ft,36)},pt=nt("wks"),vt=a.Symbol,yt=vt&&vt.for,dt=H?vt:vt&&vt.withoutSetter||lt,ht=function(t){if(!ut(pt,t)||!q&&"string"!=typeof pt[t]){var r="Symbol."+t;q&&ut(vt,t)?pt[t]=vt[t]:pt[t]=H&&yt?yt(r):dt(r)}return pt[t]},bt=a.TypeError,mt=ht("toPrimitive"),gt=function(t,r){if(!k(t)||J(t))return t;var e,n,o=null==(e=t[mt])?void 0:Z(e);if(o){if(void 0===r&&(r="default"),n=_(o,t,r),!k(n)||J(n))return n;throw bt("Can't convert object to primitive value")}return void 0===r&&(r="number"),function(t,r){var e,n;if("string"===r&&m(e=t.toString)&&!k(n=_(e,t)))return n;if(m(e=t.valueOf)&&!k(n=_(e,t)))return n;if("string"!==r&&m(e=t.toString)&&!k(n=_(e,t)))return n;throw tt("Can't convert object to primitive value")}(t,r)},wt=function(t){var r=gt(t,"string");return J(r)?r:r+""},_t=a.document,Ot=k(_t)&&k(_t.createElement),jt=function(t){return Ot?_t.createElement(t):{}},St=!g&&!u((function(){return 7!=Object.defineProperty(jt("div"),"a",{get:function(){return 7}}).a})),Pt=Object.getOwnPropertyDescriptor,xt={f:g?Pt:function(t,r){if(t=C(t),r=wt(r),St)try{return Pt(t,r)}catch(t){}if(ut(t,r))return P(!_(S.f,t,r),t[r])}},At=/#|\.prototype\./,Tt=function(t,r){var e=Ft[Et(t)];return e==It||e!=Mt&&(m(r)?u(r):!!r)},Et=Tt.normalize=function(t){return String(t).replace(At,".").toLowerCase()},Ft=Tt.data={},Mt=Tt.NATIVE="N",It=Tt.POLYFILL="P",Lt=Tt,Ct=b(b.bind),kt=function(t,r){return Z(t),void 0===r?t:c?Ct(t,r):function(){return t.apply(r,arguments)}},Rt=g&&u((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype})),zt=a.String,Dt=a.TypeError,Bt=function(t){if(k(t))return t;throw Dt(zt(t)+" is not an object")},Nt=a.TypeError,Gt=Object.defineProperty,Ut=Object.getOwnPropertyDescriptor,Vt={f:g?Rt?function(t,r,e){if(Bt(t),r=wt(r),Bt(e),"function"==typeof t&&"prototype"===r&&"value"in e&&"writable"in e&&!e.writable){var n=Ut(t,r);n&&n.writable&&(t[r]=e.value,e={configurable:"configurable"in e?e.configurable:n.configurable,enumerable:"enumerable"in e?e.enumerable:n.enumerable,writable:!1})}return Gt(t,r,e)}:Gt:function(t,r,e){if(Bt(t),r=wt(r),Bt(e),St)try{return Gt(t,r,e)}catch(t){}if("get"in e||"set"in e)throw Nt("Accessors not supported");return"value"in e&&(t[r]=e.value),t}},$t=g?function(t,r,e){return Vt.f(t,r,P(1,e))}:function(t,r,e){return t[r]=e,t},Wt=xt.f,qt=function(t){var r=function(e,n,o){if(this instanceof r){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,n)}return new t(e,n,o)}return p(t,this,arguments)};return r.prototype=t.prototype,r},Ht=function(t,r){var e,n,o,i,u,c,f,s,l=t.target,p=t.global,v=t.stat,y=t.proto,d=p?a:v?a[l]:(a[l]||{}).prototype,h=p?R:R[l]||$t(R,l,{})[l],g=h.prototype;for(o in r)e=!Lt(p?o:l+(v?".":"#")+o,t.forced)&&d&&ut(d,o),u=h[o],e&&(c=t.dontCallGetSet?(s=Wt(d,o))&&s.value:d[o]),i=e&&c?c:r[o],e&&typeof u==typeof i||(f=t.bind&&e?kt(i,a):t.wrap&&e?qt(i):y&&m(i)?b(i):i,(t.sham||i&&i.sham||u&&u.sham)&&$t(f,"sham",!0),$t(h,o,f),y&&(ut(R,n=l+"Prototype")||$t(R,n,{}),$t(R[n],o,i),t.real&&g&&!g[o]&&$t(g,o,i)))},Yt=Math.ceil,Jt=Math.floor,Xt=Math.trunc||function(t){var r=+t;return(r>0?Jt:Yt)(r)},Kt=function(t){var r=+t;return r!=r||0===r?0:Xt(r)},Qt=Math.max,Zt=Math.min,tr=function(t,r){var e=Kt(t);return e<0?Qt(e+r,0):Zt(e,r)},rr=Math.min,er=function(t){return(r=t.length)>0?rr(Kt(r),9007199254740991):0;var r},nr=function(t){return function(r,e,n){var o,i=C(r),a=er(i),u=tr(n,a);if(t&&e!=e){for(;a>u;)if((o=i[u++])!=o)return!0}else for(;a>u;u++)if((t||u in i)&&i[u]===e)return t||u||0;return!t&&-1}},or={includes:nr(!0),indexOf:nr(!1)},ir={},ar=or.indexOf,ur=b([].push),cr=function(t,r){var e,n=C(t),o=0,i=[];for(e in n)!ut(ir,e)&&ut(n,e)&&ur(i,e);for(;r.length>o;)ut(n,e=r[o++])&&(~ar(i,e)||ur(i,e));return i},fr=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],sr=Object.keys||function(t){return cr(t,fr)},lr=u((function(){sr(1)}));Ht({target:"Object",stat:!0,forced:lr},{keys:function(t){return sr(it(t))}});var pr=R.Object.keys,vr={};vr[ht("toStringTag")]="z";var yr,dr="[object z]"===String(vr),hr=ht("toStringTag"),br=a.Object,mr="Arguments"==T(function(){return arguments}()),gr=dr?T:function(t){var r,e,n;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(e=function(t,r){try{return t[r]}catch(t){}}(r=br(t),hr))?e:mr?T(r):"Object"==(n=T(r))&&m(r.callee)?"Arguments":n},wr=a.String,_r=function(t){if("Symbol"===gr(t))throw TypeError("Cannot convert a Symbol value to a string");return wr(t)},Or={f:g&&!Rt?Object.defineProperties:function(t,r){Bt(t);for(var e,n=C(r),o=sr(r),i=o.length,a=0;i>a;)Vt.f(t,e=o[a++],n[e]);return t}},jr=D("document","documentElement"),Sr=nt("keys"),Pr=function(t){return Sr[t]||(Sr[t]=lt(t))},xr=Pr("IE_PROTO"),Ar=function(){},Tr=function(t){return"`.
+ this.sequenceIndex = Number(c === CharCodes.Lt);
+ }
+ }
+ stateCDATASequence(c) {
+ if (c === Sequences.Cdata[this.sequenceIndex]) {
+ if (++this.sequenceIndex === Sequences.Cdata.length) {
+ this.state = State$2.InCommentLike;
+ this.currentSequence = Sequences.CdataEnd;
+ this.sequenceIndex = 0;
+ this.sectionStart = this.index + 1;
+ }
+ }
+ else {
+ this.sequenceIndex = 0;
+ this.state = State$2.InDeclaration;
+ this.stateInDeclaration(c); // Reconsume the character
+ }
+ }
+ /**
+ * When we wait for one specific character, we can speed things up
+ * by skipping through the buffer until we find it.
+ *
+ * @returns Whether the character was found.
+ */
+ fastForwardTo(c) {
+ while (++this.index < this.buffer.length + this.offset) {
+ if (this.buffer.charCodeAt(this.index - this.offset) === c) {
+ return true;
+ }
+ }
+ /*
+ * We increment the index at the end of the `parse` loop,
+ * so set it to `buffer.length - 1` here.
+ *
+ * TODO: Refactor `parse` to increment index before calling states.
+ */
+ this.index = this.buffer.length + this.offset - 1;
+ return false;
+ }
+ /**
+ * Comments and CDATA end with `-->` and `]]>`.
+ *
+ * Their common qualities are:
+ * - Their end sequences have a distinct character they start with.
+ * - That character is then repeated, so we have to check multiple repeats.
+ * - All characters but the start character of the sequence can be skipped.
+ */
+ stateInCommentLike(c) {
+ if (c === this.currentSequence[this.sequenceIndex]) {
+ if (++this.sequenceIndex === this.currentSequence.length) {
+ if (this.currentSequence === Sequences.CdataEnd) {
+ this.cbs.oncdata(this.sectionStart, this.index, 2);
+ }
+ else {
+ this.cbs.oncomment(this.sectionStart, this.index, 2);
+ }
+ this.sequenceIndex = 0;
+ this.sectionStart = this.index + 1;
+ this.state = State$2.Text;
+ }
+ }
+ else if (this.sequenceIndex === 0) {
+ // Fast-forward to the first character of the sequence
+ if (this.fastForwardTo(this.currentSequence[0])) {
+ this.sequenceIndex = 1;
+ }
+ }
+ else if (c !== this.currentSequence[this.sequenceIndex - 1]) {
+ // Allow long sequences, eg. --->, ]]]>
+ this.sequenceIndex = 0;
+ }
+ }
+ /**
+ * HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a tag name.
+ *
+ * XML allows a lot more characters here (@see https://www.w3.org/TR/REC-xml/#NT-NameStartChar).
+ * We allow anything that wouldn't end the tag.
+ */
+ isTagStartChar(c) {
+ return this.xmlMode ? !isEndOfTagSection(c) : isASCIIAlpha(c);
+ }
+ startSpecial(sequence, offset) {
+ this.isSpecial = true;
+ this.currentSequence = sequence;
+ this.sequenceIndex = offset;
+ this.state = State$2.SpecialStartSequence;
+ }
+ stateBeforeTagName(c) {
+ if (c === CharCodes.ExclamationMark) {
+ this.state = State$2.BeforeDeclaration;
+ this.sectionStart = this.index + 1;
+ }
+ else if (c === CharCodes.Questionmark) {
+ this.state = State$2.InProcessingInstruction;
+ this.sectionStart = this.index + 1;
+ }
+ else if (this.isTagStartChar(c)) {
+ const lower = c | 0x20;
+ this.sectionStart = this.index;
+ if (!this.xmlMode && lower === Sequences.TitleEnd[2]) {
+ this.startSpecial(Sequences.TitleEnd, 3);
+ }
+ else {
+ this.state =
+ !this.xmlMode && lower === Sequences.ScriptEnd[2]
+ ? State$2.BeforeSpecialS
+ : State$2.InTagName;
+ }
+ }
+ else if (c === CharCodes.Slash) {
+ this.state = State$2.BeforeClosingTagName;
+ }
+ else {
+ this.state = State$2.Text;
+ this.stateText(c);
+ }
+ }
+ stateInTagName(c) {
+ if (isEndOfTagSection(c)) {
+ this.cbs.onopentagname(this.sectionStart, this.index);
+ this.sectionStart = -1;
+ this.state = State$2.BeforeAttributeName;
+ this.stateBeforeAttributeName(c);
+ }
+ }
+ stateBeforeClosingTagName(c) {
+ if (isWhitespace$2(c)) ;
+ else if (c === CharCodes.Gt) {
+ this.state = State$2.Text;
+ }
+ else {
+ this.state = this.isTagStartChar(c)
+ ? State$2.InClosingTagName
+ : State$2.InSpecialComment;
+ this.sectionStart = this.index;
+ }
+ }
+ stateInClosingTagName(c) {
+ if (c === CharCodes.Gt || isWhitespace$2(c)) {
+ this.cbs.onclosetag(this.sectionStart, this.index);
+ this.sectionStart = -1;
+ this.state = State$2.AfterClosingTagName;
+ this.stateAfterClosingTagName(c);
+ }
+ }
+ stateAfterClosingTagName(c) {
+ // Skip everything until ">"
+ if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
+ this.state = State$2.Text;
+ this.sectionStart = this.index + 1;
+ }
+ }
+ stateBeforeAttributeName(c) {
+ if (c === CharCodes.Gt) {
+ this.cbs.onopentagend(this.index);
+ if (this.isSpecial) {
+ this.state = State$2.InSpecialTag;
+ this.sequenceIndex = 0;
+ }
+ else {
+ this.state = State$2.Text;
+ }
+ this.baseState = this.state;
+ this.sectionStart = this.index + 1;
+ }
+ else if (c === CharCodes.Slash) {
+ this.state = State$2.InSelfClosingTag;
+ }
+ else if (!isWhitespace$2(c)) {
+ this.state = State$2.InAttributeName;
+ this.sectionStart = this.index;
+ }
+ }
+ stateInSelfClosingTag(c) {
+ if (c === CharCodes.Gt) {
+ this.cbs.onselfclosingtag(this.index);
+ this.state = State$2.Text;
+ this.baseState = State$2.Text;
+ this.sectionStart = this.index + 1;
+ this.isSpecial = false; // Reset special state, in case of self-closing special tags
+ }
+ else if (!isWhitespace$2(c)) {
+ this.state = State$2.BeforeAttributeName;
+ this.stateBeforeAttributeName(c);
+ }
+ }
+ stateInAttributeName(c) {
+ if (c === CharCodes.Eq || isEndOfTagSection(c)) {
+ this.cbs.onattribname(this.sectionStart, this.index);
+ this.sectionStart = -1;
+ this.state = State$2.AfterAttributeName;
+ this.stateAfterAttributeName(c);
+ }
+ }
+ stateAfterAttributeName(c) {
+ if (c === CharCodes.Eq) {
+ this.state = State$2.BeforeAttributeValue;
+ }
+ else if (c === CharCodes.Slash || c === CharCodes.Gt) {
+ this.cbs.onattribend(QuoteType.NoValue, this.index);
+ this.state = State$2.BeforeAttributeName;
+ this.stateBeforeAttributeName(c);
+ }
+ else if (!isWhitespace$2(c)) {
+ this.cbs.onattribend(QuoteType.NoValue, this.index);
+ this.state = State$2.InAttributeName;
+ this.sectionStart = this.index;
+ }
+ }
+ stateBeforeAttributeValue(c) {
+ if (c === CharCodes.DoubleQuote) {
+ this.state = State$2.InAttributeValueDq;
+ this.sectionStart = this.index + 1;
+ }
+ else if (c === CharCodes.SingleQuote) {
+ this.state = State$2.InAttributeValueSq;
+ this.sectionStart = this.index + 1;
+ }
+ else if (!isWhitespace$2(c)) {
+ this.sectionStart = this.index;
+ this.state = State$2.InAttributeValueNq;
+ this.stateInAttributeValueNoQuotes(c); // Reconsume token
+ }
+ }
+ handleInAttributeValue(c, quote) {
+ if (c === quote ||
+ (!this.decodeEntities && this.fastForwardTo(quote))) {
+ this.cbs.onattribdata(this.sectionStart, this.index);
+ this.sectionStart = -1;
+ this.cbs.onattribend(quote === CharCodes.DoubleQuote
+ ? QuoteType.Double
+ : QuoteType.Single, this.index);
+ this.state = State$2.BeforeAttributeName;
+ }
+ else if (this.decodeEntities && c === CharCodes.Amp) {
+ this.baseState = this.state;
+ this.state = State$2.BeforeEntity;
+ }
+ }
+ stateInAttributeValueDoubleQuotes(c) {
+ this.handleInAttributeValue(c, CharCodes.DoubleQuote);
+ }
+ stateInAttributeValueSingleQuotes(c) {
+ this.handleInAttributeValue(c, CharCodes.SingleQuote);
+ }
+ stateInAttributeValueNoQuotes(c) {
+ if (isWhitespace$2(c) || c === CharCodes.Gt) {
+ this.cbs.onattribdata(this.sectionStart, this.index);
+ this.sectionStart = -1;
+ this.cbs.onattribend(QuoteType.Unquoted, this.index);
+ this.state = State$2.BeforeAttributeName;
+ this.stateBeforeAttributeName(c);
+ }
+ else if (this.decodeEntities && c === CharCodes.Amp) {
+ this.baseState = this.state;
+ this.state = State$2.BeforeEntity;
+ }
+ }
+ stateBeforeDeclaration(c) {
+ if (c === CharCodes.OpeningSquareBracket) {
+ this.state = State$2.CDATASequence;
+ this.sequenceIndex = 0;
+ }
+ else {
+ this.state =
+ c === CharCodes.Dash
+ ? State$2.BeforeComment
+ : State$2.InDeclaration;
+ }
+ }
+ stateInDeclaration(c) {
+ if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
+ this.cbs.ondeclaration(this.sectionStart, this.index);
+ this.state = State$2.Text;
+ this.sectionStart = this.index + 1;
+ }
+ }
+ stateInProcessingInstruction(c) {
+ if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
+ this.cbs.onprocessinginstruction(this.sectionStart, this.index);
+ this.state = State$2.Text;
+ this.sectionStart = this.index + 1;
+ }
+ }
+ stateBeforeComment(c) {
+ if (c === CharCodes.Dash) {
+ this.state = State$2.InCommentLike;
+ this.currentSequence = Sequences.CommentEnd;
+ // Allow short comments (eg. )
+ this.sequenceIndex = 2;
+ this.sectionStart = this.index + 1;
+ }
+ else {
+ this.state = State$2.InDeclaration;
+ }
+ }
+ stateInSpecialComment(c) {
+ if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) {
+ this.cbs.oncomment(this.sectionStart, this.index, 0);
+ this.state = State$2.Text;
+ this.sectionStart = this.index + 1;
+ }
+ }
+ stateBeforeSpecialS(c) {
+ const lower = c | 0x20;
+ if (lower === Sequences.ScriptEnd[3]) {
+ this.startSpecial(Sequences.ScriptEnd, 4);
+ }
+ else if (lower === Sequences.StyleEnd[3]) {
+ this.startSpecial(Sequences.StyleEnd, 4);
+ }
+ else {
+ this.state = State$2.InTagName;
+ this.stateInTagName(c); // Consume the token again
+ }
+ }
+ stateBeforeEntity(c) {
+ // Start excess with 1 to include the '&'
+ this.entityExcess = 1;
+ this.entityResult = 0;
+ if (c === CharCodes.Num) {
+ this.state = State$2.BeforeNumericEntity;
+ }
+ else if (c === CharCodes.Amp) ;
+ else {
+ this.trieIndex = 0;
+ this.trieCurrent = this.entityTrie[0];
+ this.state = State$2.InNamedEntity;
+ this.stateInNamedEntity(c);
+ }
+ }
+ stateInNamedEntity(c) {
+ this.entityExcess += 1;
+ this.trieIndex = decode_4(this.entityTrie, this.trieCurrent, this.trieIndex + 1, c);
+ if (this.trieIndex < 0) {
+ this.emitNamedEntity();
+ this.index--;
+ return;
+ }
+ this.trieCurrent = this.entityTrie[this.trieIndex];
+ const masked = this.trieCurrent & decode_5.VALUE_LENGTH;
+ // If the branch is a value, store it and continue
+ if (masked) {
+ // The mask is the number of bytes of the value, including the current byte.
+ const valueLength = (masked >> 14) - 1;
+ // If we have a legacy entity while parsing strictly, just skip the number of bytes
+ if (!this.allowLegacyEntity() && c !== CharCodes.Semi) {
+ this.trieIndex += valueLength;
+ }
+ else {
+ // Add 1 as we have already incremented the excess
+ const entityStart = this.index - this.entityExcess + 1;
+ if (entityStart > this.sectionStart) {
+ this.emitPartial(this.sectionStart, entityStart);
+ }
+ // If this is a surrogate pair, consume the next two bytes
+ this.entityResult = this.trieIndex;
+ this.trieIndex += valueLength;
+ this.entityExcess = 0;
+ this.sectionStart = this.index + 1;
+ if (valueLength === 0) {
+ this.emitNamedEntity();
+ }
+ }
+ }
+ }
+ emitNamedEntity() {
+ this.state = this.baseState;
+ if (this.entityResult === 0) {
+ return;
+ }
+ const valueLength = (this.entityTrie[this.entityResult] & decode_5.VALUE_LENGTH) >>
+ 14;
+ switch (valueLength) {
+ case 1:
+ this.emitCodePoint(this.entityTrie[this.entityResult] &
+ ~decode_5.VALUE_LENGTH);
+ break;
+ case 2:
+ this.emitCodePoint(this.entityTrie[this.entityResult + 1]);
+ break;
+ case 3: {
+ this.emitCodePoint(this.entityTrie[this.entityResult + 1]);
+ this.emitCodePoint(this.entityTrie[this.entityResult + 2]);
+ }
+ }
+ }
+ stateBeforeNumericEntity(c) {
+ if ((c | 0x20) === CharCodes.LowerX) {
+ this.entityExcess++;
+ this.state = State$2.InHexEntity;
+ }
+ else {
+ this.state = State$2.InNumericEntity;
+ this.stateInNumericEntity(c);
+ }
+ }
+ emitNumericEntity(strict) {
+ const entityStart = this.index - this.entityExcess - 1;
+ const numberStart = entityStart + 2 + Number(this.state === State$2.InHexEntity);
+ if (numberStart !== this.index) {
+ // Emit leading data if any
+ if (entityStart > this.sectionStart) {
+ this.emitPartial(this.sectionStart, entityStart);
+ }
+ this.sectionStart = this.index + Number(strict);
+ this.emitCodePoint(decode_7(this.entityResult));
+ }
+ this.state = this.baseState;
+ }
+ stateInNumericEntity(c) {
+ if (c === CharCodes.Semi) {
+ this.emitNumericEntity(true);
+ }
+ else if (isNumber$1(c)) {
+ this.entityResult = this.entityResult * 10 + (c - CharCodes.Zero);
+ this.entityExcess++;
+ }
+ else {
+ if (this.allowLegacyEntity()) {
+ this.emitNumericEntity(false);
+ }
+ else {
+ this.state = this.baseState;
+ }
+ this.index--;
+ }
+ }
+ stateInHexEntity(c) {
+ if (c === CharCodes.Semi) {
+ this.emitNumericEntity(true);
+ }
+ else if (isNumber$1(c)) {
+ this.entityResult = this.entityResult * 16 + (c - CharCodes.Zero);
+ this.entityExcess++;
+ }
+ else if (isHexDigit(c)) {
+ this.entityResult =
+ this.entityResult * 16 + ((c | 0x20) - CharCodes.LowerA + 10);
+ this.entityExcess++;
+ }
+ else {
+ if (this.allowLegacyEntity()) {
+ this.emitNumericEntity(false);
+ }
+ else {
+ this.state = this.baseState;
+ }
+ this.index--;
+ }
+ }
+ allowLegacyEntity() {
+ return (!this.xmlMode &&
+ (this.baseState === State$2.Text ||
+ this.baseState === State$2.InSpecialTag));
+ }
+ /**
+ * Remove data that has already been consumed from the buffer.
+ */
+ cleanup() {
+ // If we are inside of text or attributes, emit what we already have.
+ if (this.running && this.sectionStart !== this.index) {
+ if (this.state === State$2.Text ||
+ (this.state === State$2.InSpecialTag && this.sequenceIndex === 0)) {
+ this.cbs.ontext(this.sectionStart, this.index);
+ this.sectionStart = this.index;
+ }
+ else if (this.state === State$2.InAttributeValueDq ||
+ this.state === State$2.InAttributeValueSq ||
+ this.state === State$2.InAttributeValueNq) {
+ this.cbs.onattribdata(this.sectionStart, this.index);
+ this.sectionStart = this.index;
+ }
+ }
+ }
+ shouldContinue() {
+ return this.index < this.buffer.length + this.offset && this.running;
+ }
+ /**
+ * Iterates through the buffer, calling the function corresponding to the current state.
+ *
+ * States that are more likely to be hit are higher up, as a performance improvement.
+ */
+ parse() {
+ while (this.shouldContinue()) {
+ const c = this.buffer.charCodeAt(this.index - this.offset);
+ if (this.state === State$2.Text) {
+ this.stateText(c);
+ }
+ else if (this.state === State$2.SpecialStartSequence) {
+ this.stateSpecialStartSequence(c);
+ }
+ else if (this.state === State$2.InSpecialTag) {
+ this.stateInSpecialTag(c);
+ }
+ else if (this.state === State$2.CDATASequence) {
+ this.stateCDATASequence(c);
+ }
+ else if (this.state === State$2.InAttributeValueDq) {
+ this.stateInAttributeValueDoubleQuotes(c);
+ }
+ else if (this.state === State$2.InAttributeName) {
+ this.stateInAttributeName(c);
+ }
+ else if (this.state === State$2.InCommentLike) {
+ this.stateInCommentLike(c);
+ }
+ else if (this.state === State$2.InSpecialComment) {
+ this.stateInSpecialComment(c);
+ }
+ else if (this.state === State$2.BeforeAttributeName) {
+ this.stateBeforeAttributeName(c);
+ }
+ else if (this.state === State$2.InTagName) {
+ this.stateInTagName(c);
+ }
+ else if (this.state === State$2.InClosingTagName) {
+ this.stateInClosingTagName(c);
+ }
+ else if (this.state === State$2.BeforeTagName) {
+ this.stateBeforeTagName(c);
+ }
+ else if (this.state === State$2.AfterAttributeName) {
+ this.stateAfterAttributeName(c);
+ }
+ else if (this.state === State$2.InAttributeValueSq) {
+ this.stateInAttributeValueSingleQuotes(c);
+ }
+ else if (this.state === State$2.BeforeAttributeValue) {
+ this.stateBeforeAttributeValue(c);
+ }
+ else if (this.state === State$2.BeforeClosingTagName) {
+ this.stateBeforeClosingTagName(c);
+ }
+ else if (this.state === State$2.AfterClosingTagName) {
+ this.stateAfterClosingTagName(c);
+ }
+ else if (this.state === State$2.BeforeSpecialS) {
+ this.stateBeforeSpecialS(c);
+ }
+ else if (this.state === State$2.InAttributeValueNq) {
+ this.stateInAttributeValueNoQuotes(c);
+ }
+ else if (this.state === State$2.InSelfClosingTag) {
+ this.stateInSelfClosingTag(c);
+ }
+ else if (this.state === State$2.InDeclaration) {
+ this.stateInDeclaration(c);
+ }
+ else if (this.state === State$2.BeforeDeclaration) {
+ this.stateBeforeDeclaration(c);
+ }
+ else if (this.state === State$2.BeforeComment) {
+ this.stateBeforeComment(c);
+ }
+ else if (this.state === State$2.InProcessingInstruction) {
+ this.stateInProcessingInstruction(c);
+ }
+ else if (this.state === State$2.InNamedEntity) {
+ this.stateInNamedEntity(c);
+ }
+ else if (this.state === State$2.BeforeEntity) {
+ this.stateBeforeEntity(c);
+ }
+ else if (this.state === State$2.InHexEntity) {
+ this.stateInHexEntity(c);
+ }
+ else if (this.state === State$2.InNumericEntity) {
+ this.stateInNumericEntity(c);
+ }
+ else {
+ // `this._state === State.BeforeNumericEntity`
+ this.stateBeforeNumericEntity(c);
+ }
+ this.index++;
+ }
+ this.cleanup();
+ }
+ finish() {
+ if (this.state === State$2.InNamedEntity) {
+ this.emitNamedEntity();
+ }
+ // If there is remaining data, emit it in a reasonable way
+ if (this.sectionStart < this.index) {
+ this.handleTrailingData();
+ }
+ this.cbs.onend();
+ }
+ /** Handle any trailing data. */
+ handleTrailingData() {
+ const endIndex = this.buffer.length + this.offset;
+ if (this.state === State$2.InCommentLike) {
+ if (this.currentSequence === Sequences.CdataEnd) {
+ this.cbs.oncdata(this.sectionStart, endIndex, 0);
+ }
+ else {
+ this.cbs.oncomment(this.sectionStart, endIndex, 0);
+ }
+ }
+ else if (this.state === State$2.InNumericEntity &&
+ this.allowLegacyEntity()) {
+ this.emitNumericEntity(false);
+ // All trailing data will have been consumed
+ }
+ else if (this.state === State$2.InHexEntity &&
+ this.allowLegacyEntity()) {
+ this.emitNumericEntity(false);
+ // All trailing data will have been consumed
+ }
+ else if (this.state === State$2.InTagName ||
+ this.state === State$2.BeforeAttributeName ||
+ this.state === State$2.BeforeAttributeValue ||
+ this.state === State$2.AfterAttributeName ||
+ this.state === State$2.InAttributeName ||
+ this.state === State$2.InAttributeValueSq ||
+ this.state === State$2.InAttributeValueDq ||
+ this.state === State$2.InAttributeValueNq ||
+ this.state === State$2.InClosingTagName) ;
+ else {
+ this.cbs.ontext(this.sectionStart, endIndex);
+ }
+ }
+ emitPartial(start, endIndex) {
+ if (this.baseState !== State$2.Text &&
+ this.baseState !== State$2.InSpecialTag) {
+ this.cbs.onattribdata(start, endIndex);
+ }
+ else {
+ this.cbs.ontext(start, endIndex);
+ }
+ }
+ emitCodePoint(cp) {
+ if (this.baseState !== State$2.Text &&
+ this.baseState !== State$2.InSpecialTag) {
+ this.cbs.onattribentity(cp);
+ }
+ else {
+ this.cbs.ontextentity(cp);
+ }
+ }
+ }
+
+ const formTags = new Set([
+ "input",
+ "option",
+ "optgroup",
+ "select",
+ "button",
+ "datalist",
+ "textarea",
+ ]);
+ const pTag = new Set(["p"]);
+ const tableSectionTags = new Set(["thead", "tbody"]);
+ const ddtTags = new Set(["dd", "dt"]);
+ const rtpTags = new Set(["rt", "rp"]);
+ const openImpliesClose = new Map([
+ ["tr", new Set(["tr", "th", "td"])],
+ ["th", new Set(["th"])],
+ ["td", new Set(["thead", "th", "td"])],
+ ["body", new Set(["head", "link", "script"])],
+ ["li", new Set(["li"])],
+ ["p", pTag],
+ ["h1", pTag],
+ ["h2", pTag],
+ ["h3", pTag],
+ ["h4", pTag],
+ ["h5", pTag],
+ ["h6", pTag],
+ ["select", formTags],
+ ["input", formTags],
+ ["output", formTags],
+ ["button", formTags],
+ ["datalist", formTags],
+ ["textarea", formTags],
+ ["option", new Set(["option"])],
+ ["optgroup", new Set(["optgroup", "option"])],
+ ["dd", ddtTags],
+ ["dt", ddtTags],
+ ["address", pTag],
+ ["article", pTag],
+ ["aside", pTag],
+ ["blockquote", pTag],
+ ["details", pTag],
+ ["div", pTag],
+ ["dl", pTag],
+ ["fieldset", pTag],
+ ["figcaption", pTag],
+ ["figure", pTag],
+ ["footer", pTag],
+ ["form", pTag],
+ ["header", pTag],
+ ["hr", pTag],
+ ["main", pTag],
+ ["nav", pTag],
+ ["ol", pTag],
+ ["pre", pTag],
+ ["section", pTag],
+ ["table", pTag],
+ ["ul", pTag],
+ ["rt", rtpTags],
+ ["rp", rtpTags],
+ ["tbody", tableSectionTags],
+ ["tfoot", tableSectionTags],
+ ]);
+ const voidElements = new Set([
+ "area",
+ "base",
+ "basefont",
+ "br",
+ "col",
+ "command",
+ "embed",
+ "frame",
+ "hr",
+ "img",
+ "input",
+ "isindex",
+ "keygen",
+ "link",
+ "meta",
+ "param",
+ "source",
+ "track",
+ "wbr",
+ ]);
+ const foreignContextElements = new Set(["math", "svg"]);
+ const htmlIntegrationElements = new Set([
+ "mi",
+ "mo",
+ "mn",
+ "ms",
+ "mtext",
+ "annotation-xml",
+ "foreignobject",
+ "desc",
+ "title",
+ ]);
+ const reNameEnd = /\s|\//;
+ class Parser$1 {
+ constructor(cbs, options = {}) {
+ var _a, _b, _c, _d, _e;
+ this.options = options;
+ /** The start index of the last event. */
+ this.startIndex = 0;
+ /** The end index of the last event. */
+ this.endIndex = 0;
+ /**
+ * Store the start index of the current open tag,
+ * so we can update the start index for attributes.
+ */
+ this.openTagStart = 0;
+ this.tagname = "";
+ this.attribname = "";
+ this.attribvalue = "";
+ this.attribs = null;
+ this.stack = [];
+ this.foreignContext = [];
+ this.buffers = [];
+ this.bufferOffset = 0;
+ /** The index of the last written buffer. Used when resuming after a `pause()`. */
+ this.writeIndex = 0;
+ /** Indicates whether the parser has finished running / `.end` has been called. */
+ this.ended = false;
+ this.cbs = cbs !== null && cbs !== void 0 ? cbs : {};
+ this.lowerCaseTagNames = (_a = options.lowerCaseTags) !== null && _a !== void 0 ? _a : !options.xmlMode;
+ this.lowerCaseAttributeNames =
+ (_b = options.lowerCaseAttributeNames) !== null && _b !== void 0 ? _b : !options.xmlMode;
+ this.tokenizer = new ((_c = options.Tokenizer) !== null && _c !== void 0 ? _c : Tokenizer$1)(this.options, this);
+ (_e = (_d = this.cbs).onparserinit) === null || _e === void 0 ? void 0 : _e.call(_d, this);
+ }
+ // Tokenizer event handlers
+ /** @internal */
+ ontext(start, endIndex) {
+ var _a, _b;
+ const data = this.getSlice(start, endIndex);
+ this.endIndex = endIndex - 1;
+ (_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, data);
+ this.startIndex = endIndex;
+ }
+ /** @internal */
+ ontextentity(cp) {
+ var _a, _b;
+ /*
+ * Entities can be emitted on the character, or directly after.
+ * We use the section start here to get accurate indices.
+ */
+ const idx = this.tokenizer.getSectionStart();
+ this.endIndex = idx - 1;
+ (_b = (_a = this.cbs).ontext) === null || _b === void 0 ? void 0 : _b.call(_a, decode_6(cp));
+ this.startIndex = idx;
+ }
+ isVoidElement(name) {
+ return !this.options.xmlMode && voidElements.has(name);
+ }
+ /** @internal */
+ onopentagname(start, endIndex) {
+ this.endIndex = endIndex;
+ let name = this.getSlice(start, endIndex);
+ if (this.lowerCaseTagNames) {
+ name = name.toLowerCase();
+ }
+ this.emitOpenTag(name);
+ }
+ emitOpenTag(name) {
+ var _a, _b, _c, _d;
+ this.openTagStart = this.startIndex;
+ this.tagname = name;
+ const impliesClose = !this.options.xmlMode && openImpliesClose.get(name);
+ if (impliesClose) {
+ while (this.stack.length > 0 &&
+ impliesClose.has(this.stack[this.stack.length - 1])) {
+ const el = this.stack.pop();
+ (_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, el, true);
+ }
+ }
+ if (!this.isVoidElement(name)) {
+ this.stack.push(name);
+ if (foreignContextElements.has(name)) {
+ this.foreignContext.push(true);
+ }
+ else if (htmlIntegrationElements.has(name)) {
+ this.foreignContext.push(false);
+ }
+ }
+ (_d = (_c = this.cbs).onopentagname) === null || _d === void 0 ? void 0 : _d.call(_c, name);
+ if (this.cbs.onopentag)
+ this.attribs = {};
+ }
+ endOpenTag(isImplied) {
+ var _a, _b;
+ this.startIndex = this.openTagStart;
+ if (this.attribs) {
+ (_b = (_a = this.cbs).onopentag) === null || _b === void 0 ? void 0 : _b.call(_a, this.tagname, this.attribs, isImplied);
+ this.attribs = null;
+ }
+ if (this.cbs.onclosetag && this.isVoidElement(this.tagname)) {
+ this.cbs.onclosetag(this.tagname, true);
+ }
+ this.tagname = "";
+ }
+ /** @internal */
+ onopentagend(endIndex) {
+ this.endIndex = endIndex;
+ this.endOpenTag(false);
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ /** @internal */
+ onclosetag(start, endIndex) {
+ var _a, _b, _c, _d, _e, _f;
+ this.endIndex = endIndex;
+ let name = this.getSlice(start, endIndex);
+ if (this.lowerCaseTagNames) {
+ name = name.toLowerCase();
+ }
+ if (foreignContextElements.has(name) ||
+ htmlIntegrationElements.has(name)) {
+ this.foreignContext.pop();
+ }
+ if (!this.isVoidElement(name)) {
+ const pos = this.stack.lastIndexOf(name);
+ if (pos !== -1) {
+ if (this.cbs.onclosetag) {
+ let count = this.stack.length - pos;
+ while (count--) {
+ // We know the stack has sufficient elements.
+ this.cbs.onclosetag(this.stack.pop(), count !== 0);
+ }
+ }
+ else
+ this.stack.length = pos;
+ }
+ else if (!this.options.xmlMode && name === "p") {
+ // Implicit open before close
+ this.emitOpenTag("p");
+ this.closeCurrentTag(true);
+ }
+ }
+ else if (!this.options.xmlMode && name === "br") {
+ // We can't use `emitOpenTag` for implicit open, as `br` would be implicitly closed.
+ (_b = (_a = this.cbs).onopentagname) === null || _b === void 0 ? void 0 : _b.call(_a, "br");
+ (_d = (_c = this.cbs).onopentag) === null || _d === void 0 ? void 0 : _d.call(_c, "br", {}, true);
+ (_f = (_e = this.cbs).onclosetag) === null || _f === void 0 ? void 0 : _f.call(_e, "br", false);
+ }
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ /** @internal */
+ onselfclosingtag(endIndex) {
+ this.endIndex = endIndex;
+ if (this.options.xmlMode ||
+ this.options.recognizeSelfClosing ||
+ this.foreignContext[this.foreignContext.length - 1]) {
+ this.closeCurrentTag(false);
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ else {
+ // Ignore the fact that the tag is self-closing.
+ this.onopentagend(endIndex);
+ }
+ }
+ closeCurrentTag(isOpenImplied) {
+ var _a, _b;
+ const name = this.tagname;
+ this.endOpenTag(isOpenImplied);
+ // Self-closing tags will be on the top of the stack
+ if (this.stack[this.stack.length - 1] === name) {
+ // If the opening tag isn't implied, the closing tag has to be implied.
+ (_b = (_a = this.cbs).onclosetag) === null || _b === void 0 ? void 0 : _b.call(_a, name, !isOpenImplied);
+ this.stack.pop();
+ }
+ }
+ /** @internal */
+ onattribname(start, endIndex) {
+ this.startIndex = start;
+ const name = this.getSlice(start, endIndex);
+ this.attribname = this.lowerCaseAttributeNames
+ ? name.toLowerCase()
+ : name;
+ }
+ /** @internal */
+ onattribdata(start, endIndex) {
+ this.attribvalue += this.getSlice(start, endIndex);
+ }
+ /** @internal */
+ onattribentity(cp) {
+ this.attribvalue += decode_6(cp);
+ }
+ /** @internal */
+ onattribend(quote, endIndex) {
+ var _a, _b;
+ this.endIndex = endIndex;
+ (_b = (_a = this.cbs).onattribute) === null || _b === void 0 ? void 0 : _b.call(_a, this.attribname, this.attribvalue, quote === QuoteType.Double
+ ? '"'
+ : quote === QuoteType.Single
+ ? "'"
+ : quote === QuoteType.NoValue
+ ? undefined
+ : null);
+ if (this.attribs &&
+ !Object.prototype.hasOwnProperty.call(this.attribs, this.attribname)) {
+ this.attribs[this.attribname] = this.attribvalue;
+ }
+ this.attribvalue = "";
+ }
+ getInstructionName(value) {
+ const idx = value.search(reNameEnd);
+ let name = idx < 0 ? value : value.substr(0, idx);
+ if (this.lowerCaseTagNames) {
+ name = name.toLowerCase();
+ }
+ return name;
+ }
+ /** @internal */
+ ondeclaration(start, endIndex) {
+ this.endIndex = endIndex;
+ const value = this.getSlice(start, endIndex);
+ if (this.cbs.onprocessinginstruction) {
+ const name = this.getInstructionName(value);
+ this.cbs.onprocessinginstruction(`!${name}`, `!${value}`);
+ }
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ /** @internal */
+ onprocessinginstruction(start, endIndex) {
+ this.endIndex = endIndex;
+ const value = this.getSlice(start, endIndex);
+ if (this.cbs.onprocessinginstruction) {
+ const name = this.getInstructionName(value);
+ this.cbs.onprocessinginstruction(`?${name}`, `?${value}`);
+ }
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ /** @internal */
+ oncomment(start, endIndex, offset) {
+ var _a, _b, _c, _d;
+ this.endIndex = endIndex;
+ (_b = (_a = this.cbs).oncomment) === null || _b === void 0 ? void 0 : _b.call(_a, this.getSlice(start, endIndex - offset));
+ (_d = (_c = this.cbs).oncommentend) === null || _d === void 0 ? void 0 : _d.call(_c);
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ /** @internal */
+ oncdata(start, endIndex, offset) {
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
+ this.endIndex = endIndex;
+ const value = this.getSlice(start, endIndex - offset);
+ if (this.options.xmlMode || this.options.recognizeCDATA) {
+ (_b = (_a = this.cbs).oncdatastart) === null || _b === void 0 ? void 0 : _b.call(_a);
+ (_d = (_c = this.cbs).ontext) === null || _d === void 0 ? void 0 : _d.call(_c, value);
+ (_f = (_e = this.cbs).oncdataend) === null || _f === void 0 ? void 0 : _f.call(_e);
+ }
+ else {
+ (_h = (_g = this.cbs).oncomment) === null || _h === void 0 ? void 0 : _h.call(_g, `[CDATA[${value}]]`);
+ (_k = (_j = this.cbs).oncommentend) === null || _k === void 0 ? void 0 : _k.call(_j);
+ }
+ // Set `startIndex` for next node
+ this.startIndex = endIndex + 1;
+ }
+ /** @internal */
+ onend() {
+ var _a, _b;
+ if (this.cbs.onclosetag) {
+ // Set the end index for all remaining tags
+ this.endIndex = this.startIndex;
+ for (let i = this.stack.length; i > 0; this.cbs.onclosetag(this.stack[--i], true))
+ ;
+ }
+ (_b = (_a = this.cbs).onend) === null || _b === void 0 ? void 0 : _b.call(_a);
+ }
+ /**
+ * Resets the parser to a blank state, ready to parse a new HTML document
+ */
+ reset() {
+ var _a, _b, _c, _d;
+ (_b = (_a = this.cbs).onreset) === null || _b === void 0 ? void 0 : _b.call(_a);
+ this.tokenizer.reset();
+ this.tagname = "";
+ this.attribname = "";
+ this.attribs = null;
+ this.stack.length = 0;
+ this.startIndex = 0;
+ this.endIndex = 0;
+ (_d = (_c = this.cbs).onparserinit) === null || _d === void 0 ? void 0 : _d.call(_c, this);
+ this.buffers.length = 0;
+ this.bufferOffset = 0;
+ this.writeIndex = 0;
+ this.ended = false;
+ }
+ /**
+ * Resets the parser, then parses a complete document and
+ * pushes it to the handler.
+ *
+ * @param data Document to parse.
+ */
+ parseComplete(data) {
+ this.reset();
+ this.end(data);
+ }
+ getSlice(start, end) {
+ while (start - this.bufferOffset >= this.buffers[0].length) {
+ this.shiftBuffer();
+ }
+ let str = this.buffers[0].slice(start - this.bufferOffset, end - this.bufferOffset);
+ while (end - this.bufferOffset > this.buffers[0].length) {
+ this.shiftBuffer();
+ str += this.buffers[0].slice(0, end - this.bufferOffset);
+ }
+ return str;
+ }
+ shiftBuffer() {
+ this.bufferOffset += this.buffers[0].length;
+ this.writeIndex--;
+ this.buffers.shift();
+ }
+ /**
+ * Parses a chunk of data and calls the corresponding callbacks.
+ *
+ * @param chunk Chunk to parse.
+ */
+ write(chunk) {
+ var _a, _b;
+ if (this.ended) {
+ (_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, new Error(".write() after done!"));
+ return;
+ }
+ this.buffers.push(chunk);
+ if (this.tokenizer.running) {
+ this.tokenizer.write(chunk);
+ this.writeIndex++;
+ }
+ }
+ /**
+ * Parses the end of the buffer and clears the stack, calls onend.
+ *
+ * @param chunk Optional final chunk to parse.
+ */
+ end(chunk) {
+ var _a, _b;
+ if (this.ended) {
+ (_b = (_a = this.cbs).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, Error(".end() after done!"));
+ return;
+ }
+ if (chunk)
+ this.write(chunk);
+ this.ended = true;
+ this.tokenizer.end();
+ }
+ /**
+ * Pauses parsing. The parser won't emit events until `resume` is called.
+ */
+ pause() {
+ this.tokenizer.pause();
+ }
+ /**
+ * Resumes parsing after `pause` was called.
+ */
+ resume() {
+ this.tokenizer.resume();
+ while (this.tokenizer.running &&
+ this.writeIndex < this.buffers.length) {
+ this.tokenizer.write(this.buffers[this.writeIndex++]);
+ }
+ if (this.ended)
+ this.tokenizer.end();
+ }
+ /**
+ * Alias of `write`, for backwards compatibility.
+ *
+ * @param chunk Chunk to parse.
+ * @deprecated
+ */
+ parseChunk(chunk) {
+ this.write(chunk);
+ }
+ /**
+ * Alias of `end`, for backwards compatibility.
+ *
+ * @param chunk Optional final chunk to parse.
+ * @deprecated
+ */
+ done(chunk) {
+ this.end(chunk);
+ }
+ }
+
+ // Helper methods
+ /**
+ * Parses the data, returns the resulting document.
+ *
+ * @param data The data that should be parsed.
+ * @param options Optional options for the parser and DOM builder.
+ */
+ function parseDocument(data, options) {
+ const handler = new DomHandler(undefined, options);
+ new Parser$1(handler, options).end(data);
+ return handler.root;
+ }
+
+ /**
+ * Types used in signatures of Cheerio methods.
+ *
+ * @category Cheerio
+ */
+ const parse$4 = getParse((content, options, isDocument, context) => options.xmlMode || options._useHtmlParser2
+ ? parseDocument(content, options)
+ : parseWithParse5(content, options, isDocument, context));
+ // Duplicate docs due to https://github.com/TypeStrong/typedoc/issues/1616
+ /**
+ * Create a querying function, bound to a document created from the provided markup.
+ *
+ * Note that similar to web browser contexts, this operation may introduce
+ * ``, ``, and `` elements; set `isDocument` to `false` to
+ * switch to fragment mode and disable this.
+ *
+ * @param content - Markup to be loaded.
+ * @param options - Options for the created instance.
+ * @param isDocument - Allows parser to be switched to fragment mode.
+ * @returns The loaded document.
+ * @see {@link https://cheerio.js.org#loading} for additional usage information.
+ */
+ const load = getLoad(parse$4, (dom, options) => options.xmlMode || options._useHtmlParser2
+ ? render(dom, options)
+ : renderWithParse5(dom));
+ /**
+ * The default cheerio instance.
+ *
+ * @deprecated Use the function returned by `load` instead.
+ */
+ var cheerio = load([]);
+
+ var debug_1 = createCommonjsModule(function (module, exports) {
+ exports = module.exports = debug;
+
+ function debug(label) {
+ return _debug.bind(null, label);
+ }
+
+ function _debug(label) {
+ var args = [].slice.call(arguments, 1);
+ args.unshift('[' + label + ']');
+ process.stderr.write(args.join(' ') + '\n');
+ }
+ });
+
+ var lexer = createCommonjsModule(function (module, exports) {
+
+ var debug = debug_1('lex');
+
+ exports = module.exports = lex;
+
+ /**
+ * Convert a CSS string into an array of lexical tokens.
+ *
+ * @param {String} css CSS
+ * @returns {Array} lexical tokens
+ */
+ function lex(css) {
+
+ var buffer = ''; // Character accumulator
+ var ch; // Current character
+ var column = 0; // Current source column number
+ var cursor = -1; // Current source cursor position
+ var depth = 0; // Current nesting depth
+ var line = 1; // Current source line number
+ var state = 'before-selector'; // Current state
+ var stack = [state]; // State stack
+ var token = {}; // Current token
+ var tokens = []; // Token accumulator
+
+ // Supported @-rules, in roughly descending order of usage probability.
+ var atRules = [
+ 'media',
+ 'keyframes',
+ { name: '-webkit-keyframes', type: 'keyframes', prefix: '-webkit-' },
+ { name: '-moz-keyframes', type: 'keyframes', prefix: '-moz-' },
+ { name: '-ms-keyframes', type: 'keyframes', prefix: '-ms-' },
+ { name: '-o-keyframes', type: 'keyframes', prefix: '-o-' },
+ 'font-face',
+ { name: 'import', state: 'before-at-value' },
+ { name: 'charset', state: 'before-at-value' },
+ 'supports',
+ 'viewport',
+ { name: 'namespace', state: 'before-at-value' },
+ 'document',
+ { name: '-moz-document', type: 'document', prefix: '-moz-' },
+ 'page'
+ ];
+
+ // -- Functions ------------------------------------------------------------
+
+ /**
+ * Advance the character cursor and return the next character.
+ *
+ * @returns {String} The next character.
+ */
+ function getCh() {
+ skip();
+ return css[cursor];
+ }
+
+ /**
+ * Return the state at the given index in the stack.
+ * The stack is LIFO so indexing is from the right.
+ *
+ * @param {Number} [index=0] Index to return.
+ * @returns {String} state
+ */
+ function getState(index) {
+ return index ? stack[stack.length - 1 - index] : state;
+ }
+
+ /**
+ * Look ahead for a string beginning from the next position. The string
+ * being looked for must start at the next position.
+ *
+ * @param {String} str The string to look for.
+ * @returns {Boolean} Whether the string was found.
+ */
+ function isNextString(str) {
+ var start = cursor + 1;
+ return (str === css.slice(start, start + str.length));
+ }
+
+ /**
+ * Find the start position of a substring beginning from the next
+ * position. The string being looked for may begin anywhere.
+ *
+ * @param {String} str The substring to look for.
+ * @returns {Number|false} The position, or `false` if not found.
+ */
+ function find(str) {
+ var pos = css.slice(cursor).indexOf(str);
+
+ return pos > 0 ? pos : false;
+ }
+
+ /**
+ * Determine whether a character is next.
+ *
+ * @param {String} ch Character.
+ * @returns {Boolean} Whether the character is next.
+ */
+ function isNextChar(ch) {
+ return ch === peek(1);
+ }
+
+ /**
+ * Return the character at the given cursor offset. The offset is relative
+ * to the cursor, so negative values move backwards.
+ *
+ * @param {Number} [offset=1] Cursor offset.
+ * @returns {String} Character.
+ */
+ function peek(offset) {
+ return css[cursor + (offset || 1)];
+ }
+
+ /**
+ * Remove the current state from the stack and set the new current state.
+ *
+ * @returns {String} The removed state.
+ */
+ function popState() {
+ var removed = stack.pop();
+ state = stack[stack.length - 1];
+
+ return removed;
+ }
+
+ /**
+ * Set the current state and add it to the stack.
+ *
+ * @param {String} newState The new state.
+ * @returns {Number} The new stack length.
+ */
+ function pushState(newState) {
+ state = newState;
+ stack.push(state);
+
+ return stack.length;
+ }
+
+ /**
+ * Replace the current state with a new state.
+ *
+ * @param {String} newState The new state.
+ * @returns {String} The replaced state.
+ */
+ function replaceState(newState) {
+ var previousState = state;
+ stack[stack.length - 1] = state = newState;
+
+ return previousState;
+ }
+
+ /**
+ * Move the character cursor. Positive numbers move the cursor forward.
+ * Negative numbers are not supported!
+ *
+ * @param {Number} [n=1] Number of characters to skip.
+ */
+ function skip(n) {
+ if ((n || 1) == 1) {
+ if (css[cursor] == '\n') {
+ line++;
+ column = 1;
+ } else {
+ column++;
+ }
+ cursor++;
+ } else {
+ var skipStr = css.slice(cursor, cursor + n).split('\n');
+ if (skipStr.length > 1) {
+ line += skipStr.length - 1;
+ column = 1;
+ }
+ column += skipStr[skipStr.length - 1].length;
+ cursor = cursor + n;
+ }
+ }
+
+ /**
+ * Add the current token to the pile and reset the buffer.
+ */
+ function addToken() {
+ token.end = {
+ line: line,
+ col: column
+ };
+
+ tokens.push(token);
+
+ buffer = '';
+ token = {};
+ }
+
+ /**
+ * Set the current token.
+ *
+ * @param {String} type Token type.
+ */
+ function initializeToken(type) {
+ token = {
+ type: type,
+ start: {
+ line: line,
+ col : column
+ }
+ };
+ }
+
+ while (ch = getCh()) {
+
+ // column += 1;
+
+ switch (ch) {
+ // Space
+ case ' ':
+ switch (getState()) {
+ case 'selector':
+ case 'value':
+ case 'value-paren':
+ case 'at-group':
+ case 'at-value':
+ case 'comment':
+ case 'double-string':
+ case 'single-string':
+ buffer += ch;
+ break;
+ }
+ break;
+
+ // Newline or tab
+ case '\n':
+ case '\t':
+ case '\r':
+ case '\f':
+ switch (getState()) {
+ case 'value':
+ case 'value-paren':
+ case 'at-group':
+ case 'comment':
+ case 'single-string':
+ case 'double-string':
+ case 'selector':
+ buffer += ch;
+ break;
+
+ case 'at-value':
+ // Tokenize an @-rule if a semi-colon was omitted.
+ if ('\n' === ch) {
+ token.value = buffer.trim();
+ addToken();
+ popState();
+ }
+ break;
+ }
+
+ // if ('\n' === ch) {
+ // column = 0;
+ // line += 1;
+ // }
+ break;
+
+ case ':':
+ switch (getState()) {
+ case 'name':
+ token.name = buffer.trim();
+ buffer = '';
+
+ replaceState('before-value');
+ break;
+
+ case 'before-selector':
+ buffer += ch;
+
+ initializeToken('selector');
+ pushState('selector');
+ break;
+
+ case 'before-value':
+ replaceState('value');
+ buffer += ch;
+ break;
+
+ default:
+ buffer += ch;
+ break;
+ }
+ break;
+
+ case ';':
+ switch (getState()) {
+ case 'name':
+ case 'before-value':
+ case 'value':
+ // Tokenize a declaration
+ // if value is empty skip the declaration
+ if (buffer.trim().length > 0) {
+ token.value = buffer.trim(),
+ addToken();
+ }
+ replaceState('before-name');
+ break;
+
+ case 'value-paren':
+ // Insignificant semi-colon
+ buffer += ch;
+ break;
+
+ case 'at-value':
+ // Tokenize an @-rule
+ token.value = buffer.trim();
+ addToken();
+ popState();
+ break;
+
+ case 'before-name':
+ // Extraneous semi-colon
+ break;
+
+ default:
+ buffer += ch;
+ break;
+ }
+ break;
+
+ case '{':
+ switch (getState()) {
+ case 'selector':
+ // If the sequence is `\{` then assume that the brace should be escaped.
+ if (peek(-1) === '\\') {
+ buffer += ch;
+ break;
+ }
+
+ // Tokenize a selector
+ token.text = buffer.trim();
+ addToken();
+ replaceState('before-name');
+ depth = depth + 1;
+ break;
+
+ case 'at-group':
+ // Tokenize an @-group
+ token.name = buffer.trim();
+
+ // XXX: @-rules are starting to get hairy
+ switch (token.type) {
+ case 'font-face':
+ case 'viewport' :
+ case 'page' :
+ pushState('before-name');
+ break;
+
+ default:
+ pushState('before-selector');
+ }
+
+ addToken();
+ depth = depth + 1;
+ break;
+
+ case 'name':
+ case 'at-rule':
+ // Tokenize a declaration or an @-rule
+ token.name = buffer.trim();
+ addToken();
+ pushState('before-name');
+ depth = depth + 1;
+ break;
+
+ case 'comment':
+ case 'double-string':
+ case 'single-string':
+ // Ignore braces in comments and strings
+ buffer += ch;
+ break;
+ case 'before-value':
+ replaceState('value');
+ buffer += ch;
+ break;
+ }
+
+ break;
+
+ case '}':
+ switch (getState()) {
+ case 'before-name':
+ case 'name':
+ case 'before-value':
+ case 'value':
+ // If the buffer contains anything, it is a value
+ if (buffer) {
+ token.value = buffer.trim();
+ }
+
+ // If the current token has a name and a value it should be tokenized.
+ if (token.name && token.value) {
+ addToken();
+ }
+
+ // Leave the block
+ initializeToken('end');
+ addToken();
+ popState();
+
+ // We might need to leave again.
+ // XXX: What about 3 levels deep?
+ if ('at-group' === getState()) {
+ initializeToken('at-group-end');
+ addToken();
+ popState();
+ }
+
+ if (depth > 0) {
+ depth = depth - 1;
+ }
+
+ break;
+
+ case 'at-group':
+ case 'before-selector':
+ case 'selector':
+ // If the sequence is `\}` then assume that the brace should be escaped.
+ if (peek(-1) === '\\') {
+ buffer += ch;
+ break;
+ }
+
+ if (depth > 0) {
+ // Leave block if in an at-group
+ if ('at-group' === getState(1)) {
+ initializeToken('at-group-end');
+ addToken();
+ }
+ }
+
+ if (depth > 1) {
+ popState();
+ }
+
+ if (depth > 0) {
+ depth = depth - 1;
+ }
+ break;
+
+ case 'double-string':
+ case 'single-string':
+ case 'comment':
+ // Ignore braces in comments and strings.
+ buffer += ch;
+ break;
+ }
+
+ break;
+
+ // Strings
+ case '"':
+ case "'":
+ switch (getState()) {
+ case 'double-string':
+ if ('"' === ch && '\\' !== peek(-1)) {
+ popState();
+ }
+ break;
+
+ case 'single-string':
+ if ("'" === ch && '\\' !== peek(-1)) {
+ popState();
+ }
+ break;
+
+ case 'before-at-value':
+ replaceState('at-value');
+ pushState('"' === ch ? 'double-string' : 'single-string');
+ break;
+
+ case 'before-value':
+ replaceState('value');
+ pushState('"' === ch ? 'double-string' : 'single-string');
+ break;
+
+ case 'comment':
+ // Ignore strings within comments.
+ break;
+
+ default:
+ if ('\\' !== peek(-1)) {
+ pushState('"' === ch ? 'double-string' : 'single-string');
+ }
+ }
+
+ buffer += ch;
+ break;
+
+ // Comments
+ case '/':
+ switch (getState()) {
+ case 'comment':
+ case 'double-string':
+ case 'single-string':
+ // Ignore
+ buffer += ch;
+ break;
+
+ case 'before-value':
+ case 'selector':
+ case 'name':
+ case 'value':
+ if (isNextChar('*')) {
+ // Ignore comments in selectors, properties and values. They are
+ // difficult to represent in the AST.
+ var pos = find('*/');
+
+ if (pos) {
+ skip(pos + 1);
+ }
+ } else {
+ if (getState() == 'before-value') replaceState('value');
+ buffer += ch;
+ }
+ break;
+
+ default:
+ if (isNextChar('*')) {
+ // Create a comment token
+ initializeToken('comment');
+ pushState('comment');
+ skip();
+ }
+ else {
+ buffer += ch;
+ }
+ break;
+ }
+ break;
+
+ // Comment end or universal selector
+ case '*':
+ switch (getState()) {
+ case 'comment':
+ if (isNextChar('/')) {
+ // Tokenize a comment
+ token.text = buffer; // Don't trim()!
+ skip();
+ addToken();
+ popState();
+ }
+ else {
+ buffer += ch;
+ }
+ break;
+
+ case 'before-selector':
+ buffer += ch;
+ initializeToken('selector');
+ pushState('selector');
+ break;
+
+ case 'before-value':
+ replaceState('value');
+ buffer += ch;
+ break;
+
+ default:
+ buffer += ch;
+ }
+ break;
+
+ // @-rules
+ case '@':
+ switch (getState()) {
+ case 'comment':
+ case 'double-string':
+ case 'single-string':
+ buffer += ch;
+ break;
+ case 'before-value':
+ replaceState('value');
+ buffer += ch;
+ break;
+
+ default:
+ // Iterate over the supported @-rules and attempt to tokenize one.
+ var tokenized = false;
+ var name;
+ var rule;
+
+ for (var j = 0, len = atRules.length; !tokenized && j < len; ++j) {
+ rule = atRules[j];
+ name = rule.name || rule;
+
+ if (!isNextString(name)) { continue; }
+
+ tokenized = true;
+
+ initializeToken(name);
+ pushState(rule.state || 'at-group');
+ skip(name.length);
+
+ if (rule.prefix) {
+ token.prefix = rule.prefix;
+ }
+
+ if (rule.type) {
+ token.type = rule.type;
+ }
+ }
+
+ if (!tokenized) {
+ // Keep on truckin' America!
+ buffer += ch;
+ }
+ break;
+ }
+ break;
+
+ // Parentheses are tracked to disambiguate semi-colons, such as within a
+ // data URI.
+ case '(':
+ switch (getState()) {
+ case 'value':
+ pushState('value-paren');
+ break;
+ case 'before-value':
+ replaceState('value');
+ break;
+ }
+
+ buffer += ch;
+ break;
+
+ case ')':
+ switch (getState()) {
+ case 'value-paren':
+ popState();
+ break;
+ case 'before-value':
+ replaceState('value');
+ break;
+ }
+
+ buffer += ch;
+ break;
+
+ default:
+ switch (getState()) {
+ case 'before-selector':
+ initializeToken('selector');
+ pushState('selector');
+ break;
+
+ case 'before-name':
+ initializeToken('property');
+ replaceState('name');
+ break;
+
+ case 'before-value':
+ replaceState('value');
+ break;
+
+ case 'before-at-value':
+ replaceState('at-value');
+ break;
+ }
+
+ buffer += ch;
+ break;
+ }
+ }
+
+ return tokens;
+ }
+ });
+
+ var parser = createCommonjsModule(function (module, exports) {
+
+ var debug = debug_1('parse');
+
+
+ exports = module.exports = parse;
+
+ var _comments; // Whether comments are allowed.
+ var _depth; // Current block nesting depth.
+ var _position; // Whether to include line/column position.
+ var _tokens; // Array of lexical tokens.
+
+ /**
+ * Convert a CSS string or array of lexical tokens into a `stringify`-able AST.
+ *
+ * @param {String} css CSS string or array of lexical token
+ * @param {Object} [options]
+ * @param {Boolean} [options.comments=false] allow comment nodes in the AST
+ * @returns {Object} `stringify`-able AST
+ */
+ function parse(css, options) {
+
+ options || (options = {});
+ _comments = !!options.comments;
+ _position = !!options.position;
+
+ _depth = 0;
+
+ // Operate on a copy of the given tokens, or the lex()'d CSS string.
+ _tokens = Array.isArray(css) ? css.slice() : lexer(css);
+
+ var rule;
+ var rules = [];
+ var token;
+
+ while ((token = next())) {
+ rule = parseToken(token);
+ rule && rules.push(rule);
+ }
+
+ return {
+ type: "stylesheet",
+ stylesheet: {
+ rules: rules
+ }
+ };
+ }
+
+ // -- Functions --------------------------------------------------------------
+
+ /**
+ * Build an AST node from a lexical token.
+ *
+ * @param {Object} token lexical token
+ * @param {Object} [override] object hash of properties that override those
+ * already in the token, or that will be added to the token.
+ * @returns {Object} AST node
+ */
+ function astNode(token, override) {
+ override || (override = {});
+
+ var key;
+ var keys = ['type', 'name', 'value'];
+ var node = {};
+
+ // Avoiding [].forEach for performance reasons.
+ for (var i = 0; i < keys.length; ++i) {
+ key = keys[i];
+
+ if (token[key]) {
+ node[key] = override[key] || token[key];
+ }
+ }
+
+ keys = Object.keys(override);
+
+ for (i = 0; i < keys.length; ++i) {
+ key = keys[i];
+
+ if (!node[key]) {
+ node[key] = override[key];
+ }
+ }
+
+ if (_position) {
+ node.position = {
+ start: token.start,
+ end: token.end
+ };
+ }
+
+ return node;
+ }
+
+ /**
+ * Remove a lexical token from the stack and return the removed token.
+ *
+ * @returns {Object} lexical token
+ */
+ function next() {
+ var token = _tokens.shift();
+ return token;
+ }
+
+ // -- Parse* Functions ---------------------------------------------------------
+
+ /**
+ * Convert an @-group lexical token to an AST node.
+ *
+ * @param {Object} token @-group lexical token
+ * @returns {Object} @-group AST node
+ */
+ function parseAtGroup(token) {
+ _depth = _depth + 1;
+
+ // As the @-group token is assembled, relevant token values are captured here
+ // temporarily. They will later be used as `tokenize()` overrides.
+ var overrides = {};
+
+ switch (token.type) {
+ case 'font-face':
+ case 'viewport' :
+ overrides.declarations = parseDeclarations();
+ break;
+
+ case 'page':
+ overrides.prefix = token.prefix;
+ overrides.declarations = parseDeclarations();
+ break;
+
+ default:
+ overrides.prefix = token.prefix;
+ overrides.rules = parseRules();
+ }
+
+ return astNode(token, overrides);
+ }
+
+ /**
+ * Convert an @import lexical token to an AST node.
+ *
+ * @param {Object} token @import lexical token
+ * @returns {Object} @import AST node
+ */
+ function parseAtImport(token) {
+ return astNode(token);
+ }
+
+ /**
+ * Convert an @charset token to an AST node.
+ *
+ * @param {Object} token @charset lexical token
+ * @returns {Object} @charset node
+ */
+ function parseCharset(token) {
+ return astNode(token);
+ }
+
+ /**
+ * Convert a comment token to an AST Node.
+ *
+ * @param {Object} token comment lexical token
+ * @returns {Object} comment node
+ */
+ function parseComment(token) {
+ return astNode(token, {text: token.text});
+ }
+
+ function parseNamespace(token) {
+ return astNode(token);
+ }
+
+ /**
+ * Convert a property lexical token to a property AST node.
+ *
+ * @returns {Object} property node
+ */
+ function parseProperty(token) {
+ return astNode(token);
+ }
+
+ /**
+ * Convert a selector lexical token to a selector AST node.
+ *
+ * @param {Object} token selector lexical token
+ * @returns {Object} selector node
+ */
+ function parseSelector(token) {
+ function trim(str) {
+ return str.trim();
+ }
+
+ return astNode(token, {
+ type: 'rule',
+ selectors: token.text.split(',').map(trim),
+ declarations: parseDeclarations()
+ });
+ }
+
+ /**
+ * Convert a lexical token to an AST node.
+ *
+ * @returns {Object|undefined} AST node
+ */
+ function parseToken(token) {
+ switch (token.type) {
+ // Cases are listed in roughly descending order of probability.
+ case 'property': return parseProperty(token);
+
+ case 'selector': return parseSelector(token);
+
+ case 'at-group-end': _depth = _depth - 1; return;
+
+ case 'media' :
+ case 'keyframes' :return parseAtGroup(token);
+
+ case 'comment': if (_comments) { return parseComment(token); } break;
+
+ case 'charset': return parseCharset(token);
+ case 'import': return parseAtImport(token);
+
+ case 'namespace': return parseNamespace(token);
+
+ case 'font-face':
+ case 'supports' :
+ case 'viewport' :
+ case 'document' :
+ case 'page' : return parseAtGroup(token);
+ }
+ }
+
+ // -- Parse Helper Functions ---------------------------------------------------
+
+ /**
+ * Iteratively parses lexical tokens from the stack into AST nodes until a
+ * conditional function returns `false`, at which point iteration terminates
+ * and any AST nodes collected are returned.
+ *
+ * @param {Function} conditionFn
+ * @param {Object} token the lexical token being parsed
+ * @returns {Boolean} `true` if the token should be parsed, `false` otherwise
+ * @return {Array} AST nodes
+ */
+ function parseTokensWhile(conditionFn) {
+ var node;
+ var nodes = [];
+ var token;
+
+ while ((token = next()) && (conditionFn && conditionFn(token))) {
+ node = parseToken(token);
+ node && nodes.push(node);
+ }
+
+ // Place an unused non-`end` lexical token back onto the stack.
+ if (token && token.type !== 'end') {
+ _tokens.unshift(token);
+ }
+
+ return nodes;
+ }
+
+ /**
+ * Convert a series of tokens into a sequence of declaration AST nodes.
+ *
+ * @returns {Array} declaration nodes
+ */
+ function parseDeclarations() {
+ return parseTokensWhile(function (token) {
+ return (token.type === 'property' || token.type === 'comment');
+ });
+ }
+
+ /**
+ * Convert a series of tokens into a sequence of rule nodes.
+ *
+ * @returns {Array} rule nodes
+ */
+ function parseRules() {
+ return parseTokensWhile(function () { return _depth; });
+ }
+ });
+
+ var stringify_1 = createCommonjsModule(function (module, exports) {
+
+ var debug = debug_1('stringify');
+
+ var _comments; // Whether comments are allowed in the stringified CSS.
+ var _compress; // Whether the stringified CSS should be compressed.
+ var _indentation; // Indentation option value.
+ var _level; // Current indentation level.
+ var _n; // Compression-aware newline character.
+ var _s; // Compression-aware space character.
+
+ exports = module.exports = stringify;
+
+ /**
+ * Convert a `stringify`-able AST into a CSS string.
+ *
+ * @param {Object} `stringify`-able AST
+ * @param {Object} [options]
+ * @param {Boolean} [options.comments=false] allow comments in the CSS
+ * @param {Boolean} [options.compress=false] compress whitespace
+ * @param {String} [options.indentation=''] indentation sequence
+ * @returns {String} CSS
+ */
+ function stringify(ast, options) {
+
+ options || (options = {});
+ _indentation = options.indentation || '';
+ _compress = !!options.compress;
+ _comments = !!options.comments;
+ _level = 1;
+
+ if (_compress) {
+ _n = _s = '';
+ } else {
+ _n = '\n';
+ _s = ' ';
+ }
+
+ var css = reduce(ast.stylesheet.rules, stringifyNode).join('\n').trim();
+
+ return css;
+ }
+
+ // -- Functions --------------------------------------------------------------
+
+ /**
+ * Modify the indentation level, or return a compression-aware sequence of
+ * spaces equal to the current indentation level.
+ *
+ * @param {Number} [level=undefined] indentation level modifier
+ * @returns {String} sequence of spaces
+ */
+ function indent(level) {
+ if (level) {
+ _level += level;
+ return;
+ }
+
+ if (_compress) { return ''; }
+
+ return Array(_level).join(_indentation || '');
+ }
+
+ // -- Stringify Functions ------------------------------------------------------
+
+ /**
+ * Stringify an @-rule AST node.
+ *
+ * Use `stringifyAtGroup()` when dealing with @-groups that may contain blocks
+ * such as @media.
+ *
+ * @param {String} type @-rule type. E.g., import, charset
+ * @returns {String} Stringified @-rule
+ */
+ function stringifyAtRule(node) {
+ return '@' + node.type + ' ' + node.value + ';' + _n;
+ }
+
+ /**
+ * Stringify an @-group AST node.
+ *
+ * Use `stringifyAtRule()` when dealing with @-rules that may not contain blocks
+ * such as @import.
+ *
+ * @param {Object} node @-group AST node
+ * @returns {String}
+ */
+ function stringifyAtGroup(node) {
+ var label = '';
+ var prefix = node.prefix || '';
+
+ if (node.name) {
+ label = ' ' + node.name;
+ }
+
+ // FIXME: @-rule conditional logic is leaking everywhere.
+ var chomp = node.type !== 'page';
+
+ return '@' + prefix + node.type + label + _s + stringifyBlock(node, chomp) + _n;
+ }
+
+ /**
+ * Stringify a comment AST node.
+ *
+ * @param {Object} node comment AST node
+ * @returns {String}
+ */
+ function stringifyComment(node) {
+ if (!_comments) { return ''; }
+
+ return '/*' + (node.text || '') + '*/' + _n;
+ }
+
+ /**
+ * Stringify a rule AST node.
+ *
+ * @param {Object} node rule AST node
+ * @returns {String}
+ */
+ function stringifyRule(node) {
+ var label;
+
+ if (node.selectors) {
+ label = node.selectors.join(',' + _n);
+ } else {
+ label = '@' + node.type;
+ label += node.name ? ' ' + node.name : '';
+ }
+
+ return indent() + label + _s + stringifyBlock(node) + _n;
+ }
+
+
+ // -- Stringify Helper Functions -----------------------------------------------
+
+ /**
+ * Reduce an array by applying a function to each item and retaining the truthy
+ * results.
+ *
+ * When `item.type` is `'comment'` `stringifyComment` will be applied instead.
+ *
+ * @param {Array} items array to reduce
+ * @param {Function} fn function to call for each item in the array
+ * @returns {Mixed} Truthy values will be retained, falsy values omitted
+ * @returns {Array} retained results
+ */
+ function reduce(items, fn) {
+ return items.reduce(function (results, item) {
+ var result = (item.type === 'comment') ? stringifyComment(item) : fn(item);
+ result && results.push(result);
+ return results;
+ }, []);
+ }
+
+ /**
+ * Stringify an AST node with the assumption that it represents a block of
+ * declarations or other @-group contents.
+ *
+ * @param {Object} node AST node
+ * @returns {String}
+ */
+ // FIXME: chomp should not be a magic boolean parameter
+ function stringifyBlock(node, chomp) {
+ var children = node.declarations;
+ var fn = stringifyDeclaration;
+
+ if (node.rules) {
+ children = node.rules;
+ fn = stringifyRule;
+ }
+
+ children = stringifyChildren(children, fn);
+ children && (children = _n + children + (chomp ? '' : _n));
+
+ return '{' + children + indent() + '}';
+ }
+
+ /**
+ * Stringify an array of child AST nodes by calling the given stringify function
+ * once for each child, and concatenating the results.
+ *
+ * @param {Array} children `node.rules` or `node.declarations`
+ * @param {Function} fn stringify function
+ * @returns {String}
+ */
+ function stringifyChildren(children, fn) {
+ if (!children) { return ''; }
+
+ indent(1);
+ var results = reduce(children, fn);
+ indent(-1);
+
+ if (!results.length) { return ''; }
+
+ return results.join(_n);
+ }
+
+ /**
+ * Stringify a declaration AST node.
+ *
+ * @param {Object} node declaration AST node
+ * @returns {String}
+ */
+ function stringifyDeclaration(node) {
+ if (node.type === 'property') {
+ return stringifyProperty(node);
+ }
+ }
+
+ /**
+ * Stringify an AST node.
+ *
+ * @param {Object} node AST node
+ * @returns {String}
+ */
+ function stringifyNode(node) {
+ switch (node.type) {
+ // Cases are listed in roughly descending order of probability.
+ case 'rule': return stringifyRule(node);
+
+ case 'media' :
+ case 'keyframes': return stringifyAtGroup(node);
+
+ case 'comment': return stringifyComment(node);
+
+ case 'import' :
+ case 'charset' :
+ case 'namespace': return stringifyAtRule(node);
+
+ case 'font-face':
+ case 'supports' :
+ case 'viewport' :
+ case 'document' :
+ case 'page' : return stringifyAtGroup(node);
+ }
+ }
+
+ /**
+ * Stringify an AST property node.
+ *
+ * @param {Object} node AST property node
+ * @returns {String}
+ */
+ function stringifyProperty(node) {
+ var name = node.name ? node.name + ':' + _s : '';
+
+ return indent() + name + node.value + ';';
+ }
+ });
+
+ var mensch = {
+ lex : lexer,
+ parse: parser,
+ stringify: stringify_1
+ };
+
+ // Notable changes from Slick.Parser 1.0.x
+
+ // The parser now uses 2 classes: Expressions and Expression
+ // `new Expressions` produces an array-like object containing a list of Expression objects
+ // - Expressions::toString() produces a cleaned up expressions string
+ // `new Expression` produces an array-like object
+ // - Expression::toString() produces a cleaned up expression string
+ // The only exposed method is parse, which produces a (cached) `new Expressions` instance
+ // parsed.raw is no longer present, use .toString()
+ // parsed.expression is now useless, just use the indices
+ // parsed.reverse() has been removed for now, due to its apparent uselessness
+ // Other changes in the Expressions object:
+ // - classNames are now unique, and save both escaped and unescaped values
+ // - attributes now save both escaped and unescaped values
+ // - pseudos now save both escaped and unescaped values
+
+ var escapeRe = /([-.*+?^${}()|[\]\/\\])/g,
+ unescapeRe = /\\/g;
+
+ var escape$1 = function(string){
+ // XRegExp v2.0.0-beta-3
+ // « https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js
+ return (string + "").replace(escapeRe, '\\$1')
+ };
+
+ var unescape$1 = function(string){
+ return (string + "").replace(unescapeRe, '')
+ };
+
+ var slickRe = RegExp(
+ /*
+ #!/usr/bin/env ruby
+ puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
+ __END__
+ "(?x)^(?:\
+ \\s* ( , ) \\s* # Separator \n\
+ | \\s* ( + ) \\s* # Combinator \n\
+ | ( \\s+ ) # CombinatorChildren \n\
+ | ( + | \\* ) # Tag \n\
+ | \\# ( + ) # ID \n\
+ | \\. ( + ) # ClassName \n\
+ | # Attribute \n\
+ \\[ \
+ \\s* (+) (?: \
+ \\s* ([*^$!~|]?=) (?: \
+ \\s* (?:\
+ ([\"']?)(.*?)\\9 \
+ )\
+ ) \
+ )? \\s* \
+ \\](?!\\]) \n\
+ | :+ ( + )(?:\
+ \\( (?:\
+ (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
+ ) \\)\
+ )?\
+ )"
+ */
+ "^(?:\\s*(,)\\s*|\\s*(+)\\s*|(\\s+)|(+|\\*)|\\#(+)|\\.(+)|\\[\\s*(+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
+ .replace(//, '[' + escape$1(">+~`!@$%^&={}\\;") + ']')
+ .replace(//g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
+ .replace(//g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
+ );
+
+ // Part
+
+ var Part = function Part(combinator){
+ this.combinator = combinator || " ";
+ this.tag = "*";
+ };
+
+ Part.prototype.toString = function(){
+
+ if (!this.raw){
+
+ var xpr = "", k, part;
+
+ xpr += this.tag || "*";
+ if (this.id) xpr += "#" + this.id;
+ if (this.classes) xpr += "." + this.classList.join(".");
+ if (this.attributes) for (k = 0; part = this.attributes[k++];){
+ xpr += "[" + part.name + (part.operator ? part.operator + '"' + part.value + '"' : '') + "]";
+ }
+ if (this.pseudos) for (k = 0; part = this.pseudos[k++];){
+ xpr += ":" + part.name;
+ if (part.value) xpr += "(" + part.value + ")";
+ }
+
+ this.raw = xpr;
+
+ }
+
+ return this.raw
+ };
+
+ // Expression
+
+ var Expression = function Expression(){
+ this.length = 0;
+ };
+
+ Expression.prototype.toString = function(){
+
+ if (!this.raw){
+
+ var xpr = "";
+
+ for (var j = 0, bit; bit = this[j++];){
+ if (j !== 1) xpr += " ";
+ if (bit.combinator !== " ") xpr += bit.combinator + " ";
+ xpr += bit;
+ }
+
+ this.raw = xpr;
+
+ }
+
+ return this.raw
+ };
+
+ var replacer$1 = function(
+ rawMatch,
+
+ separator,
+ combinator,
+ combinatorChildren,
+
+ tagName,
+ id,
+ className,
+
+ attributeKey,
+ attributeOperator,
+ attributeQuote,
+ attributeValue,
+
+ pseudoMarker,
+ pseudoClass,
+ pseudoQuote,
+ pseudoClassQuotedValue,
+ pseudoClassValue
+ ){
+
+ var expression, current;
+
+ if (separator || !this.length){
+ expression = this[this.length++] = new Expression;
+ if (separator) return ''
+ }
+
+ if (!expression) expression = this[this.length - 1];
+
+ if (combinator || combinatorChildren || !expression.length){
+ current = expression[expression.length++] = new Part(combinator);
+ }
+
+ if (!current) current = expression[expression.length - 1];
+
+ if (tagName){
+
+ current.tag = unescape$1(tagName);
+
+ } else if (id){
+
+ current.id = unescape$1(id);
+
+ } else if (className){
+
+ var unescaped = unescape$1(className);
+
+ var classes = current.classes || (current.classes = {});
+ if (!classes[unescaped]){
+ classes[unescaped] = escape$1(className);
+ var classList = current.classList || (current.classList = []);
+ classList.push(unescaped);
+ classList.sort();
+ }
+
+ } else if (pseudoClass){
+
+ pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue
+
+ ;(current.pseudos || (current.pseudos = [])).push({
+ type : pseudoMarker.length == 1 ? 'class' : 'element',
+ name : unescape$1(pseudoClass),
+ escapedName : escape$1(pseudoClass),
+ value : pseudoClassValue ? unescape$1(pseudoClassValue) : null,
+ escapedValue : pseudoClassValue ? escape$1(pseudoClassValue) : null
+ });
+
+ } else if (attributeKey){
+
+ attributeValue = attributeValue ? escape$1(attributeValue) : null
+
+ ;(current.attributes || (current.attributes = [])).push({
+ operator : attributeOperator,
+ name : unescape$1(attributeKey),
+ escapedName : escape$1(attributeKey),
+ value : attributeValue ? unescape$1(attributeValue) : null,
+ escapedValue : attributeValue ? escape$1(attributeValue) : null
+ });
+
+ }
+
+ return ''
+
+ };
+
+ // Expressions
+
+ var Expressions = function Expressions(expression){
+ this.length = 0;
+
+ var self = this;
+
+ var original = expression, replaced;
+
+ while (expression){
+ replaced = expression.replace(slickRe, function(){
+ return replacer$1.apply(self, arguments)
+ });
+ if (replaced === expression) throw new Error(original + ' is an invalid expression')
+ expression = replaced;
+ }
+ };
+
+ Expressions.prototype.toString = function(){
+ if (!this.raw){
+ var expressions = [];
+ for (var i = 0, expression; expression = this[i++];) expressions.push(expression);
+ this.raw = expressions.join(", ");
+ }
+
+ return this.raw
+ };
+
+ var cache = {};
+
+ var parse$5 = function(expression){
+ if (expression == null) return null
+ expression = ('' + expression).replace(/^\s+|\s+$/g, '');
+ return cache[expression] || (cache[expression] = new Expressions(expression))
+ };
+
+ var parser$1 = parse$5;
+
+ var selector = createCommonjsModule(function (module, exports) {
+
+
+
+ module.exports = exports = Selector;
+
+ /**
+ * CSS selector constructor.
+ *
+ * @param {String} selector text
+ * @param {Array} optionally, precalculated specificity
+ * @api public
+ */
+
+ function Selector(text, styleAttribute) {
+ this.text = text;
+ this.spec = undefined;
+ this.styleAttribute = styleAttribute || false;
+ }
+
+ /**
+ * Get parsed selector.
+ *
+ * @api public
+ */
+
+ Selector.prototype.parsed = function() {
+ if (!this.tokens) { this.tokens = parse(this.text); }
+ return this.tokens;
+ };
+
+ /**
+ * Lazy specificity getter
+ *
+ * @api public
+ */
+
+ Selector.prototype.specificity = function() {
+ var styleAttribute = this.styleAttribute;
+ if (!this.spec) { this.spec = specificity(this.text, this.parsed()); }
+ return this.spec;
+
+ function specificity(text, parsed) {
+ var expressions = parsed || parse(text);
+ var spec = [styleAttribute ? 1 : 0, 0, 0, 0];
+ var nots = [];
+
+ for (var i = 0; i < expressions.length; i++) {
+ var expression = expressions[i];
+ var pseudos = expression.pseudos;
+
+ // id awards a point in the second column
+ if (expression.id) { spec[1]++; }
+
+ // classes and attributes award a point each in the third column
+ if (expression.attributes) { spec[2] += expression.attributes.length; }
+ if (expression.classList) { spec[2] += expression.classList.length; }
+
+ // tag awards a point in the fourth column
+ if (expression.tag && expression.tag !== '*') { spec[3]++; }
+
+ // pseudos award a point each in the fourth column
+ if (pseudos) {
+ spec[3] += pseudos.length;
+
+ for (var p = 0; p < pseudos.length; p++) {
+ if (pseudos[p].name === 'not') {
+ nots.push(pseudos[p].value);
+ spec[3]--;
+ }
+ }
+ }
+ }
+
+ for (var ii = nots.length; ii--;) {
+ var not = specificity(nots[ii]);
+ for (var jj = 4; jj--;) { spec[jj] += not[jj]; }
+ }
+
+ return spec;
+ }
+ };
+
+ /**
+ * Parses a selector and returns the tokens.
+ *
+ * @param {String} selector
+ * @api private.
+ */
+
+ function parse(text) {
+ try {
+ return parser$1(text)[0];
+ } catch (e) {
+ return [];
+ }
+ }
+ });
+
+ var property = createCommonjsModule(function (module, exports) {
+
+ module.exports = exports = Property;
+
+ /**
+ * Module dependencies.
+ */
+
+
+
+ /**
+ * CSS property constructor.
+ *
+ * @param {String} property
+ * @param {String} value
+ * @param {Selector} selector the property originates from
+ * @param {Integer} priority 0 for normal properties, 2 for !important properties.
+ * @param {Array} additional array of integers representing more detailed priorities (sorting)
+ * @api public
+ */
+
+ function Property(prop, value, selector, priority, additionalPriority) {
+ this.prop = prop;
+ this.value = value;
+ this.selector = selector;
+ this.priority = priority || 0;
+ this.additionalPriority = additionalPriority || [];
+ }
+
+ /**
+ * Compares with another Property based on Selector#specificity.
+ *
+ * @api public
+ */
+
+ Property.prototype.compareFunc = function(property) {
+ var a = [];
+ a.push.apply(a, this.selector.specificity());
+ a.push.apply(a, this.additionalPriority);
+ a[0] += this.priority;
+ var b = [];
+ b.push.apply(b, property.selector.specificity());
+ b.push.apply(b, property.additionalPriority);
+ b[0] += property.priority;
+ return utils$1.compareFunc(a, b);
+ };
+
+ Property.prototype.compare = function(property) {
+ var winner = this.compareFunc(property);
+ if (winner === 1) {
+ return this;
+ }
+ return property;
+ };
+
+
+ /**
+ * Returns CSS property
+ *
+ * @api public
+ */
+
+ Property.prototype.toString = function() {
+ return this.prop + ': ' + this.value.replace(/['"]+/g, '') + ';';
+ };
+ });
+
+ var utils$1 = createCommonjsModule(function (module, exports) {
+
+ /**
+ * Module dependencies.
+ */
+
+
+
+
+
+ exports.Selector = selector;
+ exports.Property = property;
+
+ /**
+ * Returns an array of the selectors.
+ *
+ * @license Sizzle CSS Selector Engine - MIT
+ * @param {String} selectorText from mensch
+ * @api public
+ */
+
+ exports.extract = function extract(selectorText) {
+ var attr = 0;
+ var sels = [];
+ var sel = '';
+
+ for (var i = 0, l = selectorText.length; i < l; i++) {
+ var c = selectorText.charAt(i);
+
+ if (attr) {
+ if (']' === c || ')' === c) { attr--; }
+ sel += c;
+ } else {
+ if (',' === c) {
+ sels.push(sel);
+ sel = '';
+ } else {
+ if ('[' === c || '(' === c) { attr++; }
+ if (sel.length || (c !== ',' && c !== '\n' && c !== ' ')) { sel += c; }
+ }
+ }
+ }
+
+ if (sel.length) {
+ sels.push(sel);
+ }
+
+ return sels;
+ };
+
+ /**
+ * Returns a parse tree for a CSS source.
+ * If it encounters multiple selectors separated by a comma, it splits the
+ * tree.
+ *
+ * @param {String} css source
+ * @api public
+ */
+
+ exports.parseCSS = function(css) {
+ var parsed = mensch.parse(css, {position: true, comments: true});
+ var rules = typeof parsed.stylesheet != 'undefined' && parsed.stylesheet.rules ? parsed.stylesheet.rules : [];
+ var ret = [];
+
+ for (var i = 0, l = rules.length; i < l; i++) {
+ if (rules[i].type == 'rule') {
+ var rule = rules[i];
+ var selectors = rule.selectors;
+
+ for (var ii = 0, ll = selectors.length; ii < ll; ii++) {
+ ret.push([selectors[ii], rule.declarations]);
+ }
+ }
+ }
+
+ return ret;
+ };
+
+ /**
+ * Returns preserved text for a CSS source.
+ *
+ * @param {String} css source
+ * @param {Object} options
+ * @api public
+ */
+
+ exports.getPreservedText = function(css, options, ignoredPseudos) {
+ var parsed = mensch.parse(css, {position: true, comments: true});
+ var rules = typeof parsed.stylesheet != 'undefined' && parsed.stylesheet.rules ? parsed.stylesheet.rules : [];
+ var preserved = [];
+ var lastStart = null;
+
+ for (var i = rules.length - 1; i >= 0; i--) {
+ if ((options.fontFaces && rules[i].type === 'font-face') ||
+ (options.mediaQueries && rules[i].type === 'media') ||
+ (options.keyFrames && rules[i].type === 'keyframes') ||
+ (options.pseudos && rules[i].selectors && this.matchesPseudo(rules[i].selectors[0], ignoredPseudos))) {
+ preserved.unshift(
+ mensch.stringify(
+ { stylesheet: { rules: [ rules[i] ] }},
+ { comments: false, indentation: ' ' }
+ )
+ );
+ }
+ lastStart = rules[i].position.start;
+ }
+
+ if (preserved.length === 0) {
+ return false;
+ }
+ return '\n' + preserved.join('\n') + '\n';
+ };
+
+ exports.normalizeLineEndings = function(text) {
+ return text.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
+ };
+
+ exports.matchesPseudo = function(needle, haystack) {
+ return haystack.find(function (element) {
+ return needle.indexOf(element) > -1;
+ })
+ };
+
+ /**
+ * Compares two specificity vectors, returning the winning one.
+ *
+ * @param {Array} vector a
+ * @param {Array} vector b
+ * @return {Array}
+ * @api public
+ */
+
+ exports.compareFunc = function(a, b) {
+ var min = Math.min(a.length, b.length);
+ for (var i = 0; i < min; i++) {
+ if (a[i] === b[i]) { continue; }
+ if (a[i] > b[i]) { return 1; }
+ return -1;
+ }
+
+ return a.length - b.length;
+ };
+
+ exports.compare = function(a, b) {
+ return exports.compareFunc(a, b) == 1 ? a : b;
+ };
+
+ exports.getDefaultOptions = function(options) {
+ var result = Object.assign({
+ extraCss: '',
+ insertPreservedExtraCss: true,
+ applyStyleTags: true,
+ removeStyleTags: true,
+ preserveMediaQueries: true,
+ preserveFontFaces: true,
+ preserveKeyFrames: true,
+ preservePseudos: true,
+ applyWidthAttributes: true,
+ applyHeightAttributes: true,
+ applyAttributesTableElements: true,
+ url: ''
+ }, options);
+
+ result.webResources = result.webResources || {};
+
+ return result;
+ };
+ });
+ var utils_1 = utils$1.Selector;
+ var utils_2 = utils$1.Property;
+ var utils_3 = utils$1.extract;
+ var utils_4 = utils$1.parseCSS;
+ var utils_5 = utils$1.getPreservedText;
+ var utils_6 = utils$1.normalizeLineEndings;
+ var utils_7 = utils$1.matchesPseudo;
+ var utils_8 = utils$1.compareFunc;
+ var utils_9 = utils$1.compare;
+ var utils_10 = utils$1.getDefaultOptions;
+
+ var cheerio_1 = createCommonjsModule(function (module) {
+
+ /**
+ * Module dependencies.
+ */
+
+
+
+ var cheerioLoad = function(html, options, encodeEntities) {
+ options = Object.assign({decodeEntities: false, _useHtmlParser2:true}, options);
+ html = encodeEntities(html);
+ return cheerio.load(html, options);
+ };
+
+ var createEntityConverters = function () {
+ var codeBlockLookup = [];
+
+ var encodeCodeBlocks = function(html) {
+ var blocks = module.exports.codeBlocks;
+ Object.keys(blocks).forEach(function(key) {
+ var re = new RegExp(blocks[key].start + '([\\S\\s]*?)' + blocks[key].end, 'g');
+ html = html.replace(re, function(match, subMatch) {
+ codeBlockLookup.push(match);
+ return 'JUICE_CODE_BLOCK_' + (codeBlockLookup.length - 1) + '_';
+ });
+ });
+ return html;
+ };
+
+ var decodeCodeBlocks = function(html) {
+ for(var index = 0; index < codeBlockLookup.length; index++) {
+ var re = new RegExp('JUICE_CODE_BLOCK_' + index + '_(="")?', 'gi');
+ html = html.replace(re, function() {
+ return codeBlockLookup[index];
+ });
+ }
+ return html;
+ };
+
+ return {
+ encodeEntities: encodeCodeBlocks,
+ decodeEntities: decodeCodeBlocks,
+ };
+ };
+
+ /**
+ * Parses the input, calls the callback on the parsed DOM, and generates the output
+ *
+ * @param {String} html input html to be processed
+ * @param {Object} options for the parser
+ * @param {Function} callback to be invoked on the DOM
+ * @param {Array} callbackExtraArguments to be passed to the callback
+ * @return {String} resulting html
+ */
+ module.exports = function(html, options, callback, callbackExtraArguments) {
+ var entityConverters = createEntityConverters();
+
+ var $ = cheerioLoad(html, options, entityConverters.encodeEntities);
+ var args = [ $ ];
+ args.push.apply(args, callbackExtraArguments);
+ var doc = callback.apply(undefined, args) || $;
+
+ if (options && options.xmlMode) {
+ return entityConverters.decodeEntities(doc.xml());
+ }
+ return entityConverters.decodeEntities(doc.html());
+ };
+
+ module.exports.codeBlocks = {
+ EJS: { start: '<%', end: '%>' },
+ HBS: { start: '{{', end: '}}' }
+ };
+ });
+ var cheerio_2 = cheerio_1.codeBlocks;
+
+ /**
+ * Converts a decimal number to roman numeral.
+ * https://stackoverflow.com/questions/9083037/convert-a-number-into-a-roman-numeral-in-javascript
+ *
+ * @param {Number} number
+ * @api private.
+ */
+ var romanize = function(num) {
+ if (isNaN(num))
+ return NaN;
+ var digits = String(+num).split(""),
+ key = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM",
+ "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC",
+ "","I","II","III","IV","V","VI","VII","VIII","IX"],
+ roman = "",
+ i = 3;
+ while (i--)
+ roman = (key[+digits.pop() + (i * 10)] || "") + roman;
+ return Array(+digits.join("") + 1).join("M") + roman;
+ };
+
+ /**
+ * Converts a decimal number to alphanumeric numeral.
+ * https://stackoverflow.com/questions/45787459/convert-number-to-alphabet-string-javascript
+ *
+ * @param {Number} number
+ * @api private.
+ */
+ var alphanumeric = function(num) {
+ var s = '', t;
+
+ while (num > 0) {
+ t = (num - 1) % 26;
+ s = String.fromCharCode(65 + t) + s;
+ num = (num - t)/26 | 0;
+ }
+ return s || undefined;
+ };
+
+ var numbers = {
+ romanize: romanize,
+ alphanumeric: alphanumeric
+ };
+
+ var inline = function makeJuiceClient(juiceClient) {
+
+ juiceClient.ignoredPseudos = ['hover', 'active', 'focus', 'visited', 'link'];
+ juiceClient.widthElements = ['TABLE', 'TD', 'TH', 'IMG'];
+ juiceClient.heightElements = ['TABLE', 'TD', 'TH', 'IMG'];
+ juiceClient.tableElements = ['TABLE', 'TH', 'TR', 'TD', 'CAPTION', 'COLGROUP', 'COL', 'THEAD', 'TBODY', 'TFOOT'];
+ juiceClient.nonVisualElements = [ 'HEAD', 'TITLE', 'BASE', 'LINK', 'STYLE', 'META', 'SCRIPT', 'NOSCRIPT' ];
+ juiceClient.styleToAttribute = {
+ 'background-color': 'bgcolor',
+ 'background-image': 'background',
+ 'text-align': 'align',
+ 'vertical-align': 'valign'
+ };
+ juiceClient.excludedProperties = [];
+
+ juiceClient.juiceDocument = juiceDocument;
+ juiceClient.inlineDocument = inlineDocument;
+
+ function inlineDocument($, css, options) {
+
+ options = options || {};
+ var rules = utils$1.parseCSS(css);
+ var editedElements = [];
+ var styleAttributeName = 'style';
+ var counters = {};
+
+ if (options.styleAttributeName) {
+ styleAttributeName = options.styleAttributeName;
+ }
+
+ rules.forEach(handleRule);
+ editedElements.forEach(setStyleAttrs);
+
+ if (options.inlinePseudoElements) {
+ editedElements.forEach(inlinePseudoElements);
+ }
+
+ if (options.applyWidthAttributes) {
+ editedElements.forEach(function(el) {
+ setDimensionAttrs(el, 'width');
+ });
+ }
+
+ if (options.applyHeightAttributes) {
+ editedElements.forEach(function(el) {
+ setDimensionAttrs(el, 'height');
+ });
+ }
+
+ if (options.applyAttributesTableElements) {
+ editedElements.forEach(setAttributesOnTableElements);
+ }
+
+ if (options.insertPreservedExtraCss && options.extraCss) {
+ var preservedText = utils$1.getPreservedText(options.extraCss, {
+ mediaQueries: options.preserveMediaQueries,
+ fontFaces: options.preserveFontFaces,
+ keyFrames: options.preserveKeyFrames
+ });
+ if (preservedText) {
+ var $appendTo = null;
+ if (options.insertPreservedExtraCss !== true) {
+ $appendTo = $(options.insertPreservedExtraCss);
+ } else {
+ $appendTo = $('head');
+ if (!$appendTo.length) { $appendTo = $('body'); }
+ if (!$appendTo.length) { $appendTo = $.root(); }
+ }
+
+ $appendTo.first().append('');
+ }
+ }
+
+ function handleRule(rule) {
+ var sel = rule[0];
+ var style = rule[1];
+ var selector = new utils$1.Selector(sel);
+ var parsedSelector = selector.parsed();
+
+ if (!parsedSelector) {
+ return;
+ }
+
+ var pseudoElementType = getPseudoElementType(parsedSelector);
+
+ // skip rule if the selector has any pseudos which are ignored
+ for (var i = 0; i < parsedSelector.length; ++i) {
+ var subSel = parsedSelector[i];
+ if (subSel.pseudos) {
+ for (var j = 0; j < subSel.pseudos.length; ++j) {
+ var subSelPseudo = subSel.pseudos[j];
+ if (juiceClient.ignoredPseudos.indexOf(subSelPseudo.name) >= 0) {
+ return;
+ }
+ }
+ }
+ }
+
+ if (pseudoElementType) {
+ var last = parsedSelector[parsedSelector.length - 1];
+ var pseudos = last.pseudos;
+ last.pseudos = filterElementPseudos(last.pseudos);
+ sel = parsedSelector.toString();
+ last.pseudos = pseudos;
+ }
+
+ var els;
+ try {
+ els = $(sel);
+ } catch (err) {
+ // skip invalid selector
+ return;
+ }
+
+ els.each(function() {
+ var el = this;
+
+ if (el.name && juiceClient.nonVisualElements.indexOf(el.name.toUpperCase()) >= 0) {
+ return;
+ }
+
+ if (pseudoElementType) {
+ var pseudoElPropName = 'pseudo' + pseudoElementType;
+ var pseudoEl = el[pseudoElPropName];
+ if (!pseudoEl) {
+ pseudoEl = el[pseudoElPropName] = $('').get(0);
+ pseudoEl.pseudoElementType = pseudoElementType;
+ pseudoEl.pseudoElementParent = el;
+ pseudoEl.counterProps = el.counterProps;
+ el[pseudoElPropName] = pseudoEl;
+ }
+ el = pseudoEl;
+ }
+
+ if (!el.styleProps) {
+ el.styleProps = {};
+
+ // if the element has inline styles, fake selector with topmost specificity
+ if ($(el).attr(styleAttributeName)) {
+ var cssText = '* { ' + $(el).attr(styleAttributeName) + ' } ';
+ addProps(utils$1.parseCSS(cssText)[0][1], new utils$1.Selector('");
+ }
+ }, {
+ key: "computeStyle",
+ value: function computeStyle() {
+ // 计算需要append进富文本的style
+ var mathStyle = this.getStyleFromSheets('mjx-container');
+ var cherryStyle = this.getStyleFromSheets('cherry');
+ var echartStyle = '';
+ return {
+ mathStyle: mathStyle,
+ echartStyle: echartStyle,
+ cherryStyle: cherryStyle
+ };
+ }
+ /**
+ * 由于复制操作会随着预览区域的内容增加而耗时变长,所以需要增加“正在复制”的状态回显
+ * 同时该状态也用于限频
+ */
+
+ }, {
+ key: "toggleLoading",
+ value: function toggleLoading() {
+ // 切换loading状态
+ if (this.isLoading) {
+ var loadingButton = document.querySelector('.icon-loading');
+ loadingButton.outerHTML = "");
+ } else {
+ var copyButton = document.querySelector('.ch-icon-copy');
+ copyButton.outerHTML = '';
+ }
+
+ this.isLoading = !this.isLoading;
+ }
+ /**
+ * 响应点击事件
+ * 该按钮不会引发编辑区域的内容改动,所以不用处理用户在编辑区域的选中内容
+ * @param {Event} e 点击事件
+ */
+
+ }, {
+ key: "onClick",
+ value: function onClick(e) {
+ var _this2 = this;
+
+ this.toggleLoading();
+ var inlineCodeTheme = document.querySelector('.cherry').getAttribute('data-inline-code-theme');
+ var codeBlockTheme = document.querySelector('.cherry').getAttribute('data-code-block-theme');
+
+ var _this$computeStyle = this.computeStyle(),
+ mathStyle = _this$computeStyle.mathStyle,
+ echartStyle = _this$computeStyle.echartStyle,
+ cherryStyle = _this$computeStyle.cherryStyle;
+
+ var html = this.previewer.isPreviewerHidden() ? this.previewer.options.previewerCache.html : this.previewer.getValue(); // 将css样式以行内样式的形式插入到html内容里
+
+ this.adaptWechat(html).then(function (html) {
+ var _context7, _context8, _context9;
+
+ copyToClip(client(concat$5(_context7 = concat$5(_context8 = concat$5(_context9 = "\n
")).call(_context8, html, "
\n
")).call(_context7, mathStyle + echartStyle + cherryStyle)));
+
+ _this2.toggleLoading();
+ });
+ }
+ }]);
+
+ return Copy;
+ }(MenuBase);
+
+ function convertImgToBase64(url, callback, outputFormat) {
+ return new promise$7(function (resolve) {
+ var canvas =
+ /** @type {HTMLCanvasElement}*/
+ document.createElement('CANVAS');
+ var ctx = canvas.getContext('2d');
+ var img = new Image();
+ img.crossOrigin = 'Anonymous';
+
+ img.onload = function () {
+ canvas.height = img.height;
+ canvas.width = img.width;
+ ctx.drawImage(img, 0, 0);
+ var dataURL = canvas.toDataURL(outputFormat || 'image/png');
+ resolve(dataURL);
+ canvas = null;
+ };
+
+ img.src = url;
+ });
+ }
+
+ function _createSuper$1k(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1k(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1k() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 插入面板
+ */
+
+ var Panel$1 = /*#__PURE__*/function (_MenuBase) {
+ _inherits(Panel, _MenuBase);
+
+ var _super = _createSuper$1k(Panel);
+
+ function Panel($cherry) {
+ var _context, _context2, _context3, _context4, _context5;
+
+ var _this;
+
+ _classCallCheck(this, Panel);
+
+ _this = _super.call(this, $cherry);
+
+ _this.setName('panel', 'tips');
+
+ _this.panelRule = getPanelRule().reg;
+ _this.subMenuConfig = [{
+ iconName: 'tips',
+ name: 'tips',
+ onclick: bind$5(_context = _this.bindSubClick).call(_context, _assertThisInitialized(_this), 'primary')
+ }, {
+ iconName: 'info',
+ name: 'info',
+ onclick: bind$5(_context2 = _this.bindSubClick).call(_context2, _assertThisInitialized(_this), 'info')
+ }, {
+ iconName: 'warning',
+ name: 'warning',
+ onclick: bind$5(_context3 = _this.bindSubClick).call(_context3, _assertThisInitialized(_this), 'warning')
+ }, {
+ iconName: 'danger',
+ name: 'danger',
+ onclick: bind$5(_context4 = _this.bindSubClick).call(_context4, _assertThisInitialized(_this), 'danger')
+ }, {
+ iconName: 'success',
+ name: 'success',
+ onclick: bind$5(_context5 = _this.bindSubClick).call(_context5, _assertThisInitialized(_this), 'success')
+ }];
+ return _this;
+ }
+ /**
+ * 从字符串中找打面板的name
+ * @param {string} str
+ * @returns {string | false}
+ */
+
+
+ _createClass(Panel, [{
+ key: "$getNameFromStr",
+ value: function $getNameFromStr(str) {
+ var ret = false;
+ this.panelRule.lastIndex = 0;
+ str.replace(this.panelRule, function (match, preLines, name, content) {
+ var $name = /\s/.test(trim$3(name).call(name)) ? trim$3(name).call(name).replace(/\s.*$/, '') : name;
+ ret = $name ? trim$3($name).call($name).toLowerCase() : '';
+ return match;
+ });
+ return ret;
+ }
+ }, {
+ key: "$getTitle",
+ value: function $getTitle(str) {
+ this.panelRule.lastIndex = 0;
+ str.replace(this.panelRule, function (match, preLines, name, content) {
+ var $name = trim$3(name).call(name);
+
+ return /\s/.test($name) ? $name.replace(/[^\s]+\s/, '') : '';
+ });
+ return '';
+ }
+ /**
+ * 响应点击事件
+ * @param {string} selection 被用户选中的文本内容
+ * @param {string} shortKey 快捷键参数
+ * @returns {string} 回填到编辑器光标位置/选中文本区域的内容
+ */
+
+ }, {
+ key: "onClick",
+ value: function onClick(selection) {
+ var _this2 = this,
+ _context9,
+ _context10;
+
+ var shortKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
+ var $selection = getSelection(this.editor.editor, selection, 'line', true) || '内容';
+ var currentName = this.$getNameFromStr($selection);
+ var title = this.$getTitle($selection);
+
+ if (currentName === false) {
+ // 如果没有命中面板语法,则尝试扩大选区
+ this.getMoreSelection('::: ', '\n', function () {
+ var newSelection = _this2.editor.editor.getSelection();
+
+ var isMatch = _this2.$getNameFromStr(newSelection);
+
+ if (isMatch !== false) {
+ $selection = newSelection;
+ currentName = isMatch;
+ title = _this2.$getTitle(newSelection);
+ }
+
+ return isMatch !== false;
+ });
+ }
+
+ if (currentName !== false) {
+ // 如果命中了面板语法,则尝试去掉语法或者变更语法
+ if (currentName === shortKey) {
+ // 去掉面板语法
+ this.panelRule.lastIndex = 0;
+ return $selection.replace(this.panelRule, function (match, preLines, name, content) {
+ var _context6;
+
+ var $name = trim$3(name).call(name);
+
+ var $title = /\s/.test($name) ? $name.replace(/[^\s]+\s/, '') : '';
+ return concat$5(_context6 = "".concat($title, "\n")).call(_context6, content);
+ });
+ } // 修改name
+
+
+ this.registerAfterClickCb(function () {
+ _this2.setLessSelection('::: ', '\n');
+ });
+ this.panelRule.lastIndex = 0;
+ return $selection.replace(this.panelRule, function (match, preLines, name, content) {
+ var _context7, _context8;
+
+ var $name = trim$3(name).call(name);
+
+ var $title = /\s/.test($name) ? $name.replace(/[^\s]+\s/, '') : '';
+ return concat$5(_context7 = concat$5(_context8 = "::: ".concat(shortKey, " ")).call(_context8, $title, "\n")).call(_context7, content.replace(/\n+$/, ''), "\n:::");
+ });
+ }
+
+ this.registerAfterClickCb(function () {
+ _this2.setLessSelection('::: ', '\n');
+ });
+ $selection = $selection.replace(/^\n+/, '');
+
+ if (/\n/.test($selection)) {
+ if (!title) {
+ title = $selection.replace(/\n[\w\W]+$/, '');
+ $selection = $selection.replace(/^[^\n]+\n/, '');
+ }
+ } else {
+ title = title ? title : '标题';
+ }
+
+ return concat$5(_context9 = concat$5(_context10 = "::: ".concat(shortKey, " ")).call(_context10, title, "\n")).call(_context9, $selection, "\n:::").replace(/\n{2,}:::/g, '\n:::');
+ }
+ }]);
+
+ return Panel;
+ }(MenuBase);
+
+ function _createSuper$1l(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1l(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1l() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 插入对齐方式
+ */
+
+ var Justify = /*#__PURE__*/function (_Panel) {
+ _inherits(Justify, _Panel);
+
+ var _super = _createSuper$1l(Justify);
+
+ function Justify($cherry) {
+ var _context, _context2, _context3;
+
+ var _this;
+
+ _classCallCheck(this, Justify);
+
+ _this = _super.call(this, $cherry);
+
+ _this.setName('justify', 'justify');
+
+ _this.panelRule = getPanelRule().reg;
+ _this.subMenuConfig = [{
+ iconName: 'justifyLeft',
+ name: '左对齐',
+ onclick: bind$5(_context = _this.bindSubClick).call(_context, _assertThisInitialized(_this), 'left')
+ }, {
+ iconName: 'justifyCenter',
+ name: '居中',
+ onclick: bind$5(_context2 = _this.bindSubClick).call(_context2, _assertThisInitialized(_this), 'center')
+ }, {
+ iconName: 'justifyRight',
+ name: '右对齐',
+ onclick: bind$5(_context3 = _this.bindSubClick).call(_context3, _assertThisInitialized(_this), 'right')
+ }];
+ return _this;
+ }
+
+ _createClass(Justify, [{
+ key: "$getTitle",
+ value: function $getTitle() {
+ return ' ';
+ }
+ }]);
+
+ return Justify;
+ }(Panel$1);
+
+ function _createSuper$1m(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1m(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1m() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 插入手风琴
+ */
+
+ var Detail$1 = /*#__PURE__*/function (_MenuBase) {
+ _inherits(Detail, _MenuBase);
+
+ var _super = _createSuper$1m(Detail);
+
+ function Detail($cherry) {
+ var _this;
+
+ _classCallCheck(this, Detail);
+
+ _this = _super.call(this, $cherry);
+
+ _this.setName('detail', 'insertFlow');
+
+ _this.detailRule = getDetailRule().reg;
+ return _this;
+ }
+ /**
+ * 响应点击事件
+ * @param {string} selection 被用户选中的文本内容
+ * @returns {string} 回填到编辑器光标位置/选中文本区域的内容
+ */
+
+
+ _createClass(Detail, [{
+ key: "onClick",
+ value: function onClick(selection) {
+ var _this2 = this;
+
+ var $selection = getSelection(this.editor.editor, selection, 'line', true) || '点击展开更多\n内容\n++- 默认展开\n内容\n++ 默认收起\n内容';
+ this.detailRule.lastIndex = 0;
+
+ if (!this.detailRule.test($selection)) {
+ // 如果没有命中手风琴语法,则尝试扩大选区
+ this.getMoreSelection('+++ ', '\n', function () {
+ var newSelection = _this2.editor.editor.getSelection();
+
+ _this2.detailRule.lastIndex = 0;
+
+ var isMatch = _this2.detailRule.test(newSelection);
+
+ if (isMatch !== false) {
+ $selection = newSelection;
+ }
+
+ return isMatch !== false;
+ });
+ }
+
+ this.detailRule.lastIndex = 0;
+
+ if (this.detailRule.test($selection)) {
+ // 如果命中了手风琴语法,则去掉手风琴语法
+ this.detailRule.lastIndex = 0;
+ return $selection.replace(this.detailRule, function (match, preLines, isOpen, title, content) {
+ var _context;
+
+ return concat$5(_context = "".concat(title, "\n")).call(_context, content);
+ });
+ } // 去掉开头的空格
+
+
+ $selection = $selection.replace(/^\s+/, ''); // 如果选中的内容不包含换行,则强制增加一个换行
+
+ if (!/\n/.test($selection)) {
+ var _context2;
+
+ $selection = concat$5(_context2 = "".concat($selection, "\n")).call(_context2, $selection);
+ }
+
+ this.registerAfterClickCb(function () {
+ _this2.setLessSelection('+++ ', '\n');
+ });
+ return "+++ ".concat($selection, "\n+++").replace(/\n{2,}\+\+\+/g, '\n+++');
+ }
+ }]);
+
+ return Detail;
+ }(MenuBase);
+
+ function _createSuper$1n(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1n(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1n() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 打开draw.io画图对话框,点击确定后向编辑器插入图片语法
+ */
+
+ var DrawIo = /*#__PURE__*/function (_MenuBase) {
+ _inherits(DrawIo, _MenuBase);
+
+ var _super = _createSuper$1n(DrawIo);
+
+ function DrawIo($cherry) {
+ var _this;
+
+ _classCallCheck(this, DrawIo);
+
+ _this = _super.call(this, $cherry);
+
+ _this.setName('draw.io', 'draw.io');
+
+ _this.noIcon = true;
+ _this.drawioIframeUrl = $cherry.options.drawioIframeUrl;
+ return _this;
+ }
+ /**
+ * 响应点击事件
+ * @param {string} selection 被用户选中的文本内容
+ * @param {string} shortKey 快捷键参数,本函数不处理这个参数
+ * @returns {string} 回填到编辑器光标位置/选中文本区域的内容
+ */
+
+
+ _createClass(DrawIo, [{
+ key: "onClick",
+ value: function onClick(selection) {
+ var _this2 = this;
+
+ if (!this.drawioIframeUrl) {
+ // 如果没有配置drawio的编辑页URL,则直接失效
+ return selection;
+ }
+
+ if (this.hasCacheOnce()) {
+ var _context;
+
+ // @ts-ignore
+ var _this$getAndCleanCach = this.getAndCleanCacheOnce(),
+ xmlData = _this$getAndCleanCach.xmlData,
+ base64 = _this$getAndCleanCach.base64;
+
+ var begin = '{data-type=drawio data-xml=")).call(_context, encodeURI(xmlData), "}");
+
+ this.registerAfterClickCb(function () {
+ _this2.setLessSelection(begin, end);
+ });
+ return "".concat(begin, "\u5728\u9884\u89C8\u533A\u70B9\u51FB\u56FE\u7247\u91CD\u65B0\u7F16\u8F91draw.io").concat(end);
+ } // 插入图片,调用上传文件逻辑
+
+
+ drawioDialog(this.drawioIframeUrl, '', function (data) {
+ _this2.setCacheOnce(data);
+
+ _this2.fire(null);
+ });
+ this.updateMarkdown = false;
+ return selection;
+ }
+ }]);
+
+ return DrawIo;
+ }(MenuBase);
+
+ // 目前不支持按需动态加载
+ // 如果对CherryMarkdown构建后的文件大小有比较严格的要求,可以根据实际情况删减hook
+
+ var HookList = {
+ bold: Bold,
+ italic: Italic,
+ '|': Split,
+ strikethrough: Strikethrough$1,
+ sub: Sub$1,
+ sup: Sup$1,
+ header: Header$1,
+ insert: Insert,
+ list: List$1,
+ ol: Ol,
+ ul: Ul,
+ checklist: Checklist,
+ graph: Graph,
+ size: Size$1,
+ h1: H1,
+ h2: H2,
+ h3: H3,
+ color: Color$1,
+ quote: Quote,
+ quickTable: QuickTable,
+ togglePreview: TogglePreview,
+ code: Code,
+ codeTheme: CodeTheme,
+ "export": Export,
+ settings: Settings,
+ fullScreen: FullScreen,
+ mobilePreview: MobilePreview,
+ copy: Copy,
+ undo: Undo,
+ redo: Redo,
+ underline: Underline$1,
+ switchModel: SwitchModel,
+ image: Image$2,
+ audio: Audio,
+ video: Video,
+ br: Br$1,
+ hr: Hr$1,
+ formula: Formula,
+ link: Link$1,
+ table: Table$1,
+ toc: Toc$1,
+ lineTable: LineTable,
+ barTable: BrTable,
+ pdf: Pdf,
+ word: Word,
+ ruby: Ruby$1,
+ theme: Theme,
+ file: File,
+ panel: Panel$1,
+ justify: Justify,
+ detail: Detail$1,
+ drawIo: DrawIo,
+ chatgpt: ChatGpt
+ };
+
+ var HookCenter$1 = /*#__PURE__*/function () {
+ function HookCenter(toolbar) {
+ _classCallCheck(this, HookCenter);
+
+ this.toolbar = toolbar;
+ /**
+ * @type {{[key: string]: import('@/toolbars/MenuBase').default}} 保存所有菜单实例
+ */
+
+ this.hooks = {};
+ /**
+ * @type {string[]} 所有注册的菜单名称
+ */
+
+ this.allMenusName = [];
+ /**
+ * @type {string[]} 一级菜单的名称
+ */
+
+ this.level1MenusName = [];
+ /**
+ * @type {{ [parentName: string]: string[]}} 二级菜单的名称, e.g. {一级菜单名称: [二级菜单名称1, 二级菜单名称2]}
+ */
+
+ this.level2MenusName = {};
+ this.init();
+ }
+
+ _createClass(HookCenter, [{
+ key: "$newMenu",
+ value: function $newMenu(name) {
+ if (this.hooks[name]) {
+ return;
+ }
+
+ var _this$toolbar$options = this.toolbar.options,
+ $cherry = _this$toolbar$options.$cherry,
+ customMenu = _this$toolbar$options.customMenu;
+
+ if (HookList[name]) {
+ this.allMenusName.push(name);
+ this.hooks[name] = new HookList[name]($cherry);
+ } else if (customMenu !== undefined && customMenu !== null && customMenu[name]) {
+ this.allMenusName.push(name); // 如果是自定义菜单,传参兼容旧版
+
+ this.hooks[name] = new customMenu[name]($cherry);
+ }
+ }
+ /**
+ * 根据配置动态渲染、绑定工具栏
+ * @returns
+ */
+
+ }, {
+ key: "init",
+ value: function init() {
+ var _this = this;
+
+ var buttonConfig = this.toolbar.options.buttonConfig;
+
+ forEach$3(buttonConfig).call(buttonConfig, function (item) {
+ if (typeof item === 'string') {
+ _this.level1MenusName.push(item);
+
+ _this.$newMenu(item);
+ } else if (_typeof(item) === 'object') {
+ var keys = keys$3(item);
+
+ if (keys.length === 1) {
+ var _context;
+
+ // 只接受形如{ name: [ subMenu ] }的参数
+ var _keys = _slicedToArray(keys, 1),
+ name = _keys[0];
+
+ _this.level1MenusName.push(name);
+
+ _this.$newMenu(name);
+
+ _this.level2MenusName[name] = item[name];
+
+ forEach$3(_context = item[name]).call(_context, function (subItem) {
+ _this.$newMenu(subItem);
+ });
+ }
+ }
+ });
+ }
+ }]);
+
+ return HookCenter;
+ }();
+
+ var Toolbar = /*#__PURE__*/function () {
+ /**
+ * @type {Record} 外部获取 toolbarHandler
+ */
+ function Toolbar(options) {
+ _classCallCheck(this, Toolbar);
+
+ _defineProperty(this, "toolbarHandlers", {});
+
+ // 存储所有菜单的实例
+ this.menus = {}; // 存储所有快捷键的影射 {快捷键: 菜单名称}
+
+ this.shortcutKeyMap = {}; // 存储所有二级菜单面板
+
+ this.subMenus = {}; // 默认的菜单配置
+
+ this.options = {
+ dom: document.createElement('div'),
+ buttonConfig: ['bold'],
+ customMenu: [],
+ buttonRightConfig: []
+ };
+
+ assign$2(this.options, options);
+
+ this.$cherry = this.options.$cherry;
+ this.instanceId = this.$cherry.instanceId;
+ this.menus = new HookCenter$1(this);
+ this.drawMenus();
+ this.init();
+ }
+
+ _createClass(Toolbar, [{
+ key: "init",
+ value: function init() {
+ var _this = this;
+
+ this.collectShortcutKey();
+ this.collectToolbarHandler();
+ Event$1.on(this.instanceId, Event$1.Events.cleanAllSubMenus, function () {
+ return _this.hideAllSubMenu();
+ });
+ }
+ }, {
+ key: "previewOnly",
+ value: function previewOnly() {
+ this.options.dom.classList.add('preview-only');
+ Event$1.emit(this.instanceId, Event$1.Events.toolbarHide);
+ }
+ }, {
+ key: "showToolbar",
+ value: function showToolbar() {
+ this.options.dom.classList.remove('preview-only');
+ Event$1.emit(this.instanceId, Event$1.Events.toolbarShow);
+ }
+ }, {
+ key: "isHasLevel2Menu",
+ value: function isHasLevel2Menu(name) {
+ // FIXME: return boolean
+ return this.menus.level2MenusName[name];
+ }
+ }, {
+ key: "isHasConfigMenu",
+ value: function isHasConfigMenu(name) {
+ // FIXME: return boolean
+ return this.menus.hooks[name].subMenuConfig || [];
+ }
+ /**
+ * 判断是否有子菜单,目前有两种子菜单配置方式:1、通过`subMenuConfig`属性 2、通过`buttonConfig`配置属性
+ * @param {string} name
+ * @returns {boolean} 是否有子菜单
+ */
+
+ }, {
+ key: "isHasSubMenu",
+ value: function isHasSubMenu(name) {
+ return Boolean(this.isHasLevel2Menu(name) || this.isHasConfigMenu(name).length > 0);
+ }
+ /**
+ * 根据配置画出来一级工具栏
+ */
+
+ }, {
+ key: "drawMenus",
+ value: function drawMenus() {
+ var _context,
+ _this2 = this,
+ _this$options$buttonR;
+
+ var fragLeft = document.createDocumentFragment();
+ var toolbarLeft = createElement('div', 'toolbar-left');
+
+ forEach$3(_context = this.menus.level1MenusName).call(_context, function (name) {
+ var btn = _this2.menus.hooks[name].createBtn();
+
+ btn.addEventListener('click', function (event) {
+ _this2.onClick(event, name);
+ }, false);
+
+ if (_this2.isHasSubMenu(name)) {
+ btn.classList.add('cherry-toolbar-dropdown');
+ }
+
+ fragLeft.appendChild(btn);
+ });
+
+ toolbarLeft.appendChild(fragLeft);
+ this.options.dom.appendChild(toolbarLeft);
+ (_this$options$buttonR = this.options.buttonRightConfig) !== null && _this$options$buttonR !== void 0 && _this$options$buttonR.length ? this.drawRightMenus(this.options.buttonRightConfig) : null;
+ }
+ /**
+ * 根据配置画出来右侧一级工具栏
+ */
+
+ }, {
+ key: "drawRightMenus",
+ value: function drawRightMenus(buttonRightConfig) {
+ var _context2;
+
+ var toolbarRight = createElement('div', 'toolbar-right');
+ var fragRight = document.createDocumentFragment();
+ var rightOptions = {
+ options: {
+ $cherry: this.$cherry,
+ buttonConfig: buttonRightConfig,
+ customMenu: []
+ }
+ };
+ var rightMenus = new HookCenter$1(rightOptions);
+
+ forEach$3(_context2 = rightMenus.level1MenusName).call(_context2, function (name) {
+ var btn = rightMenus.hooks[name].createBtn();
+ btn.addEventListener('click', function (event) {
+ console.log('第一次点击');
+ rightMenus.hooks[name].fire(event, name);
+ }, false);
+ fragRight.appendChild(btn);
+ });
+
+ toolbarRight.appendChild(fragRight);
+ this.options.dom.appendChild(toolbarRight);
+ }
+ }, {
+ key: "setSubMenuPosition",
+ value: function setSubMenuPosition(menuObj, subMenuObj) {
+ var pos = menuObj.getMenuPosition();
+ subMenuObj.style.left = "".concat(pos.left + pos.width / 2, "px");
+ subMenuObj.style.top = "".concat(pos.top + pos.height, "px");
+ subMenuObj.style.position = menuObj.positionModel;
+ }
+ }, {
+ key: "drawSubMenus",
+ value: function drawSubMenus(name) {
+ var _this3 = this;
+
+ this.subMenus[name] = createElement('div', 'cherry-dropdown', {
+ name: name
+ });
+ this.setSubMenuPosition(this.menus.hooks[name], this.subMenus[name]); // 如果有配置的二级菜单
+
+ var level2MenusName = this.isHasLevel2Menu(name);
+
+ if (level2MenusName) {
+ forEach$3(level2MenusName).call(level2MenusName, function (level2Name) {
+ var subMenu = _this3.menus.hooks[level2Name];
+
+ if (subMenu !== undefined && typeof subMenu.createBtn === 'function') {
+ var btn = subMenu.createBtn(true); // 二级菜单的dom认定为一级菜单的
+
+ subMenu.dom = subMenu.dom ? subMenu.dom : _this3.menus.hooks[name].dom;
+ btn.addEventListener('click', function (event) {
+ return _this3.onClick(event, level2Name, true);
+ }, false);
+
+ _this3.subMenus[name].appendChild(btn);
+ }
+ });
+ } // 兼容旧版本配置的二级菜单
+
+
+ var subMenuConfig = this.isHasConfigMenu(name);
+
+ if (subMenuConfig.length > 0) {
+ forEach$3(subMenuConfig).call(subMenuConfig, function (config) {
+ var btn = _this3.menus.hooks[name].createSubBtnByConfig(config);
+
+ btn.addEventListener('click', function () {
+ return _this3.hideAllSubMenu();
+ }, false);
+
+ _this3.subMenus[name].appendChild(btn);
+ });
+ }
+
+ this.$cherry.wrapperDom.appendChild(this.subMenus[name]);
+ }
+ /**
+ * 处理点击事件
+ */
+
+ }, {
+ key: "onClick",
+ value: function onClick(event, name) {
+ var focusEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+ var menu = this.menus.hooks[name];
+
+ if (!menu) {
+ return;
+ }
+
+ if (this.isHasSubMenu(name) && !focusEvent) {
+ this.toggleSubMenu(name);
+ } else {
+ this.hideAllSubMenu();
+ menu.fire(event, name);
+ }
+ }
+ /**
+ * 展开/收起二级菜单
+ */
+
+ }, {
+ key: "toggleSubMenu",
+ value: function toggleSubMenu(name) {
+ if (!this.subMenus[name]) {
+ // 如果没有二级菜单,则先画出来,然后再显示
+ this.hideAllSubMenu();
+ this.drawSubMenus(name);
+ this.subMenus[name].style.display = 'block';
+ return;
+ }
+
+ if (this.subMenus[name].style.display === 'none') {
+ // 如果是隐藏的,则先隐藏所有二级菜单,再显示当前二级菜单
+ this.hideAllSubMenu();
+ this.subMenus[name].style.display = 'block';
+ this.setSubMenuPosition(this.menus.hooks[name], this.subMenus[name]);
+ } else {
+ // 如果是显示的,则隐藏当前二级菜单
+ this.subMenus[name].style.display = 'none';
+ }
+ }
+ /**
+ * 隐藏所有的二级菜单
+ */
+
+ }, {
+ key: "hideAllSubMenu",
+ value: function hideAllSubMenu() {
+ var _context3;
+
+ forEach$3(_context3 = this.$cherry.wrapperDom.querySelectorAll('.cherry-dropdown')).call(_context3, function (dom) {
+ dom.style.display = 'none';
+ });
+ }
+ /**
+ * 收集快捷键
+ */
+
+ }, {
+ key: "collectShortcutKey",
+ value: function collectShortcutKey() {
+ var _context4,
+ _this4 = this;
+
+ forEach$3(_context4 = this.menus.allMenusName).call(_context4, function (name) {
+ var _this4$menus$hooks$na;
+
+ (_this4$menus$hooks$na = _this4.menus.hooks[name].shortcutKeys) === null || _this4$menus$hooks$na === void 0 ? void 0 : forEach$3(_this4$menus$hooks$na).call(_this4$menus$hooks$na, function (key) {
+ _this4.shortcutKeyMap[key] = name;
+ });
+ });
+ }
+ }, {
+ key: "collectToolbarHandler",
+ value: function collectToolbarHandler() {
+ var _context5,
+ _this5 = this;
+
+ this.toolbarHandlers = reduce$3(_context5 = this.menus.allMenusName).call(_context5, function (handlerMap, name) {
+ var menuHook = _this5.menus.hooks[name];
+
+ if (!menuHook) {
+ return handlerMap;
+ }
+
+ handlerMap[name] = function (shortcut, _callback) {
+ if (typeof _callback === 'function') {
+ Logger.warn('MenuBase#onClick param callback is no longer supported. Please register the callback via MenuBase#registerAfterClickCb instead.');
+ }
+
+ menuHook.fire.call(menuHook, undefined, shortcut);
+ };
+
+ return handlerMap;
+ }, {});
+ }
+ /**
+ * 监测是否有对应的快捷键
+ * @param {KeyboardEvent} evt keydown 事件
+ * @returns {boolean} 是否有对应的快捷键
+ */
+
+ }, {
+ key: "matchShortcutKey",
+ value: function matchShortcutKey(evt) {
+ return !!this.shortcutKeyMap[this.getCurrentKey(evt)];
+ }
+ /**
+ * 触发对应快捷键的事件
+ * @param {KeyboardEvent} evt
+ */
+
+ }, {
+ key: "fireShortcutKey",
+ value: function fireShortcutKey(evt) {
+ var _this$menus$hooks$thi;
+
+ var currentKey = this.getCurrentKey(evt);
+ (_this$menus$hooks$thi = this.menus.hooks[this.shortcutKeyMap[currentKey]]) === null || _this$menus$hooks$thi === void 0 ? void 0 : _this$menus$hooks$thi.fire(evt, currentKey);
+ }
+ /**
+ * 格式化当前按键,mac下的command按键转换为ctrl
+ * @param {KeyboardEvent} event
+ * @returns
+ */
+
+ }, {
+ key: "getCurrentKey",
+ value: function getCurrentKey(event) {
+ var key = '';
+
+ if (event.ctrlKey) {
+ key += 'Ctrl-';
+ }
+
+ if (event.altKey) {
+ key += 'Alt-';
+ }
+
+ if (event.metaKey && mac) {
+ key += 'Ctrl-';
+ } // 如果存在shift键
+
+
+ if (event.shiftKey) {
+ key += "Shift-";
+ } // 如果还有第三个键 且不是 shift键
+
+
+ if (event.key && event.key.toLowerCase() !== 'shift') {
+ key += event.key.toLowerCase();
+ }
+
+ return key;
+ }
+ }]);
+
+ return Toolbar;
+ }();
+
+ function _createSuper$1o(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1o(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1o() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 在编辑区域选中文本时浮现的bubble工具栏
+ */
+
+ var Bubble = /*#__PURE__*/function (_Toolbar) {
+ _inherits(Bubble, _Toolbar);
+
+ var _super = _createSuper$1o(Bubble);
+
+ function Bubble() {
+ _classCallCheck(this, Bubble);
+
+ return _super.apply(this, arguments);
+ }
+
+ _createClass(Bubble, [{
+ key: "visible",
+ get: function get() {
+ var bubbleStyle = window.getComputedStyle(this.bubbleDom);
+ return bubbleStyle.display !== 'none' && bubbleStyle.visibility !== 'hidden';
+ },
+ set:
+ /**
+ * @type {'flex' | 'block'}
+ */
+ // constructor(options) {
+ // super(options);
+ // }
+ function set(visible) {
+ var bubbleStyle = window.getComputedStyle(this.bubbleDom);
+
+ if (visible) {
+ bubbleStyle.display === 'none' && (this.bubbleDom.style.display = Bubble.displayType); // bubbleStyle.visibility !== 'visible' && (this.bubbleBottom.style.visibility = 'visible');
+ } else {
+ bubbleStyle.display !== 'none' && (this.bubbleDom.style.display = 'none'); // bubbleStyle.visibility !== 'hidden' && (this.bubbleBottom.style.visibility = 'hidden');
+ }
+ }
+ }, {
+ key: "init",
+ value: function init() {
+ this.options.editor = this.$cherry.editor;
+ this.addSelectionChangeListener();
+ this.bubbleDom = this.options.dom;
+ this.editorDom = this.options.editor.getEditorDom();
+ this.initBubbleDom();
+ this.editorDom.querySelector('.CodeMirror').appendChild(this.bubbleDom);
+ }
+ /**
+ * 计算编辑区域的偏移量
+ * @returns {number} 编辑区域的滚动区域
+ */
+
+ }, {
+ key: "getScrollTop",
+ value: function getScrollTop() {
+ return this.options.editor.editor.getScrollInfo().top;
+ }
+ /**
+ * 当编辑区域滚动的时候自动隐藏bubble工具栏和子工具栏
+ */
+
+ }, {
+ key: "updatePositionWhenScroll",
+ value: function updatePositionWhenScroll() {
+ if (this.bubbleDom.style.display === Bubble.displayType) {
+ this.bubbleDom.style.marginTop = "".concat(_parseFloat$2(this.bubbleDom.dataset.scrollTop) - this.getScrollTop(), "px");
+ }
+ }
+ /**
+ * 根据高度计算bubble工具栏出现的位置的高度
+ * 根据宽度计算bubble工具栏出现的位置的left值,以及bubble工具栏三角箭头的left值
+ * @param {number} top 高度
+ * @param {number} width 选中文本内容的宽度
+ */
+
+ }, {
+ key: "showBubble",
+ value: function showBubble(top, width) {
+ if (!this.visible) {
+ this.visible = true;
+ this.bubbleDom.style.marginTop = '0';
+ this.bubbleDom.dataset.scrollTop = String(this.getScrollTop());
+ }
+
+ var positionLimit = this.editorDom.querySelector('.CodeMirror-lines').firstChild.getBoundingClientRect();
+ var editorPosition = this.editorDom.getBoundingClientRect();
+ var minLeft = positionLimit.left - editorPosition.left;
+ var maxLeft = positionLimit.width + minLeft;
+ var minTop = this.bubbleDom.offsetHeight * 2;
+ var $top = top;
+
+ if ($top < minTop) {
+ // 如果高度小于编辑器的顶部,则让bubble工具栏出现在选中文本的下放
+ $top += this.bubbleDom.offsetHeight - this.bubbleTop.getBoundingClientRect().height;
+ this.bubbleTop.style.display = 'block';
+ this.bubbleBottom.style.display = 'none';
+ } else {
+ // 反之出现在选中文本内容的上方
+ $top -= this.bubbleDom.offsetHeight + 2 * this.bubbleBottom.getBoundingClientRect().height;
+ this.bubbleTop.style.display = 'none';
+ this.bubbleBottom.style.display = 'block';
+ }
+
+ this.bubbleDom.style.top = "".concat($top, "px");
+ var left = width - this.bubbleDom.offsetWidth / 2;
+
+ if (left < minLeft) {
+ // 如果位置超过了编辑器的最左边,则控制bubble工具栏不超出编辑器最左边
+ // 同时bubble工具栏上的箭头尽量指向选中文本内容的中间位置
+ left = minLeft;
+ this.$setBubbleCursorPosition("".concat(width - minLeft, "px"));
+ } else if (left + this.bubbleDom.offsetWidth > maxLeft) {
+ // 如果位置超过了编辑器的最右边,则控制bubble工具栏不超出编辑器最右边
+ // 同时bubble工具栏上的箭头尽量指向选中文本内容的中间位置
+ left = maxLeft - this.bubbleDom.offsetWidth;
+ this.$setBubbleCursorPosition("".concat(width - left, "px"));
+ } else {
+ // 让bubble工具栏的箭头处于工具栏的中间位置
+ this.$setBubbleCursorPosition('50%');
+ } // 安全边距 20px
+
+
+ this.bubbleDom.style.left = "".concat(Math.max(20, left), "px");
+ }
+ }, {
+ key: "hideBubble",
+ value: function hideBubble() {
+ this.visible = false;
+ }
+ /**
+ * 控制bubble工具栏的箭头的位置
+ * @param {string} left 左偏移量
+ */
+
+ }, {
+ key: "$setBubbleCursorPosition",
+ value: function $setBubbleCursorPosition() {
+ var left = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '50%';
+
+ if (left === '50%') {
+ this.bubbleTop.style.left = '50%';
+ this.bubbleBottom.style.left = '50%';
+ } else {
+ var $left = _parseFloat$2(left) < 10 ? '10px' : left;
+ this.bubbleTop.style.left = $left;
+ this.bubbleBottom.style.left = $left;
+ }
+ }
+ }, {
+ key: "initBubbleDom",
+ value: function initBubbleDom() {
+ var top = document.createElement('div');
+ top.className = 'cherry-bubble-top';
+ var bottom = document.createElement('div');
+ bottom.className = 'cherry-bubble-bottom';
+ this.bubbleTop = top;
+ this.bubbleBottom = bottom;
+ this.bubbleDom.appendChild(top);
+ this.bubbleDom.appendChild(bottom); // 默认不可见
+
+ this.visible = false;
+ }
+ }, {
+ key: "getBubbleDom",
+ value: function getBubbleDom() {
+ return this.bubbleDom;
+ }
+ }, {
+ key: "addSelectionChangeListener",
+ value: function addSelectionChangeListener() {
+ var _this = this;
+
+ this.options.editor.addListener('change', function (codemirror) {
+ // 当编辑区内容变更时自动隐藏bubble工具栏
+ _this.hideBubble();
+ });
+ this.options.editor.addListener('refresh', function (codemirror) {
+ // 当编辑区内容刷新时自动隐藏bubble工具栏
+ _this.hideBubble();
+ });
+ this.options.editor.addListener('scroll', function (codemirror) {
+ // 当编辑区滚动时,需要实时同步bubble工具栏的位置
+ _this.updatePositionWhenScroll();
+ });
+ this.options.editor.addListener('beforeSelectionChange', function (codemirror, info) {
+ // 当编辑区选中内容改变时,需要展示/隐藏bubble工具栏,并计算工具栏位置
+ if (info.origin !== '*mouse' && (info.origin !== null || typeof info.origin === 'undefined')) {
+ return true;
+ }
+
+ if (!info.ranges[0]) {
+ return true;
+ }
+
+ var anchor = info.ranges[0].anchor.line * 1000000 + info.ranges[0].anchor.ch;
+ var head = info.ranges[0].head.line * 1000000 + info.ranges[0].head.ch;
+ var direction = 'asc';
+
+ if (anchor > head) {
+ direction = 'desc';
+ }
+
+ setTimeout$3(function () {
+ var selections = codemirror.getSelections();
+
+ if (selections.join('').length <= 0) {
+ _this.hideBubble();
+
+ return;
+ }
+
+ var selectedObjs = codemirror.getWrapperElement().getElementsByClassName('CodeMirror-selected');
+
+ var editorPosition = _this.editorDom.getBoundingClientRect();
+
+ var width = 0;
+ var top = 0;
+
+ if (_typeof(selectedObjs) !== 'object' || selectedObjs.length <= 0) {
+ _this.hideBubble();
+
+ return;
+ }
+
+ for (var key = 0; key < selectedObjs.length; key++) {
+ var one = selectedObjs[key];
+ var position = one.getBoundingClientRect();
+ var targetTop = position.top - editorPosition.top;
+
+ if (direction === 'asc') {
+ if (targetTop >= top) {
+ top = targetTop;
+ width = position.left - editorPosition.left + position.width / 2;
+ }
+ } else {
+ if (targetTop <= top || top <= 0) {
+ top = targetTop;
+ width = position.left - editorPosition.left + position.width / 2;
+ }
+ }
+ }
+
+ _this.showBubble(top, width);
+ }, 10);
+ });
+ }
+ }]);
+
+ return Bubble;
+ }(Toolbar);
+
+ _defineProperty(Bubble, "displayType", 'flex');
+
+ function _createSuper$1p(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1p(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1p() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 当光标处于编辑器新行起始位置时出现的浮动工具栏
+ */
+
+ var FloatMenu = /*#__PURE__*/function (_Toolbar) {
+ _inherits(FloatMenu, _Toolbar);
+
+ var _super = _createSuper$1p(FloatMenu);
+
+ function FloatMenu() {
+ _classCallCheck(this, FloatMenu);
+
+ return _super.apply(this, arguments);
+ }
+
+ _createClass(FloatMenu, [{
+ key: "init",
+ value: // constructor(options) {
+ // super(options);
+ // }
+ function init() {
+ this.editor = this.$cherry.editor;
+ this.editorDom = this.editor.getEditorDom();
+ this.editorDom.querySelector('.CodeMirror-scroll').appendChild(this.options.dom);
+ this.initAction();
+ }
+ }, {
+ key: "initAction",
+ value: function initAction() {
+ var self = this;
+ this.editor.addListener('cursorActivity', function (codemirror, evt) {
+ // 当编辑区光标位置改变时触发
+ self.cursorActivity(evt, codemirror);
+ });
+ this.editor.addListener('update', function (codemirror, evt) {
+ // 当编辑区内容改变时触发
+ self.cursorActivity(evt, codemirror);
+ });
+ this.editor.addListener('refresh', function (codemirror, evt) {
+ // 当编辑器刷新时触发
+ setTimeout$3(function () {
+ self.cursorActivity(evt, codemirror);
+ }, 0);
+ });
+ }
+ }, {
+ key: "update",
+ value: function update(evt, codeMirror) {
+ var pos = codeMirror.getCursor();
+
+ if (this.isHidden(pos.line, codeMirror)) {
+ this.options.dom.style.display = 'none';
+ return false;
+ }
+
+ this.options.dom.style.display = 'inline-block';
+ }
+ /**
+ * 当光标激活时触发,当光标处于行起始位置时展示float工具栏;反之隐藏
+ * @param {Event} evt
+ * @param {CodeMirror.Editor} codeMirror
+ * @returns
+ */
+
+ }, {
+ key: "cursorActivity",
+ value: function cursorActivity(evt, codeMirror) {
+ var pos = codeMirror.getCursor();
+ var codeMirrorLines = document.querySelector('.cherry-editor .CodeMirror-lines');
+
+ if (!codeMirrorLines) {
+ return false;
+ }
+
+ var computedLinesStyle = getComputedStyle(codeMirrorLines);
+
+ var codeWrapPaddingLeft = _parseFloat$2(computedLinesStyle.paddingLeft);
+
+ var codeWrapPaddingTop = _parseFloat$2(computedLinesStyle.paddingTop); // const cursorHandle = codeMirror.getLineHandle(pos.line);
+ // const verticalMiddle = cursorHandle.height * 1 / 2;
+
+
+ if (this.isHidden(pos.line, codeMirror)) {
+ this.options.dom.style.display = 'none';
+ return false;
+ }
+
+ this.options.dom.style.display = 'inline-block';
+ this.options.dom.style.left = "".concat(codeWrapPaddingLeft, "px");
+ this.options.dom.style.top = "".concat(this.getLineHeight(pos.line, codeMirror) + codeWrapPaddingTop, "px");
+ }
+ /**
+ * 判断是否需要隐藏Float工具栏
+ * 有选中内容,或者光标所在行有内容时隐藏float 工具栏
+ * @param {number} line
+ * @param {CodeMirror.Editor} codeMirror
+ * @returns {boolean} 是否需要隐藏float工具栏,true:需要隐藏
+ */
+
+ }, {
+ key: "isHidden",
+ value: function isHidden(line, codeMirror) {
+ var selections = codeMirror.getSelections();
+
+ if (selections.length > 1) {
+ return true;
+ }
+
+ var selection = codeMirror.getSelection();
+
+ if (selection.length > 0) {
+ return true;
+ }
+
+ if (codeMirror.getLine(line)) {
+ return true;
+ }
+
+ return false;
+ }
+ /**
+ * 获取对应行的行高度,用来让float 工具栏在该行保持垂直居中
+ * @param {number} line
+ * @param {CodeMirror.Editor} codeMirror
+ * @returns
+ */
+
+ }, {
+ key: "getLineHeight",
+ value: function getLineHeight(line, codeMirror) {
+ var height = 0;
+ codeMirror.getDoc().eachLine(0, line, function (line) {
+ height += line.height;
+ });
+ return height;
+ }
+ }]);
+
+ return FloatMenu;
+ }(Toolbar);
+
+ function _createSuper$1q(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1q(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1q() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /**
+ * 预览区域右侧悬浮的工具栏
+ * 推荐放置跟编辑区域完全无关的工具栏
+ * 比如复制预览区域内容、修改预览区域主题等
+ */
+
+ var Sidebar = /*#__PURE__*/function (_Toolbar) {
+ _inherits(Sidebar, _Toolbar);
+
+ var _super = _createSuper$1q(Sidebar);
+
+ function Sidebar() {
+ _classCallCheck(this, Sidebar);
+
+ return _super.apply(this, arguments);
+ }
+
+ return _createClass(Sidebar);
+ }(Toolbar);
+
+ /**
+ * This library modifies the diff-patch-match library by Neil Fraser
+ * by removing the patch and match functionality and certain advanced
+ * options in the diff function. The original license is as follows:
+ *
+ * ===
+ *
+ * Diff Match and Patch
+ *
+ * Copyright 2006 Google Inc.
+ * http://code.google.com/p/google-diff-match-patch/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+ /**
+ * The data structure representing a diff is an array of tuples:
+ * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
+ * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
+ */
+ var DIFF_DELETE = -1;
+ var DIFF_INSERT = 1;
+ var DIFF_EQUAL = 0;
+
+
+ /**
+ * Find the differences between two texts. Simplifies the problem by stripping
+ * any common prefix or suffix off the texts before diffing.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {Int|Object} [cursor_pos] Edit position in text1 or object with more info
+ * @return {Array} Array of diff tuples.
+ */
+ function diff_main(text1, text2, cursor_pos, _fix_unicode) {
+ // Check for equality
+ if (text1 === text2) {
+ if (text1) {
+ return [[DIFF_EQUAL, text1]];
+ }
+ return [];
+ }
+
+ if (cursor_pos != null) {
+ var editdiff = find_cursor_edit_diff(text1, text2, cursor_pos);
+ if (editdiff) {
+ return editdiff;
+ }
+ }
+
+ // Trim off common prefix (speedup).
+ var commonlength = diff_commonPrefix(text1, text2);
+ var commonprefix = text1.substring(0, commonlength);
+ text1 = text1.substring(commonlength);
+ text2 = text2.substring(commonlength);
+
+ // Trim off common suffix (speedup).
+ commonlength = diff_commonSuffix(text1, text2);
+ var commonsuffix = text1.substring(text1.length - commonlength);
+ text1 = text1.substring(0, text1.length - commonlength);
+ text2 = text2.substring(0, text2.length - commonlength);
+
+ // Compute the diff on the middle block.
+ var diffs = diff_compute_(text1, text2);
+
+ // Restore the prefix and suffix.
+ if (commonprefix) {
+ diffs.unshift([DIFF_EQUAL, commonprefix]);
+ }
+ if (commonsuffix) {
+ diffs.push([DIFF_EQUAL, commonsuffix]);
+ }
+ diff_cleanupMerge(diffs, _fix_unicode);
+ return diffs;
+ }
+
+ /**
+ * Find the differences between two texts. Assumes that the texts do not
+ * have any common prefix or suffix.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @return {Array} Array of diff tuples.
+ */
+ function diff_compute_(text1, text2) {
+ var diffs;
+
+ if (!text1) {
+ // Just add some text (speedup).
+ return [[DIFF_INSERT, text2]];
+ }
+
+ if (!text2) {
+ // Just delete some text (speedup).
+ return [[DIFF_DELETE, text1]];
+ }
+
+ var longtext = text1.length > text2.length ? text1 : text2;
+ var shorttext = text1.length > text2.length ? text2 : text1;
+ var i = longtext.indexOf(shorttext);
+ if (i !== -1) {
+ // Shorter text is inside the longer text (speedup).
+ diffs = [
+ [DIFF_INSERT, longtext.substring(0, i)],
+ [DIFF_EQUAL, shorttext],
+ [DIFF_INSERT, longtext.substring(i + shorttext.length)]
+ ];
+ // Swap insertions for deletions if diff is reversed.
+ if (text1.length > text2.length) {
+ diffs[0][0] = diffs[2][0] = DIFF_DELETE;
+ }
+ return diffs;
+ }
+
+ if (shorttext.length === 1) {
+ // Single character string.
+ // After the previous speedup, the character can't be an equality.
+ return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
+ }
+
+ // Check to see if the problem can be split in two.
+ var hm = diff_halfMatch_(text1, text2);
+ if (hm) {
+ // A half-match was found, sort out the return data.
+ var text1_a = hm[0];
+ var text1_b = hm[1];
+ var text2_a = hm[2];
+ var text2_b = hm[3];
+ var mid_common = hm[4];
+ // Send both pairs off for separate processing.
+ var diffs_a = diff_main(text1_a, text2_a);
+ var diffs_b = diff_main(text1_b, text2_b);
+ // Merge the results.
+ return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b);
+ }
+
+ return diff_bisect_(text1, text2);
+ }
+
+ /**
+ * Find the 'middle snake' of a diff, split the problem in two
+ * and return the recursively constructed diff.
+ * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @return {Array} Array of diff tuples.
+ * @private
+ */
+ function diff_bisect_(text1, text2) {
+ // Cache the text lengths to prevent multiple calls.
+ var text1_length = text1.length;
+ var text2_length = text2.length;
+ var max_d = Math.ceil((text1_length + text2_length) / 2);
+ var v_offset = max_d;
+ var v_length = 2 * max_d;
+ var v1 = new Array(v_length);
+ var v2 = new Array(v_length);
+ // Setting all elements to -1 is faster in Chrome & Firefox than mixing
+ // integers and undefined.
+ for (var x = 0; x < v_length; x++) {
+ v1[x] = -1;
+ v2[x] = -1;
+ }
+ v1[v_offset + 1] = 0;
+ v2[v_offset + 1] = 0;
+ var delta = text1_length - text2_length;
+ // If the total number of characters is odd, then the front path will collide
+ // with the reverse path.
+ var front = (delta % 2 !== 0);
+ // Offsets for start and end of k loop.
+ // Prevents mapping of space beyond the grid.
+ var k1start = 0;
+ var k1end = 0;
+ var k2start = 0;
+ var k2end = 0;
+ for (var d = 0; d < max_d; d++) {
+ // Walk the front path one step.
+ for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
+ var k1_offset = v_offset + k1;
+ var x1;
+ if (k1 === -d || (k1 !== d && v1[k1_offset - 1] < v1[k1_offset + 1])) {
+ x1 = v1[k1_offset + 1];
+ } else {
+ x1 = v1[k1_offset - 1] + 1;
+ }
+ var y1 = x1 - k1;
+ while (
+ x1 < text1_length && y1 < text2_length &&
+ text1.charAt(x1) === text2.charAt(y1)
+ ) {
+ x1++;
+ y1++;
+ }
+ v1[k1_offset] = x1;
+ if (x1 > text1_length) {
+ // Ran off the right of the graph.
+ k1end += 2;
+ } else if (y1 > text2_length) {
+ // Ran off the bottom of the graph.
+ k1start += 2;
+ } else if (front) {
+ var k2_offset = v_offset + delta - k1;
+ if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] !== -1) {
+ // Mirror x2 onto top-left coordinate system.
+ var x2 = text1_length - v2[k2_offset];
+ if (x1 >= x2) {
+ // Overlap detected.
+ return diff_bisectSplit_(text1, text2, x1, y1);
+ }
+ }
+ }
+ }
+
+ // Walk the reverse path one step.
+ for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
+ var k2_offset = v_offset + k2;
+ var x2;
+ if (k2 === -d || (k2 !== d && v2[k2_offset - 1] < v2[k2_offset + 1])) {
+ x2 = v2[k2_offset + 1];
+ } else {
+ x2 = v2[k2_offset - 1] + 1;
+ }
+ var y2 = x2 - k2;
+ while (
+ x2 < text1_length && y2 < text2_length &&
+ text1.charAt(text1_length - x2 - 1) === text2.charAt(text2_length - y2 - 1)
+ ) {
+ x2++;
+ y2++;
+ }
+ v2[k2_offset] = x2;
+ if (x2 > text1_length) {
+ // Ran off the left of the graph.
+ k2end += 2;
+ } else if (y2 > text2_length) {
+ // Ran off the top of the graph.
+ k2start += 2;
+ } else if (!front) {
+ var k1_offset = v_offset + delta - k2;
+ if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] !== -1) {
+ var x1 = v1[k1_offset];
+ var y1 = v_offset + x1 - k1_offset;
+ // Mirror x2 onto top-left coordinate system.
+ x2 = text1_length - x2;
+ if (x1 >= x2) {
+ // Overlap detected.
+ return diff_bisectSplit_(text1, text2, x1, y1);
+ }
+ }
+ }
+ }
+ }
+ // Diff took too long and hit the deadline or
+ // number of diffs equals number of characters, no commonality at all.
+ return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
+ }
+
+ /**
+ * Given the location of the 'middle snake', split the diff in two parts
+ * and recurse.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} x Index of split point in text1.
+ * @param {number} y Index of split point in text2.
+ * @return {Array} Array of diff tuples.
+ */
+ function diff_bisectSplit_(text1, text2, x, y) {
+ var text1a = text1.substring(0, x);
+ var text2a = text2.substring(0, y);
+ var text1b = text1.substring(x);
+ var text2b = text2.substring(y);
+
+ // Compute both diffs serially.
+ var diffs = diff_main(text1a, text2a);
+ var diffsb = diff_main(text1b, text2b);
+
+ return diffs.concat(diffsb);
+ }
+
+ /**
+ * Determine the common prefix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the start of each
+ * string.
+ */
+ function diff_commonPrefix(text1, text2) {
+ // Quick check for common null cases.
+ if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) {
+ return 0;
+ }
+ // Binary search.
+ // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+ var pointermin = 0;
+ var pointermax = Math.min(text1.length, text2.length);
+ var pointermid = pointermax;
+ var pointerstart = 0;
+ while (pointermin < pointermid) {
+ if (
+ text1.substring(pointerstart, pointermid) ==
+ text2.substring(pointerstart, pointermid)
+ ) {
+ pointermin = pointermid;
+ pointerstart = pointermin;
+ } else {
+ pointermax = pointermid;
+ }
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+ }
+
+ if (is_surrogate_pair_start(text1.charCodeAt(pointermid - 1))) {
+ pointermid--;
+ }
+
+ return pointermid;
+ }
+
+ /**
+ * Determine the common suffix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of each string.
+ */
+ function diff_commonSuffix(text1, text2) {
+ // Quick check for common null cases.
+ if (!text1 || !text2 || text1.slice(-1) !== text2.slice(-1)) {
+ return 0;
+ }
+ // Binary search.
+ // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+ var pointermin = 0;
+ var pointermax = Math.min(text1.length, text2.length);
+ var pointermid = pointermax;
+ var pointerend = 0;
+ while (pointermin < pointermid) {
+ if (
+ text1.substring(text1.length - pointermid, text1.length - pointerend) ==
+ text2.substring(text2.length - pointermid, text2.length - pointerend)
+ ) {
+ pointermin = pointermid;
+ pointerend = pointermin;
+ } else {
+ pointermax = pointermid;
+ }
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+ }
+
+ if (is_surrogate_pair_end(text1.charCodeAt(text1.length - pointermid))) {
+ pointermid--;
+ }
+
+ return pointermid;
+ }
+
+ /**
+ * Do the two texts share a substring which is at least half the length of the
+ * longer text?
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {Array.} Five element Array, containing the prefix of
+ * text1, the suffix of text1, the prefix of text2, the suffix of
+ * text2 and the common middle. Or null if there was no match.
+ */
+ function diff_halfMatch_(text1, text2) {
+ var longtext = text1.length > text2.length ? text1 : text2;
+ var shorttext = text1.length > text2.length ? text2 : text1;
+ if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
+ return null; // Pointless.
+ }
+
+ /**
+ * Does a substring of shorttext exist within longtext such that the substring
+ * is at least half the length of longtext?
+ * Closure, but does not reference any external variables.
+ * @param {string} longtext Longer string.
+ * @param {string} shorttext Shorter string.
+ * @param {number} i Start index of quarter length substring within longtext.
+ * @return {Array.} Five element Array, containing the prefix of
+ * longtext, the suffix of longtext, the prefix of shorttext, the suffix
+ * of shorttext and the common middle. Or null if there was no match.
+ * @private
+ */
+ function diff_halfMatchI_(longtext, shorttext, i) {
+ // Start with a 1/4 length substring at position i as a seed.
+ var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
+ var j = -1;
+ var best_common = '';
+ var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
+ while ((j = shorttext.indexOf(seed, j + 1)) !== -1) {
+ var prefixLength = diff_commonPrefix(
+ longtext.substring(i), shorttext.substring(j));
+ var suffixLength = diff_commonSuffix(
+ longtext.substring(0, i), shorttext.substring(0, j));
+ if (best_common.length < suffixLength + prefixLength) {
+ best_common = shorttext.substring(
+ j - suffixLength, j) + shorttext.substring(j, j + prefixLength);
+ best_longtext_a = longtext.substring(0, i - suffixLength);
+ best_longtext_b = longtext.substring(i + prefixLength);
+ best_shorttext_a = shorttext.substring(0, j - suffixLength);
+ best_shorttext_b = shorttext.substring(j + prefixLength);
+ }
+ }
+ if (best_common.length * 2 >= longtext.length) {
+ return [
+ best_longtext_a, best_longtext_b,
+ best_shorttext_a, best_shorttext_b, best_common
+ ];
+ } else {
+ return null;
+ }
+ }
+
+ // First check if the second quarter is the seed for a half-match.
+ var hm1 = diff_halfMatchI_(longtext, shorttext, Math.ceil(longtext.length / 4));
+ // Check again based on the third quarter.
+ var hm2 = diff_halfMatchI_(longtext, shorttext, Math.ceil(longtext.length / 2));
+ var hm;
+ if (!hm1 && !hm2) {
+ return null;
+ } else if (!hm2) {
+ hm = hm1;
+ } else if (!hm1) {
+ hm = hm2;
+ } else {
+ // Both matched. Select the longest.
+ hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
+ }
+
+ // A half-match was found, sort out the return data.
+ var text1_a, text1_b, text2_a, text2_b;
+ if (text1.length > text2.length) {
+ text1_a = hm[0];
+ text1_b = hm[1];
+ text2_a = hm[2];
+ text2_b = hm[3];
+ } else {
+ text2_a = hm[0];
+ text2_b = hm[1];
+ text1_a = hm[2];
+ text1_b = hm[3];
+ }
+ var mid_common = hm[4];
+ return [text1_a, text1_b, text2_a, text2_b, mid_common];
+ }
+
+ /**
+ * Reorder and merge like edit sections. Merge equalities.
+ * Any edit section can move as long as it doesn't cross an equality.
+ * @param {Array} diffs Array of diff tuples.
+ * @param {boolean} fix_unicode Whether to normalize to a unicode-correct diff
+ */
+ function diff_cleanupMerge(diffs, fix_unicode) {
+ diffs.push([DIFF_EQUAL, '']); // Add a dummy entry at the end.
+ var pointer = 0;
+ var count_delete = 0;
+ var count_insert = 0;
+ var text_delete = '';
+ var text_insert = '';
+ var commonlength;
+ while (pointer < diffs.length) {
+ if (pointer < diffs.length - 1 && !diffs[pointer][1]) {
+ diffs.splice(pointer, 1);
+ continue;
+ }
+ switch (diffs[pointer][0]) {
+ case DIFF_INSERT:
+
+ count_insert++;
+ text_insert += diffs[pointer][1];
+ pointer++;
+ break;
+ case DIFF_DELETE:
+ count_delete++;
+ text_delete += diffs[pointer][1];
+ pointer++;
+ break;
+ case DIFF_EQUAL:
+ var previous_equality = pointer - count_insert - count_delete - 1;
+ if (fix_unicode) {
+ // prevent splitting of unicode surrogate pairs. when fix_unicode is true,
+ // we assume that the old and new text in the diff are complete and correct
+ // unicode-encoded JS strings, but the tuple boundaries may fall between
+ // surrogate pairs. we fix this by shaving off stray surrogates from the end
+ // of the previous equality and the beginning of this equality. this may create
+ // empty equalities or a common prefix or suffix. for example, if AB and AC are
+ // emojis, `[[0, 'A'], [-1, 'BA'], [0, 'C']]` would turn into deleting 'ABAC' and
+ // inserting 'AC', and then the common suffix 'AC' will be eliminated. in this
+ // particular case, both equalities go away, we absorb any previous inequalities,
+ // and we keep scanning for the next equality before rewriting the tuples.
+ if (previous_equality >= 0 && ends_with_pair_start(diffs[previous_equality][1])) {
+ var stray = diffs[previous_equality][1].slice(-1);
+ diffs[previous_equality][1] = diffs[previous_equality][1].slice(0, -1);
+ text_delete = stray + text_delete;
+ text_insert = stray + text_insert;
+ if (!diffs[previous_equality][1]) {
+ // emptied out previous equality, so delete it and include previous delete/insert
+ diffs.splice(previous_equality, 1);
+ pointer--;
+ var k = previous_equality - 1;
+ if (diffs[k] && diffs[k][0] === DIFF_INSERT) {
+ count_insert++;
+ text_insert = diffs[k][1] + text_insert;
+ k--;
+ }
+ if (diffs[k] && diffs[k][0] === DIFF_DELETE) {
+ count_delete++;
+ text_delete = diffs[k][1] + text_delete;
+ k--;
+ }
+ previous_equality = k;
+ }
+ }
+ if (starts_with_pair_end(diffs[pointer][1])) {
+ var stray = diffs[pointer][1].charAt(0);
+ diffs[pointer][1] = diffs[pointer][1].slice(1);
+ text_delete += stray;
+ text_insert += stray;
+ }
+ }
+ if (pointer < diffs.length - 1 && !diffs[pointer][1]) {
+ // for empty equality not at end, wait for next equality
+ diffs.splice(pointer, 1);
+ break;
+ }
+ if (text_delete.length > 0 || text_insert.length > 0) {
+ // note that diff_commonPrefix and diff_commonSuffix are unicode-aware
+ if (text_delete.length > 0 && text_insert.length > 0) {
+ // Factor out any common prefixes.
+ commonlength = diff_commonPrefix(text_insert, text_delete);
+ if (commonlength !== 0) {
+ if (previous_equality >= 0) {
+ diffs[previous_equality][1] += text_insert.substring(0, commonlength);
+ } else {
+ diffs.splice(0, 0, [DIFF_EQUAL, text_insert.substring(0, commonlength)]);
+ pointer++;
+ }
+ text_insert = text_insert.substring(commonlength);
+ text_delete = text_delete.substring(commonlength);
+ }
+ // Factor out any common suffixes.
+ commonlength = diff_commonSuffix(text_insert, text_delete);
+ if (commonlength !== 0) {
+ diffs[pointer][1] =
+ text_insert.substring(text_insert.length - commonlength) + diffs[pointer][1];
+ text_insert = text_insert.substring(0, text_insert.length - commonlength);
+ text_delete = text_delete.substring(0, text_delete.length - commonlength);
+ }
+ }
+ // Delete the offending records and add the merged ones.
+ var n = count_insert + count_delete;
+ if (text_delete.length === 0 && text_insert.length === 0) {
+ diffs.splice(pointer - n, n);
+ pointer = pointer - n;
+ } else if (text_delete.length === 0) {
+ diffs.splice(pointer - n, n, [DIFF_INSERT, text_insert]);
+ pointer = pointer - n + 1;
+ } else if (text_insert.length === 0) {
+ diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete]);
+ pointer = pointer - n + 1;
+ } else {
+ diffs.splice(pointer - n, n, [DIFF_DELETE, text_delete], [DIFF_INSERT, text_insert]);
+ pointer = pointer - n + 2;
+ }
+ }
+ if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
+ // Merge this equality with the previous one.
+ diffs[pointer - 1][1] += diffs[pointer][1];
+ diffs.splice(pointer, 1);
+ } else {
+ pointer++;
+ }
+ count_insert = 0;
+ count_delete = 0;
+ text_delete = '';
+ text_insert = '';
+ break;
+ }
+ }
+ if (diffs[diffs.length - 1][1] === '') {
+ diffs.pop(); // Remove the dummy entry at the end.
+ }
+
+ // Second pass: look for single edits surrounded on both sides by equalities
+ // which can be shifted sideways to eliminate an equality.
+ // e.g: ABAC -> ABAC
+ var changes = false;
+ pointer = 1;
+ // Intentionally ignore the first and last element (don't need checking).
+ while (pointer < diffs.length - 1) {
+ if (diffs[pointer - 1][0] === DIFF_EQUAL &&
+ diffs[pointer + 1][0] === DIFF_EQUAL) {
+ // This is a single edit surrounded by equalities.
+ if (diffs[pointer][1].substring(diffs[pointer][1].length -
+ diffs[pointer - 1][1].length) === diffs[pointer - 1][1]) {
+ // Shift the edit over the previous equality.
+ diffs[pointer][1] = diffs[pointer - 1][1] +
+ diffs[pointer][1].substring(0, diffs[pointer][1].length -
+ diffs[pointer - 1][1].length);
+ diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
+ diffs.splice(pointer - 1, 1);
+ changes = true;
+ } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==
+ diffs[pointer + 1][1]) {
+ // Shift the edit over the next equality.
+ diffs[pointer - 1][1] += diffs[pointer + 1][1];
+ diffs[pointer][1] =
+ diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
+ diffs[pointer + 1][1];
+ diffs.splice(pointer + 1, 1);
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+ // If shifts were made, the diff needs reordering and another shift sweep.
+ if (changes) {
+ diff_cleanupMerge(diffs, fix_unicode);
+ }
+ }
+ function is_surrogate_pair_start(charCode) {
+ return charCode >= 0xD800 && charCode <= 0xDBFF;
+ }
+
+ function is_surrogate_pair_end(charCode) {
+ return charCode >= 0xDC00 && charCode <= 0xDFFF;
+ }
+
+ function starts_with_pair_end(str) {
+ return is_surrogate_pair_end(str.charCodeAt(0));
+ }
+
+ function ends_with_pair_start(str) {
+ return is_surrogate_pair_start(str.charCodeAt(str.length - 1));
+ }
+
+ function remove_empty_tuples(tuples) {
+ var ret = [];
+ for (var i = 0; i < tuples.length; i++) {
+ if (tuples[i][1].length > 0) {
+ ret.push(tuples[i]);
+ }
+ }
+ return ret;
+ }
+
+ function make_edit_splice(before, oldMiddle, newMiddle, after) {
+ if (ends_with_pair_start(before) || starts_with_pair_end(after)) {
+ return null;
+ }
+ return remove_empty_tuples([
+ [DIFF_EQUAL, before],
+ [DIFF_DELETE, oldMiddle],
+ [DIFF_INSERT, newMiddle],
+ [DIFF_EQUAL, after]
+ ]);
+ }
+
+ function find_cursor_edit_diff(oldText, newText, cursor_pos) {
+ // note: this runs after equality check has ruled out exact equality
+ var oldRange = typeof cursor_pos === 'number' ?
+ { index: cursor_pos, length: 0 } : cursor_pos.oldRange;
+ var newRange = typeof cursor_pos === 'number' ?
+ null : cursor_pos.newRange;
+ // take into account the old and new selection to generate the best diff
+ // possible for a text edit. for example, a text change from "xxx" to "xx"
+ // could be a delete or forwards-delete of any one of the x's, or the
+ // result of selecting two of the x's and typing "x".
+ var oldLength = oldText.length;
+ var newLength = newText.length;
+ if (oldRange.length === 0 && (newRange === null || newRange.length === 0)) {
+ // see if we have an insert or delete before or after cursor
+ var oldCursor = oldRange.index;
+ var oldBefore = oldText.slice(0, oldCursor);
+ var oldAfter = oldText.slice(oldCursor);
+ var maybeNewCursor = newRange ? newRange.index : null;
+ editBefore: {
+ // is this an insert or delete right before oldCursor?
+ var newCursor = oldCursor + newLength - oldLength;
+ if (maybeNewCursor !== null && maybeNewCursor !== newCursor) {
+ break editBefore;
+ }
+ if (newCursor < 0 || newCursor > newLength) {
+ break editBefore;
+ }
+ var newBefore = newText.slice(0, newCursor);
+ var newAfter = newText.slice(newCursor);
+ if (newAfter !== oldAfter) {
+ break editBefore;
+ }
+ var prefixLength = Math.min(oldCursor, newCursor);
+ var oldPrefix = oldBefore.slice(0, prefixLength);
+ var newPrefix = newBefore.slice(0, prefixLength);
+ if (oldPrefix !== newPrefix) {
+ break editBefore;
+ }
+ var oldMiddle = oldBefore.slice(prefixLength);
+ var newMiddle = newBefore.slice(prefixLength);
+ return make_edit_splice(oldPrefix, oldMiddle, newMiddle, oldAfter);
+ }
+ editAfter: {
+ // is this an insert or delete right after oldCursor?
+ if (maybeNewCursor !== null && maybeNewCursor !== oldCursor) {
+ break editAfter;
+ }
+ var cursor = oldCursor;
+ var newBefore = newText.slice(0, cursor);
+ var newAfter = newText.slice(cursor);
+ if (newBefore !== oldBefore) {
+ break editAfter;
+ }
+ var suffixLength = Math.min(oldLength - cursor, newLength - cursor);
+ var oldSuffix = oldAfter.slice(oldAfter.length - suffixLength);
+ var newSuffix = newAfter.slice(newAfter.length - suffixLength);
+ if (oldSuffix !== newSuffix) {
+ break editAfter;
+ }
+ var oldMiddle = oldAfter.slice(0, oldAfter.length - suffixLength);
+ var newMiddle = newAfter.slice(0, newAfter.length - suffixLength);
+ return make_edit_splice(oldBefore, oldMiddle, newMiddle, oldSuffix);
+ }
+ }
+ if (oldRange.length > 0 && newRange && newRange.length === 0) {
+ replaceRange: {
+ // see if diff could be a splice of the old selection range
+ var oldPrefix = oldText.slice(0, oldRange.index);
+ var oldSuffix = oldText.slice(oldRange.index + oldRange.length);
+ var prefixLength = oldPrefix.length;
+ var suffixLength = oldSuffix.length;
+ if (newLength < prefixLength + suffixLength) {
+ break replaceRange;
+ }
+ var newPrefix = newText.slice(0, prefixLength);
+ var newSuffix = newText.slice(newLength - suffixLength);
+ if (oldPrefix !== newPrefix || oldSuffix !== newSuffix) {
+ break replaceRange;
+ }
+ var oldMiddle = oldText.slice(prefixLength, oldLength - suffixLength);
+ var newMiddle = newText.slice(prefixLength, newLength - suffixLength);
+ return make_edit_splice(oldPrefix, oldMiddle, newMiddle, oldSuffix);
+ }
+ }
+
+ return null;
+ }
+
+ function diff$1(text1, text2, cursor_pos) {
+ // only pass fix_unicode=true at the top level, not when diff_main is
+ // recursively invoked
+ return diff_main(text1, text2, cursor_pos, true);
+ }
+
+ diff$1.INSERT = DIFF_INSERT;
+ diff$1.DELETE = DIFF_DELETE;
+ diff$1.EQUAL = DIFF_EQUAL;
+
+ var diff_1$2 = diff$1;
+
+ /**
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ /**
+ * 更新内容时保持光标不变
+ * @param {Number} pos 光标相对文档开头的偏移量
+ * @param {String} oldContent 变更前的内容
+ * @param {String} newContent 变更后的内容
+ * @returns {Number} newPos 新的光标偏移量
+ */
+
+ function getPosBydiffs(pos, oldContent, newContent) {
+ var diffs = diff_1$2(oldContent, newContent);
+ var newPos = pos;
+ var tmpPos = pos;
+
+ for (var i = 0; i < diffs.length; i++) {
+ var val = diffs[i];
+
+ if (tmpPos <= 0) {
+ return newPos;
+ }
+
+ var opType = val[0];
+ var opLength = val[1].length;
+
+ switch (opType) {
+ // 没有改变的内容
+ case diff_1$2.EQUAL:
+ if (tmpPos <= opLength) {
+ return newPos;
+ }
+
+ tmpPos -= opLength;
+ break;
+ // 删除的内容
+
+ case diff_1$2.DELETE:
+ if (tmpPos <= opLength) {
+ return newPos - opLength + tmpPos;
+ }
+
+ tmpPos -= opLength;
+ newPos -= opLength;
+ break;
+ // 新增的内容
+
+ case diff_1$2.INSERT:
+ newPos += opLength;
+ break;
+ }
+ }
+
+ return newPos;
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array == null ? 0 : array.length;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ var _arrayEach = arrayEach;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeKeys = _overArg(Object.keys, Object);
+
+ var _nativeKeys = nativeKeys;
+
+ /** Used for built-in method references. */
+ var objectProto$b = Object.prototype;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty$a = objectProto$b.hasOwnProperty;
+
+ /**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeys(object) {
+ if (!_isPrototype(object)) {
+ return _nativeKeys(object);
+ }
+ var result = [];
+ for (var key in Object(object)) {
+ if (hasOwnProperty$a.call(object, key) && key != 'constructor') {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ var _baseKeys = baseKeys;
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ function keys$8(object) {
+ return isArrayLike_1(object) ? _arrayLikeKeys(object) : _baseKeys(object);
+ }
+
+ var keys_1 = keys$8;
+
+ /**
+ * The base implementation of `_.assign` without support for multiple sources
+ * or `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+ function baseAssign(object, source) {
+ return object && _copyObject(source, keys_1(source), object);
+ }
+
+ var _baseAssign = baseAssign;
+
+ /**
+ * The base implementation of `_.assignIn` without support for multiple sources
+ * or `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+ function baseAssignIn(object, source) {
+ return object && _copyObject(source, keysIn_1(source), object);
+ }
+
+ var _baseAssignIn = baseAssignIn;
+
+ /**
+ * A specialized version of `_.filter` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {Array} Returns the new filtered array.
+ */
+ function arrayFilter(array, predicate) {
+ var index = -1,
+ length = array == null ? 0 : array.length,
+ resIndex = 0,
+ result = [];
+
+ while (++index < length) {
+ var value = array[index];
+ if (predicate(value, index, array)) {
+ result[resIndex++] = value;
+ }
+ }
+ return result;
+ }
+
+ var _arrayFilter = arrayFilter;
+
+ /**
+ * This method returns a new empty array.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.13.0
+ * @category Util
+ * @returns {Array} Returns the new empty array.
+ * @example
+ *
+ * var arrays = _.times(2, _.stubArray);
+ *
+ * console.log(arrays);
+ * // => [[], []]
+ *
+ * console.log(arrays[0] === arrays[1]);
+ * // => false
+ */
+ function stubArray() {
+ return [];
+ }
+
+ var stubArray_1 = stubArray;
+
+ /** Used for built-in method references. */
+ var objectProto$c = Object.prototype;
+
+ /** Built-in value references. */
+ var propertyIsEnumerable$2 = objectProto$c.propertyIsEnumerable;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeGetSymbols = Object.getOwnPropertySymbols;
+
+ /**
+ * Creates an array of the own enumerable symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of symbols.
+ */
+ var getSymbols = !nativeGetSymbols ? stubArray_1 : function(object) {
+ if (object == null) {
+ return [];
+ }
+ object = Object(object);
+ return _arrayFilter(nativeGetSymbols(object), function(symbol) {
+ return propertyIsEnumerable$2.call(object, symbol);
+ });
+ };
+
+ var _getSymbols = getSymbols;
+
+ /**
+ * Copies own symbols of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy symbols from.
+ * @param {Object} [object={}] The object to copy symbols to.
+ * @returns {Object} Returns `object`.
+ */
+ function copySymbols(source, object) {
+ return _copyObject(source, _getSymbols(source), object);
+ }
+
+ var _copySymbols = copySymbols;
+
+ /**
+ * Appends the elements of `values` to `array`.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to append.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayPush(array, values) {
+ var index = -1,
+ length = values.length,
+ offset = array.length;
+
+ while (++index < length) {
+ array[offset + index] = values[index];
+ }
+ return array;
+ }
+
+ var _arrayPush = arrayPush;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeGetSymbols$1 = Object.getOwnPropertySymbols;
+
+ /**
+ * Creates an array of the own and inherited enumerable symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of symbols.
+ */
+ var getSymbolsIn = !nativeGetSymbols$1 ? stubArray_1 : function(object) {
+ var result = [];
+ while (object) {
+ _arrayPush(result, _getSymbols(object));
+ object = _getPrototype(object);
+ }
+ return result;
+ };
+
+ var _getSymbolsIn = getSymbolsIn;
+
+ /**
+ * Copies own and inherited symbols of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy symbols from.
+ * @param {Object} [object={}] The object to copy symbols to.
+ * @returns {Object} Returns `object`.
+ */
+ function copySymbolsIn(source, object) {
+ return _copyObject(source, _getSymbolsIn(source), object);
+ }
+
+ var _copySymbolsIn = copySymbolsIn;
+
+ /**
+ * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+ * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+ * symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @param {Function} symbolsFunc The function to get the symbols of `object`.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+ var result = keysFunc(object);
+ return isArray_1(object) ? result : _arrayPush(result, symbolsFunc(object));
+ }
+
+ var _baseGetAllKeys = baseGetAllKeys;
+
+ /**
+ * Creates an array of own enumerable property names and symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function getAllKeys(object) {
+ return _baseGetAllKeys(object, keys_1, _getSymbols);
+ }
+
+ var _getAllKeys = getAllKeys;
+
+ /**
+ * Creates an array of own and inherited enumerable property names and
+ * symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function getAllKeysIn(object) {
+ return _baseGetAllKeys(object, keysIn_1, _getSymbolsIn);
+ }
+
+ var _getAllKeysIn = getAllKeysIn;
+
+ /* Built-in method references that are verified to be native. */
+ var DataView$1 = _getNative(_root, 'DataView');
+
+ var _DataView = DataView$1;
+
+ /* Built-in method references that are verified to be native. */
+ var Promise$2 = _getNative(_root, 'Promise');
+
+ var _Promise = Promise$2;
+
+ /* Built-in method references that are verified to be native. */
+ var Set$1 = _getNative(_root, 'Set');
+
+ var _Set = Set$1;
+
+ /* Built-in method references that are verified to be native. */
+ var WeakMap$2 = _getNative(_root, 'WeakMap');
+
+ var _WeakMap = WeakMap$2;
+
+ /** `Object#toString` result references. */
+ var mapTag$1 = '[object Map]',
+ objectTag$2 = '[object Object]',
+ promiseTag = '[object Promise]',
+ setTag$1 = '[object Set]',
+ weakMapTag$1 = '[object WeakMap]';
+
+ var dataViewTag$1 = '[object DataView]';
+
+ /** Used to detect maps, sets, and weakmaps. */
+ var dataViewCtorString = _toSource(_DataView),
+ mapCtorString = _toSource(_Map),
+ promiseCtorString = _toSource(_Promise),
+ setCtorString = _toSource(_Set),
+ weakMapCtorString = _toSource(_WeakMap);
+
+ /**
+ * Gets the `toStringTag` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ var getTag = _baseGetTag;
+
+ // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
+ if ((_DataView && getTag(new _DataView(new ArrayBuffer(1))) != dataViewTag$1) ||
+ (_Map && getTag(new _Map) != mapTag$1) ||
+ (_Promise && getTag(_Promise.resolve()) != promiseTag) ||
+ (_Set && getTag(new _Set) != setTag$1) ||
+ (_WeakMap && getTag(new _WeakMap) != weakMapTag$1)) {
+ getTag = function(value) {
+ var result = _baseGetTag(value),
+ Ctor = result == objectTag$2 ? value.constructor : undefined,
+ ctorString = Ctor ? _toSource(Ctor) : '';
+
+ if (ctorString) {
+ switch (ctorString) {
+ case dataViewCtorString: return dataViewTag$1;
+ case mapCtorString: return mapTag$1;
+ case promiseCtorString: return promiseTag;
+ case setCtorString: return setTag$1;
+ case weakMapCtorString: return weakMapTag$1;
+ }
+ }
+ return result;
+ };
+ }
+
+ var _getTag = getTag;
+
+ /** Used for built-in method references. */
+ var objectProto$d = Object.prototype;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty$b = objectProto$d.hasOwnProperty;
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = new array.constructor(length);
+
+ // Add properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty$b.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ var _initCloneArray = initCloneArray;
+
+ /**
+ * Creates a clone of `dataView`.
+ *
+ * @private
+ * @param {Object} dataView The data view to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned data view.
+ */
+ function cloneDataView(dataView, isDeep) {
+ var buffer = isDeep ? _cloneArrayBuffer(dataView.buffer) : dataView.buffer;
+ return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
+ }
+
+ var _cloneDataView = cloneDataView;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /**
+ * Creates a clone of `regexp`.
+ *
+ * @private
+ * @param {Object} regexp The regexp to clone.
+ * @returns {Object} Returns the cloned regexp.
+ */
+ function cloneRegExp(regexp) {
+ var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
+ result.lastIndex = regexp.lastIndex;
+ return result;
+ }
+
+ var _cloneRegExp = cloneRegExp;
+
+ /** Used to convert symbols to primitives and strings. */
+ var symbolProto$1 = _Symbol ? _Symbol.prototype : undefined,
+ symbolValueOf = symbolProto$1 ? symbolProto$1.valueOf : undefined;
+
+ /**
+ * Creates a clone of the `symbol` object.
+ *
+ * @private
+ * @param {Object} symbol The symbol object to clone.
+ * @returns {Object} Returns the cloned symbol object.
+ */
+ function cloneSymbol(symbol) {
+ return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
+ }
+
+ var _cloneSymbol = cloneSymbol;
+
+ /** `Object#toString` result references. */
+ var boolTag$1 = '[object Boolean]',
+ dateTag$1 = '[object Date]',
+ mapTag$2 = '[object Map]',
+ numberTag$1 = '[object Number]',
+ regexpTag$1 = '[object RegExp]',
+ setTag$2 = '[object Set]',
+ stringTag$1 = '[object String]',
+ symbolTag$1 = '[object Symbol]';
+
+ var arrayBufferTag$1 = '[object ArrayBuffer]',
+ dataViewTag$2 = '[object DataView]',
+ float32Tag$1 = '[object Float32Array]',
+ float64Tag$1 = '[object Float64Array]',
+ int8Tag$1 = '[object Int8Array]',
+ int16Tag$1 = '[object Int16Array]',
+ int32Tag$1 = '[object Int32Array]',
+ uint8Tag$1 = '[object Uint8Array]',
+ uint8ClampedTag$1 = '[object Uint8ClampedArray]',
+ uint16Tag$1 = '[object Uint16Array]',
+ uint32Tag$1 = '[object Uint32Array]';
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag$1:
+ return _cloneArrayBuffer(object);
+
+ case boolTag$1:
+ case dateTag$1:
+ return new Ctor(+object);
+
+ case dataViewTag$2:
+ return _cloneDataView(object, isDeep);
+
+ case float32Tag$1: case float64Tag$1:
+ case int8Tag$1: case int16Tag$1: case int32Tag$1:
+ case uint8Tag$1: case uint8ClampedTag$1: case uint16Tag$1: case uint32Tag$1:
+ return _cloneTypedArray(object, isDeep);
+
+ case mapTag$2:
+ return new Ctor;
+
+ case numberTag$1:
+ case stringTag$1:
+ return new Ctor(object);
+
+ case regexpTag$1:
+ return _cloneRegExp(object);
+
+ case setTag$2:
+ return new Ctor;
+
+ case symbolTag$1:
+ return _cloneSymbol(object);
+ }
+ }
+
+ var _initCloneByTag = initCloneByTag;
+
+ /** `Object#toString` result references. */
+ var mapTag$3 = '[object Map]';
+
+ /**
+ * The base implementation of `_.isMap` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+ */
+ function baseIsMap(value) {
+ return isObjectLike_1(value) && _getTag(value) == mapTag$3;
+ }
+
+ var _baseIsMap = baseIsMap;
+
+ /* Node.js helper references. */
+ var nodeIsMap = _nodeUtil && _nodeUtil.isMap;
+
+ /**
+ * Checks if `value` is classified as a `Map` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.3.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+ * @example
+ *
+ * _.isMap(new Map);
+ * // => true
+ *
+ * _.isMap(new WeakMap);
+ * // => false
+ */
+ var isMap = nodeIsMap ? _baseUnary(nodeIsMap) : _baseIsMap;
+
+ var isMap_1 = isMap;
+
+ /** `Object#toString` result references. */
+ var setTag$3 = '[object Set]';
+
+ /**
+ * The base implementation of `_.isSet` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+ */
+ function baseIsSet(value) {
+ return isObjectLike_1(value) && _getTag(value) == setTag$3;
+ }
+
+ var _baseIsSet = baseIsSet;
+
+ /* Node.js helper references. */
+ var nodeIsSet = _nodeUtil && _nodeUtil.isSet;
+
+ /**
+ * Checks if `value` is classified as a `Set` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.3.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+ * @example
+ *
+ * _.isSet(new Set);
+ * // => true
+ *
+ * _.isSet(new WeakSet);
+ * // => false
+ */
+ var isSet = nodeIsSet ? _baseUnary(nodeIsSet) : _baseIsSet;
+
+ var isSet_1 = isSet;
+
+ /** Used to compose bitmasks for cloning. */
+ var CLONE_DEEP_FLAG = 1,
+ CLONE_FLAT_FLAG = 2,
+ CLONE_SYMBOLS_FLAG = 4;
+
+ /** `Object#toString` result references. */
+ var argsTag$2 = '[object Arguments]',
+ arrayTag$1 = '[object Array]',
+ boolTag$2 = '[object Boolean]',
+ dateTag$2 = '[object Date]',
+ errorTag$1 = '[object Error]',
+ funcTag$2 = '[object Function]',
+ genTag$1 = '[object GeneratorFunction]',
+ mapTag$4 = '[object Map]',
+ numberTag$2 = '[object Number]',
+ objectTag$3 = '[object Object]',
+ regexpTag$2 = '[object RegExp]',
+ setTag$4 = '[object Set]',
+ stringTag$2 = '[object String]',
+ symbolTag$2 = '[object Symbol]',
+ weakMapTag$2 = '[object WeakMap]';
+
+ var arrayBufferTag$2 = '[object ArrayBuffer]',
+ dataViewTag$3 = '[object DataView]',
+ float32Tag$2 = '[object Float32Array]',
+ float64Tag$2 = '[object Float64Array]',
+ int8Tag$2 = '[object Int8Array]',
+ int16Tag$2 = '[object Int16Array]',
+ int32Tag$2 = '[object Int32Array]',
+ uint8Tag$2 = '[object Uint8Array]',
+ uint8ClampedTag$2 = '[object Uint8ClampedArray]',
+ uint16Tag$2 = '[object Uint16Array]',
+ uint32Tag$2 = '[object Uint32Array]';
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag$2] = cloneableTags[arrayTag$1] =
+ cloneableTags[arrayBufferTag$2] = cloneableTags[dataViewTag$3] =
+ cloneableTags[boolTag$2] = cloneableTags[dateTag$2] =
+ cloneableTags[float32Tag$2] = cloneableTags[float64Tag$2] =
+ cloneableTags[int8Tag$2] = cloneableTags[int16Tag$2] =
+ cloneableTags[int32Tag$2] = cloneableTags[mapTag$4] =
+ cloneableTags[numberTag$2] = cloneableTags[objectTag$3] =
+ cloneableTags[regexpTag$2] = cloneableTags[setTag$4] =
+ cloneableTags[stringTag$2] = cloneableTags[symbolTag$2] =
+ cloneableTags[uint8Tag$2] = cloneableTags[uint8ClampedTag$2] =
+ cloneableTags[uint16Tag$2] = cloneableTags[uint32Tag$2] = true;
+ cloneableTags[errorTag$1] = cloneableTags[funcTag$2] =
+ cloneableTags[weakMapTag$2] = false;
+
+ /**
+ * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+ * traversed objects.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} bitmask The bitmask flags.
+ * 1 - Deep clone
+ * 2 - Flatten inherited properties
+ * 4 - Clone symbols
+ * @param {Function} [customizer] The function to customize cloning.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The parent object of `value`.
+ * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, bitmask, customizer, key, object, stack) {
+ var result,
+ isDeep = bitmask & CLONE_DEEP_FLAG,
+ isFlat = bitmask & CLONE_FLAT_FLAG,
+ isFull = bitmask & CLONE_SYMBOLS_FLAG;
+
+ if (customizer) {
+ result = object ? customizer(value, key, object, stack) : customizer(value);
+ }
+ if (result !== undefined) {
+ return result;
+ }
+ if (!isObject_1(value)) {
+ return value;
+ }
+ var isArr = isArray_1(value);
+ if (isArr) {
+ result = _initCloneArray(value);
+ if (!isDeep) {
+ return _copyArray(value, result);
+ }
+ } else {
+ var tag = _getTag(value),
+ isFunc = tag == funcTag$2 || tag == genTag$1;
+
+ if (isBuffer_1(value)) {
+ return _cloneBuffer(value, isDeep);
+ }
+ if (tag == objectTag$3 || tag == argsTag$2 || (isFunc && !object)) {
+ result = (isFlat || isFunc) ? {} : _initCloneObject(value);
+ if (!isDeep) {
+ return isFlat
+ ? _copySymbolsIn(value, _baseAssignIn(result, value))
+ : _copySymbols(value, _baseAssign(result, value));
+ }
+ } else {
+ if (!cloneableTags[tag]) {
+ return object ? value : {};
+ }
+ result = _initCloneByTag(value, tag, isDeep);
+ }
+ }
+ // Check for circular references and return its corresponding clone.
+ stack || (stack = new _Stack);
+ var stacked = stack.get(value);
+ if (stacked) {
+ return stacked;
+ }
+ stack.set(value, result);
+
+ if (isSet_1(value)) {
+ value.forEach(function(subValue) {
+ result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
+ });
+ } else if (isMap_1(value)) {
+ value.forEach(function(subValue, key) {
+ result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
+ });
+ }
+
+ var keysFunc = isFull
+ ? (isFlat ? _getAllKeysIn : _getAllKeys)
+ : (isFlat ? keysIn_1 : keys_1);
+
+ var props = isArr ? undefined : keysFunc(value);
+ _arrayEach(props || value, function(subValue, key) {
+ if (props) {
+ key = subValue;
+ subValue = value[key];
+ }
+ // Recursively populate clone (susceptible to call stack limits).
+ _assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
+ });
+ return result;
+ }
+
+ var _baseClone = baseClone;
+
+ /** Used to compose bitmasks for cloning. */
+ var CLONE_DEEP_FLAG$1 = 1,
+ CLONE_SYMBOLS_FLAG$1 = 4;
+
+ /**
+ * This method is like `_.clone` except that it recursively clones `value`.
+ *
+ * @static
+ * @memberOf _
+ * @since 1.0.0
+ * @category Lang
+ * @param {*} value The value to recursively clone.
+ * @returns {*} Returns the deep cloned value.
+ * @see _.clone
+ * @example
+ *
+ * var objects = [{ 'a': 1 }, { 'b': 2 }];
+ *
+ * var deep = _.cloneDeep(objects);
+ * console.log(deep[0] === objects[0]);
+ * // => false
+ */
+ function cloneDeep(value) {
+ return _baseClone(value, CLONE_DEEP_FLAG$1 | CLONE_SYMBOLS_FLAG$1);
+ }
+
+ var cloneDeep_1 = cloneDeep;
+
+ /**
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ var callbacks = {
+ /**
+ * 全局的URL处理器
+ * @param {string} url 来源url
+ * @param {'image'|'audio'|'video'|'autolink'|'link'} srcType 来源类型
+ * @returns
+ */
+ urlProcessor: function urlProcessor(url, srcType) {
+ return url;
+ },
+ fileUpload: function fileUpload(file, callback) {
+ if (/video/i.test(file.type)) {
+ callback('images/demo-dog.png', {
+ name: "".concat(file.name.replace(/\.[^.]+$/, '')),
+ poster: 'images/demo-dog.png?poster=true',
+ isBorder: true,
+ isShadow: true,
+ isRadius: true
+ });
+ } else {
+ callback('images/demo-dog.png', {
+ name: "".concat(file.name.replace(/\.[^.]+$/, '')),
+ isShadow: true
+ });
+ }
+ },
+ afterChange: function afterChange(text, html) {},
+ afterInit: function afterInit(text, html) {},
+ beforeImageMounted: function beforeImageMounted(srcProp, src) {
+ return {
+ srcProp: srcProp,
+ src: src
+ };
+ },
+ onClickPreview: function onClickPreview(event) {},
+ onCopyCode: function onCopyCode(event, code) {
+ // 阻止默认的粘贴事件
+ // return false;
+ // 对复制内容进行额外处理
+ return code;
+ },
+ // 获取中文的拼音
+ changeString2Pinyin: function changeString2Pinyin(string) {
+ /**
+ * 推荐使用这个组件:https://github.com/liu11hao11/pinyin_js
+ *
+ * 可以在 ../scripts/pinyin/pinyin_dist.js 里直接引用
+ */
+ return string;
+ }
+ };
+ /** @type {Partial} */
+
+ var defaultConfig = {
+ // 第三方包
+ externals: {// externals
+ },
+ // chatGpt的openai配置
+ openai: {
+ apiKey: '',
+ // apiKey
+ // proxy: {
+ // host: '127.0.0.1',
+ // port: '7890',
+ // }, // http & https代理配置
+ ignoreError: false // 是否忽略请求失败,默认忽略
+
+ },
+ // 解析引擎配置
+ engine: {
+ // 全局配置
+ global: {
+ // 是否启用经典换行逻辑
+ // true:一个换行会被忽略,两个以上连续换行会分割成段落,
+ // false: 一个换行会转成
,两个连续换行会分割成段落,三个以上连续换行会转成
并分割段落
+ classicBr: false,
+
+ /**
+ * 全局的URL处理器
+ * @param {string} url 来源url
+ * @param {'image'|'audio'|'video'|'autolink'|'link'} srcType 来源类型
+ * @returns
+ */
+ urlProcessor: callbacks.urlProcessor,
+
+ /**
+ * 额外允许渲染的html标签
+ * 标签以英文竖线分隔,如:htmlWhiteList: 'iframe|script|style'
+ * 默认为空,默认允许渲染的html见src/utils/sanitize.js whiteList 属性
+ * 需要注意:
+ * - 启用iframe、script等标签后,会产生xss注入,请根据实际场景判断是否需要启用
+ * - 一般编辑权限可控的场景(如api文档系统)可以允许iframe、script等标签
+ */
+ htmlWhiteList: ''
+ },
+ // 内置语法配置
+ syntax: {
+ // 语法开关
+ // 'hookName': false,
+ // 语法配置
+ // 'hookName': {
+ //
+ // }
+ link: {
+ /** 生成的标签追加target属性的默认值 空:在标签里不会追加target属性, _blank:在标签里追加target="_blank"属性 */
+ target: '',
+
+ /** 生成的标签追加rel属性的默认值 空:在标签里不会追加rel属性, nofollow:在标签里追加rel="nofollow:在"属性*/
+ rel: ''
+ },
+ autoLink: {
+ /** 生成的标签追加target属性的默认值 空:在标签里不会追加target属性, _blank:在标签里追加target="_blank"属性 */
+ target: '',
+
+ /** 生成的标签追加rel属性的默认值 空:在标签里不会追加rel属性, nofollow:在标签里追加rel="nofollow:在"属性*/
+ rel: '',
+
+ /** 是否开启短链接 */
+ enableShortLink: true,
+
+ /** 短链接长度 */
+ shortLinkLength: 20
+ },
+ list: {
+ listNested: false,
+ // 同级列表类型转换后变为子级
+ indentSpace: 2 // 默认2个空格缩进
+
+ },
+ table: {
+ enableChart: false // chartRenderEngine: EChartsTableEngine,
+ // externals: ['echarts'],
+
+ },
+ inlineCode: {
+ theme: 'red'
+ },
+ codeBlock: {
+ theme: 'dark',
+ // 默认为深色主题
+ wrap: true,
+ // 超出长度是否换行,false则显示滚动条
+ lineNumber: true,
+ // 默认显示行号
+ copyCode: true,
+ // 是否显示“复制”按钮
+ customRenderer: {// 自定义语法渲染器
+ },
+ mermaid: {
+ svg2img: false // 是否将mermaid生成的画图变成img格式
+
+ },
+
+ /**
+ * indentedCodeBlock是缩进代码块是否启用的开关
+ *
+ * 在6.X之前的版本中默认不支持该语法。
+ * 因为cherry的开发团队认为该语法太丑了(容易误触)
+ * 开发团队希望用```代码块语法来彻底取代该语法
+ * 但在后续的沟通中,开发团队发现在某些场景下该语法有更好的显示效果
+ * 因此开发团队在6.X版本中才引入了该语法
+ * 已经引用6.x以下版本的业务如果想做到用户无感知升级,可以去掉该语法:
+ * indentedCodeBlock:false
+ */
+ indentedCodeBlock: true
+ },
+ emoji: {
+ useUnicode: true // 是否使用unicode进行渲染
+
+ },
+ fontEmphasis: {
+ /**
+ * 是否允许首尾空格
+ * 首尾、前后的定义: 语法前**语法首+内容+语法尾**语法后
+ * 例:
+ * true:
+ * __ hello __ ====> hello
+ * __hello__ ====> hello
+ * false:
+ * __ hello __ ====> _ hello _
+ * __hello__ ====> hello
+ */
+ allowWhitespace: false
+ },
+ strikethrough: {
+ /**
+ * 是否必须有前后空格
+ * 首尾、前后的定义: 语法前**语法首+内容+语法尾**语法后
+ * 例:
+ * true:
+ * hello wor~~l~~d ====> hello wor~~l~~d
+ * hello wor ~~l~~ d ====> hello wor l d
+ * false:
+ * hello wor~~l~~d ====> hello world
+ * hello wor ~~l~~ d ====> hello wor l d
+ */
+ needWhitespace: false
+ },
+ mathBlock: {
+ engine: 'MathJax',
+ // katex或MathJax
+ src: '',
+ plugins: true // 默认加载插件
+
+ },
+ inlineMath: {
+ engine: 'MathJax',
+ // katex或MathJax
+ src: ''
+ },
+ toc: {
+ /** 默认只渲染一个目录 */
+ allowMultiToc: false
+ },
+ header: {
+ /**
+ * 标题的样式:
+ * - default 默认样式,标题前面有锚点
+ * - autonumber 标题前面有自增序号锚点
+ * - none 标题没有锚点
+ */
+ anchorStyle: 'default'
+ }
+ }
+ },
+ editor: {
+ id: 'code',
+ // textarea 的id属性值
+ name: 'code',
+ // textarea 的name属性值
+ autoSave2Textarea: false,
+ // 是否自动将编辑区的内容回写到textarea里
+ theme: 'default',
+ // depend on codemirror theme name: https://codemirror.net/demo/theme.htm
+ // 编辑器的高度,默认100%,如果挂载点存在内联设置的height则以内联样式为主
+ height: '100%',
+ // defaultModel 编辑器初始化后的默认模式,一共有三种模式:1、双栏编辑预览模式;2、纯编辑模式;3、预览模式
+ // edit&preview: 双栏编辑预览模式
+ // editOnly: 纯编辑模式(没有预览,可通过toolbar切换成双栏或预览模式)
+ // previewOnly: 预览模式(没有编辑框,toolbar只显示“返回编辑”按钮,可通过toolbar切换成编辑模式)
+ defaultModel: 'edit&preview',
+ // 粘贴时是否自动将html转成markdown
+ convertWhenPaste: true,
+ codemirror: {
+ // 是否自动focus 默认为true
+ autofocus: true
+ },
+ writingStyle: 'normal' // 书写风格,normal 普通 | typewriter 打字机 | focus 专注,默认normal
+
+ },
+ toolbars: {
+ theme: 'dark',
+ // light or dark
+ showToolbar: true,
+ // false:不展示顶部工具栏; true:展示工具栏; toolbars.showToolbar=false 与 toolbars.toolbar=false 等效
+ toolbar: ['bold', 'italic', 'strikethrough', '|', 'color', 'header', 'ruby', '|', 'list', 'panel', // 'justify', // 对齐方式,默认不推荐这么“复杂”的样式要求
+ 'detail', {
+ insert: ['image', 'audio', 'video', 'link', 'hr', 'br', 'code', 'formula', 'toc', 'table', 'line-table', 'bar-table', 'pdf', 'word']
+ }, 'graph', 'settings'],
+ toolbarRight: [],
+ sidebar: [],
+ bubble: ['bold', 'italic', 'underline', 'strikethrough', 'sub', 'sup', 'quote', '|', 'size', 'color'],
+ // array or false
+ "float": ['h1', 'h2', 'h3', '|', 'checklist', 'quote', 'table', 'code'] // array or false
+
+ },
+ // 打开draw.io编辑页的url,如果为空则drawio按钮失效
+ drawioIframeUrl: '',
+ // 上传文件的回调
+ fileUpload: callbacks.fileUpload,
+
+ /**
+ * 上传文件的时候用来指定文件类型
+ */
+ fileTypeLimitMap: {
+ video: 'video/*',
+ audio: 'audio/*',
+ image: 'image/*',
+ word: '.doc,.docx',
+ pdf: '.pdf',
+ file: '*'
+ },
+ callback: {
+ afterChange: callbacks.afterChange,
+ afterInit: callbacks.afterInit,
+ beforeImageMounted: callbacks.beforeImageMounted,
+ // 预览区域点击事件,previewer.enablePreviewerBubble = true 时生效
+ onClickPreview: callbacks.onClickPreview,
+ // 复制代码块代码时的回调
+ onCopyCode: callbacks.onCopyCode,
+ // 把中文变成拼音的回调,当然也可以把中文变成英文、英文变成中文
+ changeString2Pinyin: callbacks.changeString2Pinyin
+ },
+ previewer: {
+ dom: false,
+ className: 'cherry-markdown',
+ // 是否启用预览区域编辑能力(目前支持编辑图片尺寸、编辑表格内容)
+ enablePreviewerBubble: true,
+
+ /**
+ * 配置图片懒加载的逻辑
+ * - 如果不希望图片懒加载,可配置成 lazyLoadImg = {noLoadImgNum: -1}
+ * - 如果希望所有图片都无脑懒加载,可配置成 lazyLoadImg = {noLoadImgNum: 0, autoLoadImgNum: -1}
+ * - 如果一共有15张图片,希望:
+ * 1、前5张图片(1~5)直接加载;
+ * 2、后5张图片(6~10)不论在不在视区内,都无脑懒加载;
+ * 3、其他图片(11~15)在视区内时,进行懒加载;
+ * 则配置应该为:lazyLoadImg = {noLoadImgNum: 5, autoLoadImgNum: 5}
+ */
+ lazyLoadImg: {
+ // 加载图片时如果需要展示loading图,则配置loading图的地址
+ loadingImgPath: '',
+ // 同一时间最多有几个图片请求,最大同时加载6张图片
+ maxNumPerTime: 2,
+ // 不进行懒加载处理的图片数量,如果为0,即所有图片都进行懒加载处理, 如果设置为-1,则所有图片都不进行懒加载处理
+ noLoadImgNum: 5,
+ // 首次自动加载几张图片(不论图片是否滚动到视野内),autoLoadImgNum = -1 表示会自动加载完所有图片
+ autoLoadImgNum: 5,
+ // 针对加载失败的图片 或 beforeLoadOneImgCallback 返回false 的图片,最多尝试加载几次,为了防止死循环,最多5次。以图片的src为纬度统计重试次数
+ maxTryTimesPerSrc: 2,
+ // 加载一张图片之前的回调函数,函数return false 会终止加载操作
+ beforeLoadOneImgCallback: function beforeLoadOneImgCallback(img) {
+ return true;
+ },
+ // 加载一张图片失败之后的回调函数
+ failLoadOneImgCallback: function failLoadOneImgCallback(img) {},
+ // 加载一张图片之后的回调函数,如果图片加载失败,则不会回调该函数
+ afterLoadOneImgCallback: function afterLoadOneImgCallback(img) {},
+ // 加载完所有图片后调用的回调函数
+ afterLoadAllImgCallback: function afterLoadAllImgCallback() {}
+ }
+ },
+
+ /**
+ * 配置主题,第三方可以自行扩展主题
+ */
+ theme: [{
+ className: 'default',
+ label: '默认'
+ }, {
+ className: 'dark',
+ label: '暗黑'
+ }, {
+ className: 'light',
+ label: '明亮'
+ }, {
+ className: 'green',
+ label: '清新'
+ }, {
+ className: 'red',
+ label: '热情'
+ }, {
+ className: 'violet',
+ label: '淡雅'
+ }, {
+ className: 'blue',
+ label: '清幽'
+ }],
+ // 预览页面不需要绑定事件
+ isPreviewOnly: false,
+ // 预览区域跟随编辑器光标自动滚动
+ autoScrollByCursor: true,
+ // 外层容器不存在时,是否强制输出到body上
+ forceAppend: true,
+ // The locale Cherry is going to use. Locales live in /src/locales/
+ locale: 'zh_CN'
+ };
+ var defaultConfig$1 = cloneDeep_1(defaultConfig);
+
+ /**
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ var zhCn = {
+ bold: '加粗',
+ // 加粗
+ code: '代码',
+ // 代码
+ graph: '画图',
+ // 画图
+ h1: '一级标题',
+ // 一级标题
+ h2: '二级标题',
+ // 二级标题
+ h3: '三级标题',
+ // 三级标题
+ h4: '四级标题',
+ // 四级标题
+ h5: '五级标题',
+ // 五级标题
+ header: '标题',
+ // 标题
+ insert: '插入',
+ // 插入
+ italic: '斜体',
+ // 斜体
+ list: '列表',
+ // 列表
+ quickTable: '表格',
+ // 表格
+ quote: '引用',
+ // 引用
+ size: '大小',
+ // 大小
+ color: '文字颜色&背景',
+ // 文字颜色&背景
+ strikethrough: '删除线',
+ // 删除线
+ sub: '下标',
+ // 下标
+ sup: '上标',
+ // 上标
+ togglePreview: '预览',
+ // 预览
+ fullScreen: '全屏',
+ // 全屏
+ image: '图片',
+ // 图片
+ audio: '音频',
+ // 音频
+ video: '视频',
+ // 视频
+ link: '超链接',
+ // 超链接
+ hr: '分隔线',
+ // 分隔线
+ br: '换行',
+ // 换行
+ toc: '目录',
+ // 目录
+ pdf: 'pdf',
+ // pdf
+ word: 'word',
+ // word
+ table: '表格',
+ // 表格
+ 'line-table': '折线表格',
+ // 折线表格
+ 'bar-table': '柱状表格',
+ // 柱状表格
+ formula: '公式',
+ // 公式
+ insertFormula: '公式',
+ // 公式
+ insertFlow: '流程图',
+ // 流程图
+ insertSeq: '时序图',
+ // 时序图
+ insertState: '状态图',
+ // 状态图
+ insertClass: '类图',
+ // 类图
+ insertPie: '饼图',
+ // 饼图
+ insertGantt: '甘特图',
+ // 甘特图
+ checklist: '清单',
+ // 清单
+ ol: '有序列表',
+ // 有序列表
+ ul: '无序列表',
+ // 无序列表
+ undo: '撤销',
+ // 撤销
+ redo: '恢复',
+ // 恢复
+ previewClose: '关闭预览',
+ // 关闭预览
+ codeTheme: '代码主题',
+ // 代码主题
+ switchModel: '模式切换',
+ // 模式切换
+ switchPreview: '预览',
+ // 预览
+ switchEdit: '返回编辑',
+ // 返回编辑
+ classicBr: '经典换行',
+ // 经典换行
+ normalBr: '常规换行',
+ // 常规换行
+ settings: '设置',
+ // 设置
+ mobilePreview: '移动端预览',
+ // 移动端预览
+ copy: '复制内容',
+ // 复制内容
+ "export": '导出',
+ // 导出PDF、长图
+ underline: '下划线',
+ // 下划线
+ pinyin: '拼音',
+ // 拼音
+ file: '文件',
+ pastePlain: '粘贴为纯文本格式',
+ // 粘贴为纯文本格式
+ pasteMarkdown: '粘贴为markdown格式',
+ // 粘贴为markdown格式
+ hide: '隐藏(ctrl+0)',
+ // 隐藏(ctrl+0)
+ exportToPdf: '导出PDF',
+ // 导出PDF
+ exportScreenshot: '导出长图',
+ // 导出长图
+ exportMarkdownFile: '导出markdown',
+ // 导出markdown文件
+ exportHTMLFile: '导出html',
+ // 导出预览区html文件
+ theme: '主题',
+ // 导出长图
+ panel: '面板',
+ // 导出长图
+ detail: '手风琴',
+ // 手风琴
+ 'H1 Heading': 'H1 一级标题',
+ 'H2 Heading': 'H2 二级标题',
+ 'H3 Heading': 'H3 三级标题',
+ complement: '续写',
+ summary: '总结',
+ save: '保存',
+ release: '发布',
+ back: '返回',
+ };
+
+ /**
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ var enUs = {
+ bold: 'Bold',
+ code: 'Code',
+ graph: 'Graph',
+ h1: 'Heading 1',
+ h2: 'Heading 2',
+ h3: 'Heading 3',
+ h4: 'Heading 4',
+ h5: 'Heading 5',
+ header: 'Header',
+ insert: 'Insert',
+ italic: 'Italic',
+ list: 'List',
+ quickTable: 'Quick Table',
+ quote: 'Quote',
+ size: 'Size',
+ color: 'Text Color & Background',
+ strikethrough: 'Strikethrough',
+ sub: 'Sub',
+ sup: 'Sup',
+ togglePreview: 'Toggle Preview',
+ fullScreen: 'Full Screen',
+ image: 'Image',
+ audio: 'Audio',
+ video: 'Video',
+ link: 'Link',
+ hr: 'Horizontal Rule',
+ br: 'New Line',
+ toc: 'Table Of Content',
+ pdf: 'PDF',
+ word: 'Word',
+ table: 'Table',
+ 'line-table': 'Line Table',
+ 'bar-table': 'Bar Table',
+ formula: 'Formula',
+ insertFormula: 'Insert Formula',
+ insertFlow: 'Insert Flow',
+ insertSeq: 'Insert Seq',
+ insertState: 'Insert State',
+ insertClass: 'Insert Class',
+ insertPie: 'Insert Pie',
+ insertGantt: 'Insert Gantt',
+ checklist: 'Checklist',
+ ol: 'Ordered List',
+ ul: 'Unordered List',
+ undo: 'Undo',
+ redo: 'Redo',
+ previewClose: 'Preview Close',
+ codeTheme: 'Code Theme',
+ switchModel: 'Switch Model',
+ switchPreview: 'Switch Preview',
+ switchEdit: 'Switch Edit',
+ classicBr: 'Classic New Line',
+ normalBr: 'Normal New Line',
+ settings: 'Settings',
+ mobilePreview: 'Mobile Preview',
+ copy: 'Copy',
+ "export": 'Export',
+ underline: 'Underline',
+ pinyin: 'Pinyin',
+ pastePlain: 'Paste as Plain Text',
+ pasteMarkdown: 'Paste as Markdown',
+ hide: 'Hide (ctrl+0)',
+ exportToPdf: 'Export to PDF',
+ exportScreenshot: 'Screenshot',
+ exportMarkdownFile: 'Export Markdown File',
+ exportHTMLFile: 'Export preview HTML File',
+ 'H1 Heading': 'H1 Heading',
+ 'H2 Heading': 'H1 Heading',
+ 'H3 Heading': 'H1 Heading',
+ complement: 'Complement',
+ summary: 'Summary',
+ save: 'Save',
+ release: 'Release',
+ back: 'Back',
+ };
+
+ /**
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ var locales = {
+ zh_CN: zhCn,
+ en_US: enUs
+ };
+
+ function _createSuper$1r(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1r(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1r() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+
+ function filterOptions(options, whiteList, propTypes) {
+ var _context;
+
+ var filteredOptions = {};
+
+ forEach$3(_context = keys$3(options)).call(_context, function (key) {
+ if (indexOf$8(whiteList).call(whiteList, key) === -1) {
+ return;
+ }
+
+ if (_typeof(propTypes) === 'object') {
+ if (typeof propTypes[key] === 'string') {
+ if (_typeof(options[key]) === propTypes[key]) {
+ filteredOptions[key] = options[key];
+ }
+ } else {
+ if (options[key] instanceof propTypes[key]) {
+ filteredOptions[key] = options[key];
+ }
+ }
+ } else if (typeof propTypes === 'string') {
+ if (_typeof(options[key]) === propTypes) {
+ filteredOptions[key] = options[key];
+ }
+ }
+ });
+
+ return filteredOptions;
+ }
+
+ function createSyntaxHook(name, type, options) {
+ var _class;
+
+ var BaseClass = type === HOOKS_TYPE_LIST.PAR ? ParagraphBase : SyntaxBase;
+ var optionsWhiteList = ['beforeMakeHtml', 'makeHtml', 'afterMakeHtml', 'rule', 'test'];
+ var filteredOptions = filterOptions(options, optionsWhiteList, 'function');
+ var paragraphConfig = {
+ needCache: options.needCache,
+ defaultCache: options.defaultCache
+ };
+ return _class = /*#__PURE__*/function (_BaseClass) {
+ _inherits(CustomSyntax, _BaseClass);
+
+ var _super = _createSuper$1r(CustomSyntax);
+
+ function CustomSyntax() {
+ var _this;
+
+ var editorConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ _classCallCheck(this, CustomSyntax);
+
+ if (type === HOOKS_TYPE_LIST.PAR) {
+ _this = _super.call(this, {
+ needCache: !!paragraphConfig.needCache,
+ defaultCache: paragraphConfig.defaultCache
+ });
+ } else {
+ _this = _super.call(this);
+ }
+
+ _this.config = editorConfig.config;
+ return _possibleConstructorReturn(_this);
+ }
+
+ _createClass(CustomSyntax, [{
+ key: "beforeMakeHtml",
+ value: function beforeMakeHtml() {
+ var _get2, _context2;
+
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ if (filteredOptions.beforeMakeHtml) {
+ return filteredOptions.beforeMakeHtml.apply(this, args);
+ }
+
+ return (_get2 = _get(_getPrototypeOf(CustomSyntax.prototype), "beforeMakeHtml", this)).call.apply(_get2, concat$5(_context2 = [this]).call(_context2, args));
+ }
+ }, {
+ key: "makeHtml",
+ value: function makeHtml() {
+ var _get3, _context3;
+
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
+ }
+
+ if (filteredOptions.makeHtml) {
+ return filteredOptions.makeHtml.apply(this, args);
+ }
+
+ return (_get3 = _get(_getPrototypeOf(CustomSyntax.prototype), "makeHtml", this)).call.apply(_get3, concat$5(_context3 = [this]).call(_context3, args));
+ }
+ }, {
+ key: "afterMakeHtml",
+ value: function afterMakeHtml() {
+ var _get4, _context4;
+
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
+ args[_key3] = arguments[_key3];
+ }
+
+ if (filteredOptions.afterMakeHtml) {
+ return filteredOptions.afterMakeHtml.apply(this, args);
+ }
+
+ return (_get4 = _get(_getPrototypeOf(CustomSyntax.prototype), "afterMakeHtml", this)).call.apply(_get4, concat$5(_context4 = [this]).call(_context4, args));
+ }
+ }, {
+ key: "test",
+ value: function test() {
+ var _get5, _context5;
+
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
+ args[_key4] = arguments[_key4];
+ }
+
+ if (filteredOptions.test) {
+ return filteredOptions.test.apply(this, args);
+ }
+
+ return (_get5 = _get(_getPrototypeOf(CustomSyntax.prototype), "test", this)).call.apply(_get5, concat$5(_context5 = [this]).call(_context5, args));
+ }
+ }, {
+ key: "rule",
+ value: function rule() {
+ var _get6, _context6;
+
+ for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
+ args[_key5] = arguments[_key5];
+ }
+
+ if (filteredOptions.rule) {
+ return filteredOptions.rule.apply(this, args);
+ }
+
+ return (_get6 = _get(_getPrototypeOf(CustomSyntax.prototype), "rule", this)).call.apply(_get6, concat$5(_context6 = [this]).call(_context6, args));
+ }
+ }]);
+
+ return CustomSyntax;
+ }(BaseClass), _defineProperty(_class, "HOOK_NAME", name), _class;
+ }
+ function createMenuHook(name, options) {
+ var optionsWhiteList = ['subMenuConfig', 'id', 'onClick', 'shortcutKeys', 'iconName'];
+ var propTypes = {
+ subMenuConfig: Array,
+ onClick: 'function',
+ shortcutKeys: Array,
+ id: 'string',
+ iconName: 'string'
+ };
+ var filteredOptions = filterOptions(options, optionsWhiteList, propTypes);
+ return /*#__PURE__*/function (_MenuBase) {
+ _inherits(CustomMenu, _MenuBase);
+
+ var _super2 = _createSuper$1r(CustomMenu);
+
+ function CustomMenu(editorInstance) {
+ var _this2;
+
+ _classCallCheck(this, CustomMenu);
+
+ _this2 = _super2.call(this, editorInstance);
+
+ if (!filteredOptions.iconName) {
+ _this2.noIcon = true;
+ }
+
+ _this2.setName(name, filteredOptions.iconName);
+ _this2.setId(filteredOptions.id);
+
+ _this2.subMenuConfig = filteredOptions.subMenuConfig || [];
+ return _this2;
+ }
+
+ _createClass(CustomMenu, [{
+ key: "onClick",
+ value: function onClick() {
+ var _get7, _context7;
+
+ for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
+ args[_key6] = arguments[_key6];
+ }
+
+ if (filteredOptions.onClick) {
+ return filteredOptions.onClick.apply(this, args);
+ }
+
+ return (_get7 = _get(_getPrototypeOf(CustomMenu.prototype), "onClick", this)).call.apply(_get7, concat$5(_context7 = [this]).call(_context7, args));
+ }
+ }, {
+ key: "shortcutKeys",
+ get: function get() {
+ if (filteredOptions.shortcutKeys) {
+ return filteredOptions.shortcutKeys;
+ }
+
+ return [];
+ }
+ }]);
+
+ return CustomMenu;
+ }(MenuBase);
+ }
+
+ var constants = {
+ HOOKS_TYPE_LIST: HOOKS_TYPE_LIST
+ };
+ var nodeIgnorePlugin = [];
+
+ if (!isBrowser()) {
+ forEach$3(nodeIgnorePlugin).call(nodeIgnorePlugin, function (key) {
+ });
+ }
+
+ var VERSION$1 = "0.8.21-4b60dd76";
+ var CherryStatic = /*#__PURE__*/function () {
+ function CherryStatic() {
+ _classCallCheck(this, CherryStatic);
+ }
+
+ _createClass(CherryStatic, null, [{
+ key: "usePlugin",
+ value:
+ /**
+ * @this {typeof import('./Cherry').default | typeof CherryStatic}
+ * @param {{ install: (defaultConfig: any, ...args: any[]) => void }} PluginClass 插件Class
+ * @param {...any} args 初始化插件的参数
+ * @returns
+ */
+ function usePlugin(PluginClass) {
+ var _context;
+
+ if (this === CherryStatic) {
+ throw new Error('`usePlugin` is not allowed to called through CherryStatic class.');
+ } // @ts-ignore
+
+
+ if (this.initialized) {
+ throw new Error('The function `usePlugin` should be called before Cherry is instantiated.');
+ } // @ts-ignore
+
+
+ if (PluginClass.$cherry$mounted === true) {
+ return;
+ } // @ts-ignore
+
+
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
+
+ PluginClass.install.apply(PluginClass, concat$5(_context = [this.config.defaults]).call(_context, args)); // @ts-ignore
+
+ PluginClass.$cherry$mounted = true;
+ }
+ }]);
+
+ return CherryStatic;
+ }();
+
+ _defineProperty(CherryStatic, "createSyntaxHook", createSyntaxHook);
+
+ _defineProperty(CherryStatic, "createMenuHook", createMenuHook);
+
+ _defineProperty(CherryStatic, "constants", constants);
+
+ _defineProperty(CherryStatic, "VERSION", VERSION$1);
+
+ function ownKeys$9(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols$2) { var symbols = getOwnPropertySymbols$2(object); enumerableOnly && (symbols = filter$3(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+ function _objectSpread$8(target) { for (var i = 1; i < arguments.length; i++) { var _context5, _context6; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$3(_context5 = ownKeys$9(Object(source), !0)).call(_context5, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors$2 ? defineProperties$2(target, getOwnPropertyDescriptors$2(source)) : forEach$3(_context6 = ownKeys$9(Object(source))).call(_context6, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
+
+ function _createSuper$1s(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct$1s(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = construct$4(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
+
+ function _isNativeReflectConstruct$1s() { if (typeof Reflect === "undefined" || !construct$4) return false; if (construct$4.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(construct$4(Boolean, [], function () {})); return true; } catch (e) { return false; } }
+ /** @typedef {import('~types/cherry').CherryOptions} CherryOptions */
+
+ var Cherry = /*#__PURE__*/function (_CherryStatic) {
+ _inherits(Cherry, _CherryStatic);
+
+ var _super = _createSuper$1s(Cherry);
+
+ /**
+ * @protected
+ */
+
+ /**
+ * @readonly
+ */
+
+ /**
+ * @param {Partial} options
+ */
+ function Cherry(options) {
+ var _context;
+
+ var _this;
+
+ _classCallCheck(this, Cherry);
+
+ _this = _super.call(this);
+ Cherry.initialized = true;
+ var defaultConfigCopy = cloneDeep_1(Cherry.config.defaults);
+ _this.defaultToolbar = defaultConfigCopy.toolbars.toolbar;
+ $expectTarget(options, Object);
+ /**
+ * @property
+ * @type {Partial}
+ */
+
+ _this.options = mergeWith_1({}, defaultConfigCopy, options, customizer); // loading the locale
+
+ _this.locale = locales[_this.options.locale];
+
+ if (typeof _this.options.engine.global.urlProcessor === 'function') {
+ _this.options.engine.global.urlProcessor = urlProcessorProxy(_this.options.engine.global.urlProcessor);
+ }
+
+ _this.status = {
+ toolbar: 'show',
+ previewer: 'show',
+ editor: 'show'
+ };
+
+ if (_this.options.isPreviewOnly || _this.options.editor.defaultModel === 'previewOnly') {
+ _this.options.toolbars.showToolbar = false;
+ _this.options.editor.defaultModel = 'previewOnly';
+ _this.status.editor = 'hide';
+ _this.status.toolbar = 'hide';
+ }
+ /**
+ * @property
+ * @type {string} 实例ID
+ */
+
+
+ _this.instanceId = concat$5(_context = "cherry-".concat(new Date().getTime())).call(_context, Math.random());
+ _this.options.instanceId = _this.instanceId;
+ /**
+ * @private
+ * @type {Engine}
+ */
+
+ _this.engine = new Engine(_this.options, _assertThisInitialized(_this));
+
+ _this.init();
+
+ return _this;
+ }
+ /**
+ * 初始化工具栏、编辑区、预览区等
+ * @private
+ */
+
+
+ _createClass(Cherry, [{
+ key: "init",
+ value: function init() {
+ var _context2,
+ _this2 = this;
+
+ var mountEl = this.options.id ? document.getElementById(this.options.id) : this.options.el;
+
+ if (!mountEl) {
+ if (!this.options.forceAppend) {
+ return false;
+ }
+
+ mountEl = document.createElement('div');
+ mountEl.id = this.options.id || 'cherry-markdown';
+ document.body.appendChild(mountEl);
+ }
+
+ if (!mountEl.style.height) {
+ mountEl.style.height = this.options.editor.height;
+ }
+
+ this.cherryDom = mountEl; // 蒙层dom,用来拖拽编辑区&预览区宽度时展示蒙层
+
+ var wrapperDom = this.createWrapper(); // 创建编辑区
+
+ var editor = this.createEditor(); // 创建预览区
+
+ var previewer = this.createPreviewer();
+
+ if (this.options.toolbars.showToolbar === false || this.options.toolbars.toolbar === false) {
+ // 即便配置了不展示工具栏,也要让工具栏加载对应的语法hook
+ wrapperDom.classList.add('cherry--no-toolbar');
+ this.options.toolbars.toolbar = this.defaultToolbar;
+ }
+
+ $expectTarget(this.options.toolbars.toolbar, Array); // 创建顶部工具栏
+
+ this.toolbar = this.createToolbar();
+ var wrapperFragment = document.createDocumentFragment();
+ wrapperFragment.appendChild(this.toolbar.options.dom);
+ wrapperFragment.appendChild(editor.options.editorDom); // 创建预览区域的侧边工具栏
+
+ this.createSidebar(wrapperFragment);
+
+ if (!this.options.previewer.dom) {
+ wrapperFragment.appendChild(previewer.options.previewerDom);
+ }
+
+ wrapperFragment.appendChild(previewer.options.virtualDragLineDom);
+ wrapperFragment.appendChild(previewer.options.editorMaskDom);
+ wrapperFragment.appendChild(previewer.options.previewerMaskDom);
+ wrapperDom.appendChild(wrapperFragment);
+ mountEl.appendChild(wrapperDom);
+ editor.init(previewer); // 创建bubble工具栏,所谓bubble工具栏,是指在编辑区选中文本时悬浮出现的工具栏
+
+ this.createBubble(); // 创建float工具栏,所谓float工具栏,是指当编辑区光标处于新行时,在行内联想出的工具栏
+
+ this.createFloatMenu();
+ previewer.init(editor);
+ previewer.registerAfterUpdate(bind$5(_context2 = this.engine.mounted).call(_context2, this.engine)); // default value init
+
+ this.initText(editor.editor); // 切换模式,有纯预览模式、纯编辑模式、双栏编辑模式
+
+ this.switchModel(this.options.editor.defaultModel);
+ Event$1.on(this.instanceId, Event$1.Events.toolbarHide, function () {
+ _this2.status.toolbar = 'hide';
+ });
+ Event$1.on(this.instanceId, Event$1.Events.toolbarShow, function () {
+ _this2.status.toolbar = 'show';
+ });
+ Event$1.on(this.instanceId, Event$1.Events.previewerClose, function () {
+ _this2.status.previewer = 'hide';
+ });
+ Event$1.on(this.instanceId, Event$1.Events.previewerOpen, function () {
+ _this2.status.previewer = 'show';
+ });
+ Event$1.on(this.instanceId, Event$1.Events.editorClose, function () {
+ _this2.status.editor = 'hide'; // 关闭编辑区时,需要清除所有高亮
+
+ _this2.previewer.highlightLine(0);
+ });
+ Event$1.on(this.instanceId, Event$1.Events.editorOpen, function () {
+ _this2.status.editor = 'show';
+ });
+ }
+ /**
+ * 切换编辑模式
+ * @param {'edit&preview'|'editOnly'|'previewOnly'} model 模式类型
+ * 一般纯预览模式和纯编辑模式适合在屏幕较小的终端使用,比如手机移动端
+ *
+ * @returns
+ */
+
+ }, {
+ key: "switchModel",
+ value: function switchModel() {
+ var model = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'edit&preview';
+
+ switch (model) {
+ case 'edit&preview':
+ if (this.previewer) {
+ this.previewer.editOnly(true);
+ this.previewer.recoverPreviewer();
+ }
+
+ if (this.toolbar) {
+ this.toolbar.showToolbar();
+ }
+
+ break;
+
+ case 'editOnly':
+ if (!this.previewer.isPreviewerHidden()) {
+ this.previewer.editOnly(true);
+ }
+
+ if (this.toolbar) {
+ this.toolbar.showToolbar();
+ }
+
+ break;
+
+ case 'previewOnly':
+ this.previewer.previewOnly();
+ this.toolbar && this.toolbar.previewOnly();
+ break;
+ }
+ }
+ /**
+ * 获取实例id
+ * @returns {string}
+ * @public
+ */
+
+ }, {
+ key: "getInstanceId",
+ value: function getInstanceId() {
+ return this.instanceId;
+ }
+ /**
+ * 获取编辑器状态
+ * @returns {Object}
+ */
+
+ }, {
+ key: "getStatus",
+ value: function getStatus() {
+ return this.status;
+ }
+ /**
+ * 获取编辑区内的markdown源码内容
+ * @returns markdown源码内容
+ */
+
+ }, {
+ key: "getValue",
+ value: function getValue() {
+ return this.editor.editor.getValue();
+ }
+ /**
+ * 获取编辑区内的markdown源码内容
+ * @returns markdown源码内容
+ */
+
+ }, {
+ key: "getMarkdown",
+ value: function getMarkdown() {
+ return this.getValue();
+ }
+ /**
+ * 获取CodeMirror实例
+ * @returns CodeMirror实例
+ */
+
+ }, {
+ key: "getCodeMirror",
+ value: function getCodeMirror() {
+ return this.editor.editor;
+ }
+ /**
+ * 获取预览区内的html内容
+ * @param {boolean} wrapTheme 是否在外层包裹主题class
+ * @returns html内容
+ */
+
+ }, {
+ key: "getHtml",
+ value: function getHtml() {
+ var wrapTheme = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
+ return this.previewer.getValue(wrapTheme);
+ }
+ }, {
+ key: "getPreviewer",
+ value: function getPreviewer() {
+ return this.previewer;
+ }
+ /**
+ * 获取目录,目录由head1~6组成
+ * @returns 标题head数组
+ */
+ }, {
+ key: "getTheme",
+ value: function getTheme() {
+ return getThemeFromLocal(true)
+ }
+ }, {
+ key: "setTheme",
+ value: function setTheme(theme) {
+ changeTheme(this, theme)
+ }
+ }, {
+ key: "getToc",
+ value: function getToc() {
+ var str = this.getHtml();
+ /** @type {({level: number;id: string;text: string})[]} */
+
+ var headerList = [];
+ var headerRegex = /(.+?)<\/h[0-6]>/g;
+ str.replace(headerRegex, function (match, level, id, text) {
+ headerList.push({
+ level: +level,
+ id: id,
+ text: text
+ });
+ return match;
+ });
+ return headerList;
+ }
+ /**
+ * 覆盖编辑区的内容
+ * @param {string} content markdown内容
+ * @param {boolean} keepCursor 是否保持光标位置
+ * @returns
+ */
+
+ }, {
+ key: "setValue",
+ value: function setValue(content) {
+ var keepCursor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+ if (keepCursor === false) {
+ return this.editor.editor.setValue(content);
+ }
+
+ var codemirror = this.editor.editor;
+ var old = this.getValue();
+ var pos = codemirror.getDoc().indexFromPos(codemirror.getCursor());
+ var newPos = getPosBydiffs(pos, old, content);
+ var ret = codemirror.setValue(content);
+ var cursor = codemirror.getDoc().posFromIndex(newPos);
+ codemirror.setCursor(cursor);
+ return ret;
+ }
+ /**
+ * 在光标处或者指定行+偏移量插入内容
+ * @param {string} content 被插入的文本
+ * @param {boolean} [isSelect=false] 是否选中刚插入的内容
+ * @param {[number, number]|false} [anchor=false] [x,y] 代表x+1行,y+1字符偏移量,默认false 会从光标处插入
+ * @param {boolean} [focus=true] 保持编辑器处于focus状态
+ * @returns
+ */
+
+ }, {
+ key: "insert",
+ value: function insert(content) {
+ var isSelect = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+ var anchor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+ var focus = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+
+ if (anchor) {
+ this.editor.editor.setSelection({
+ line: anchor[0],
+ ch: anchor[1]
+ }, {
+ line: anchor[0],
+ ch: anchor[1]
+ });
+ }
+
+ var ret = this.editor.editor.replaceSelection(content, isSelect ? 'around' : 'end');
+ focus && this.editor.editor.focus();
+ return ret;
+ }
+ /**
+ * 在光标处或者指定行+偏移量插入内容
+ * @param {string} content 被插入的文本
+ * @param {boolean} [isSelect=false] 是否选中刚插入的内容
+ * @param {[number, number]|false} [anchor=false] [x,y] 代表x+1行,y+1字符偏移量,默认false 会从光标处插入
+ * @param {boolean} [focus=true] 保持编辑器处于focus状态
+ * @returns
+ */
+
+ }, {
+ key: "insertValue",
+ value: function insertValue(content) {
+ var isSelect = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+ var anchor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+ var focus = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
+ return this.insert(content, isSelect, anchor, focus);
+ }
+ /**
+ * 强制重新渲染预览区域
+ */
+
+ }, {
+ key: "refreshPreviewer",
+ value: function refreshPreviewer() {
+ try {
+ var markdownText = this.getValue();
+ var html = this.engine.makeHtml(markdownText);
+ this.previewer.refresh(html);
+ } catch (e) {
+ throw new NestedError(e);
+ }
+ }
+ /**
+ * 覆盖编辑区的内容
+ * @param {string} content markdown内容
+ * @param {boolean} keepCursor 是否保持光标位置
+ * @returns
+ */
+
+ }, {
+ key: "setMarkdown",
+ value: function setMarkdown(content) {
+ var keepCursor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+ return this.setValue(content, keepCursor);
+ }
+ /**
+ * @private
+ * @returns
+ */
+
+ }, {
+ key: "createWrapper",
+ value: function createWrapper() {
+ var toolbarTheme = this.options.toolbars.theme === 'dark' ? 'dark' : ''; // TODO: 完善类型
+
+ var inlineCodeTheme =
+ /** @type {{theme?: string;}} */
+ this.options.engine.syntax.inlineCode.theme;
+ var codeBlockTheme =
+ /** @type {{theme?: string;}} */
+ this.options.engine.syntax.codeBlock.theme;
+ if (codeBlockTheme === 'dark') codeBlockTheme = 'tomorrow-night';else if (codeBlockTheme === 'light') codeBlockTheme = 'solarized-light';
+ var wrapperDom = createElement('div', ['cherry', 'clearfix', getThemeFromLocal(true)].join(' '), {
+ 'data-toolbarTheme': toolbarTheme,
+ 'data-inlineCodeTheme': inlineCodeTheme,
+ 'data-codeBlockTheme': codeBlockTheme
+ });
+ this.wrapperDom = wrapperDom;
+ return wrapperDom;
+ }
+ /**
+ * @private
+ * @returns {Toolbar}
+ */
+
+ }, {
+ key: "createToolbar",
+ value: function createToolbar() {
+ var dom = createElement('div', 'cherry-toolbar');
+ this.toolbar = new Toolbar({
+ dom: dom,
+ $cherry: this,
+ buttonRightConfig: this.options.toolbars.toolbarRight,
+ buttonConfig: this.options.toolbars.toolbar,
+ customMenu: this.options.toolbars.customMenu
+ });
+ return this.toolbar;
+ }
+ /**
+ * @private
+ * @returns
+ */
+
+ }, {
+ key: "createSidebar",
+ value: function createSidebar(wrapperFragment) {
+ if (this.options.toolbars.sidebar) {
+ $expectTarget(this.options.toolbars.sidebar, Array);
+ var externalClass = this.options.toolbars.theme === 'dark' ? 'dark' : '';
+ var dom = createElement('div', "cherry-sidebar ".concat(externalClass));
+ this.sidebar = new Sidebar({
+ dom: dom,
+ $cherry: this,
+ buttonConfig: this.options.toolbars.sidebar,
+ customMenu: this.options.toolbars.customMenu
+ });
+ wrapperFragment.appendChild(this.sidebar.options.dom);
+ }
+ }
+ /**
+ * @private
+ * @returns
+ */
+
+ }, {
+ key: "createFloatMenu",
+ value: function createFloatMenu() {
+ if (this.options.toolbars["float"]) {
+ var dom = createElement('div', 'cherry-floatmenu');
+ $expectTarget(this.options.toolbars["float"], Array);
+ this.floatMenu = new FloatMenu({
+ dom: dom,
+ $cherry: this,
+ buttonConfig: this.options.toolbars["float"],
+ customMenu: this.options.toolbars.customMenu
+ });
+ }
+ }
+ /**
+ * @private
+ * @returns
+ */
+
+ }, {
+ key: "createBubble",
+ value: function createBubble() {
+ if (this.options.toolbars.bubble) {
+ var dom = createElement('div', 'cherry-bubble');
+ $expectTarget(this.options.toolbars.bubble, Array);
+ this.bubble = new Bubble({
+ dom: dom,
+ $cherry: this,
+ buttonConfig: this.options.toolbars.bubble,
+ customMenu: this.options.toolbars.customMenu,
+ engine: this.engine
+ });
+ }
+ }
+ /**
+ * @private
+ * @returns {import('@/Editor').default}
+ */
+
+ }, {
+ key: "createEditor",
+ value: function createEditor() {
+ var _this$options$editor$, _this$options$editor$2, _context3, _context4;
+
+ var textArea = createElement('textarea', '', {
+ id: (_this$options$editor$ = this.options.editor.id) !== null && _this$options$editor$ !== void 0 ? _this$options$editor$ : 'code',
+ name: (_this$options$editor$2 = this.options.editor.name) !== null && _this$options$editor$2 !== void 0 ? _this$options$editor$2 : 'code'
+ });
+ textArea.textContent = this.options.value;
+ var editor = createElement('div', 'cherry-editor');
+ editor.appendChild(textArea);
+ this.editor = new Editor(_objectSpread$8({
+ $cherry: this,
+ editorDom: editor,
+ wrapperDom: this.wrapperDom,
+ value: this.options.value,
+ onKeydown: bind$5(_context3 = this.fireShortcutKey).call(_context3, this),
+ onChange: bind$5(_context4 = this.editText).call(_context4, this),
+ toolbars: this.options.toolbars,
+ fileUpload: this.options.fileUpload,
+ autoScrollByCursor: this.options.autoScrollByCursor
+ }, this.options.editor));
+ return this.editor;
+ }
+ /**
+ * @private
+ * @returns {import('@/Previewer').default}
+ */
+
+ }, {
+ key: "createPreviewer",
+ value: function createPreviewer() {
+ /** @type {HTMLDivElement} */
+ var previewer;
+ var anchorStyle = this.options.engine.syntax.header && this.options.engine.syntax.header.anchorStyle || 'default';
+ var autonumberClass = anchorStyle === 'autonumber' ? ' head-num' : '';
+ var _this$options$preview = this.options.previewer,
+ className = _this$options$preview.className,
+ dom = _this$options$preview.dom,
+ enablePreviewerBubble = _this$options$preview.enablePreviewerBubble;
+ var previewerClassName = ['cherry-previewer cherry-markdown', className || '', autonumberClass, getThemeFromLocal(true)].join(' ');
+
+ if (dom) {
+ previewer = dom;
+ previewer.className += " ".concat(previewerClassName);
+ } else {
+ previewer = createElement('div', previewerClassName);
+ }
+
+ var virtualDragLine = createElement('div', 'cherry-drag');
+ var editorMask = createElement('div', 'cherry-editor-mask');
+ var previewerMask = createElement('div', 'cherry-previewer-mask');
+ this.previewer = new Previewer({
+ $cherry: this,
+ virtualDragLineDom: virtualDragLine,
+ editorMaskDom: editorMask,
+ previewerMaskDom: previewerMask,
+ previewerDom: previewer,
+ value: this.options.value,
+ isPreviewOnly: this.options.isPreviewOnly,
+ enablePreviewerBubble: enablePreviewerBubble,
+ lazyLoadImg: this.options.previewer.lazyLoadImg
+ });
+ return this.previewer;
+ }
+ /**
+ * @private
+ * @param {import('codemirror').Editor} codemirror
+ */
+
+ }, {
+ key: "initText",
+ value: function initText(codemirror) {
+ try {
+ var markdownText = codemirror.getValue();
+ var html = this.engine.makeHtml(markdownText);
+ this.previewer.update(html);
+
+ if (this.options.callback.afterInit) {
+ this.options.callback.afterInit(markdownText, html);
+ }
+ } catch (e) {
+ throw new NestedError(e);
+ }
+ }
+ /**
+ * @private
+ * @param {Event} _evt
+ * @param {import('codemirror').Editor} codemirror
+ */
+
+ }, {
+ key: "editText",
+ value: function editText(_evt, codemirror) {
+ var _this3 = this;
+
+ try {
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
+
+ this.timer = setTimeout$3(function () {
+ var markdownText = codemirror.getValue();
+
+ var html = _this3.engine.makeHtml(markdownText);
+
+ _this3.previewer.update(html);
+
+ if (_this3.options.callback.afterChange) {
+ _this3.options.callback.afterChange(markdownText, html);
+ } // 强制每次编辑(包括undo、redo)编辑器都会自动滚动到光标位置
+
+
+ codemirror.scrollIntoView(null);
+ }, 50);
+ } catch (e) {
+ throw new NestedError(e);
+ }
+ }
+ /**
+ * @private
+ * @param {any} cb
+ */
+
+ }, {
+ key: "onChange",
+ value: function onChange(cb) {
+ this.editor.editor.on('change', function (codeMirror) {
+ cb({
+ markdown: codeMirror.getValue() // 后续可以按需增加html或其他状态
+
+ });
+ });
+ }
+ /**
+ * @private
+ * @param {*} evt
+ */
+
+ }, {
+ key: "fireShortcutKey",
+ value: function fireShortcutKey(evt) {
+ if (this.toolbar.matchShortcutKey(evt)) {
+ // 快捷键
+ evt.preventDefault();
+ this.toolbar.fireShortcutKey(evt);
+ }
+ }
+ /**
+ * 导出预览区域内容
+ * @public
+ * @param {String} type 'pdf':导出成pdf文件; 'img':导出成图片
+ * @param {String} fileName 导出文件名
+ */
+
+ }, {
+ key: "export",
+ value: function _export() {
+ var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'pdf';
+ var fileName = arguments.length > 1 ? arguments[1] : undefined;
+ this.previewer["export"](type, fileName);
+ }
+ /**
+ * 修改主题
+ * @param {string} theme option.theme里的className
+ */
+
+ }, {
+ key: "setTheme",
+ value: function setTheme() {
+ var theme = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'default';
+ changeTheme(this, theme);
+ }
+ /**
+ * 修改书写风格
+ * @param {string} writingStyle normal 普通 | typewriter 打字机 | focus 专注
+ */
+
+ }, {
+ key: "setWritingStyle",
+ value: function setWritingStyle(writingStyle) {
+ this.editor.setWritingStyle(writingStyle);
+ }
+ }]);
+
+ return Cherry;
+ }(CherryStatic);
+
+ _defineProperty(Cherry, "initialized", false);
+
+ _defineProperty(Cherry, "config", {
+ /** @type {Partial} */
+ defaults: defaultConfig$1
+ });
+
+ /**
+ * Copyright (C) 2021 THL A29 Limited, a Tencent company.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ if (window) {
+ // @ts-ignore
+ window.Cherry = Cherry;
+ }
+
+ function ownKeys$a(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols$2) { var symbols = getOwnPropertySymbols$2(object); enumerableOnly && (symbols = filter$3(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+ function _objectSpread$9(target) { for (var i = 1; i < arguments.length; i++) { var _context4, _context5; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$3(_context4 = ownKeys$a(Object(source), !0)).call(_context4, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors$2 ? defineProperties$2(target, getOwnPropertyDescriptors$2(source)) : forEach$3(_context5 = ownKeys$a(Object(source))).call(_context5, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
+ var DEFAULT_OPTIONS = {
+ // TODO: themes
+ theme: 'default',
+ altFontFamily: 'sans-serif',
+ fontFamily: 'sans-serif',
+ themeCSS: '.label foreignObject { font-size: 90%; overflow: visible; } .label { font-family: sans-serif; }',
+ flowchart: {
+ useMaxWidth: false
+ },
+ sequence: {
+ useMaxWidth: false
+ },
+ startOnLoad: false,
+ logLevel: 5 // fontFamily: 'Arial, monospace'
+
+ };
+
+ var MermaidCodeEngine = /*#__PURE__*/function () {
+ function MermaidCodeEngine() {
+ var mermaidOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ _classCallCheck(this, MermaidCodeEngine);
+
+ _defineProperty(this, "mermaidAPIRefs", null);
+
+ _defineProperty(this, "options", DEFAULT_OPTIONS);
+
+ _defineProperty(this, "dom", null);
+
+ _defineProperty(this, "mermaidCanvas", null);
+
+ var mermaid = mermaidOptions.mermaid,
+ mermaidAPI = mermaidOptions.mermaidAPI;
+
+ if (!mermaidAPI && !window.mermaidAPI && (!mermaid || !mermaid.mermaidAPI) && (!window.mermaid || !window.mermaid.mermaidAPI)) {
+ throw new Error('code-block-mermaid-plugin[init]: Package mermaid or mermaidAPI not found.');
+ }
+
+ this.options = _objectSpread$9(_objectSpread$9({}, DEFAULT_OPTIONS), mermaidOptions || {});
+ this.mermaidAPIRefs = mermaidAPI || window.mermaidAPI || mermaid.mermaidAPI || window.mermaid.mermaidAPI;
+ delete this.options.mermaid;
+ delete this.options.mermaidAPI;
+ this.mermaidAPIRefs.initialize(this.options);
+ }
+
+ _createClass(MermaidCodeEngine, [{
+ key: "mountMermaidCanvas",
+ value: function mountMermaidCanvas($engine) {
+ if (this.mermaidCanvas && document.body.contains(this.mermaidCanvas)) {
+ return;
+ }
+
+ this.mermaidCanvas = document.createElement('div');
+ this.mermaidCanvas.style = 'width:1024px;opacity:0;position:fixed;top:100%;';
+ var container = $engine.$cherry.wrapperDom || document.body;
+ container.appendChild(this.mermaidCanvas);
+ }
+ /**
+ * 转换svg为img,如果出错则直出svg
+ * @param {string} svgCode
+ * @param {string} graphId
+ * @returns {string}
+ */
+
+ }, {
+ key: "convertMermaidSvgToImg",
+ value: function convertMermaidSvgToImg(svgCode, graphId) {
+ var domParser = new DOMParser();
+ var svgHtml;
+
+ var injectSvgFallback = function injectSvgFallback(svg) {
+ return svg.replace('");
+ }
+ } else {
+ svgHtml = injectSvgFallback(svgCode);
+ }
+ } catch (e) {
+ svgHtml = injectSvgFallback(svgCode);
+ }
+
+ return svgHtml;
+ }
+ }, {
+ key: "render",
+ value: function render(src, sign, $engine) {
+ var _context3,
+ _config$svg2img,
+ _this = this;
+
+ var config = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+ var $sign = sign;
+
+ if (!$sign) {
+ $sign = Math.round(Math.random() * 100000000);
+ }
+
+ this.mountMermaidCanvas($engine);
+ var html; // 多实例的情况下相同的内容ID相同会导致mermaid渲染异常
+ // 需要通过添加时间戳使得多次渲染相同内容的图像ID唯一
+ // 图像渲染节流在CodeBlock Hook内部控制
+
+ var graphId = concat$5(_context3 = "mermaid-".concat($sign, "-")).call(_context3, new Date().getTime());
+
+ this.svg2img = (_config$svg2img = config === null || config === void 0 ? void 0 : config.svg2img) !== null && _config$svg2img !== void 0 ? _config$svg2img : false;
+
+ try {
+ this.mermaidAPIRefs.render(graphId, src, function (svgCode) {
+ var fixedSvg = svgCode.replace(/\s*markerUnits="0"/g, '').replace(/\s*x="NaN"/g, '').replace(/
/g, '
');
+ html = _this.convertMermaidSvgToImg(fixedSvg, graphId);
+ }, this.mermaidCanvas);
+ } catch (e) {
+ return e === null || e === void 0 ? void 0 : e.str;
+ }
+
+ return html;
+ }
+ }], [{
+ key: "install",
+ value: function install(cherryOptions) {
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
+
+ mergeWith_1(cherryOptions, {
+ engine: {
+ syntax: {
+ codeBlock: {
+ customRenderer: {
+ mermaid: _construct(MermaidCodeEngine, args)
+ }
+ }
+ }
+ }
+ });
+ }
+ }]);
+
+ return MermaidCodeEngine;
+ }();
+
+ _defineProperty(MermaidCodeEngine, "TYPE", 'figure');
+
+ // @ts-nocheck
+
+ /*
+ * $Id: rawdeflate.js,v 0.3 2009/03/01 19:05:05 dankogai Exp dankogai $
+ *
+ * Original:
+ * http://www.onicos.com/staff/iz/amuse/javascript/expert/deflate.txt
+ */
+ // if run as a web worker, respond to messages by deflating them
+ var deflate = function () {
+ /* Copyright (C) 1999 Masanao Izumo
+ * Version: 1.0.1
+ * LastModified: Dec 25 1999
+ */
+
+ /* Interface:
+ * data = deflate(src);
+ */
+
+ /* constant parameters */
+ var zip_WSIZE = 32768; // Sliding Window size
+
+ var zip_STORED_BLOCK = 0;
+ var zip_STATIC_TREES = 1;
+ var zip_DYN_TREES = 2;
+ /* for deflate */
+
+ var zip_DEFAULT_LEVEL = 6;
+ var zip_INBUFSIZ = 32768; // Input buffer size
+
+ var zip_INBUF_EXTRA = 64; // Extra buffer
+
+ var zip_OUTBUFSIZ = 1024 * 8;
+ var zip_window_size = 2 * zip_WSIZE;
+ var zip_MIN_MATCH = 3;
+ var zip_MAX_MATCH = 258;
+ var zip_BITS = 16; // for SMALL_MEM
+
+ var zip_LIT_BUFSIZE = 0x2000;
+ var zip_HASH_BITS = 13; // for MEDIUM_MEM
+ // var zip_LIT_BUFSIZE = 0x4000;
+ // var zip_HASH_BITS = 14;
+ // for BIG_MEM
+ // var zip_LIT_BUFSIZE = 0x8000;
+ // var zip_HASH_BITS = 15;
+ // if(zip_LIT_BUFSIZE > zip_INBUFSIZ)
+ // alert("error: zip_INBUFSIZ is too small");
+ // if((zip_WSIZE<<1) > (1< zip_BITS-1)
+ // alert("error: zip_HASH_BITS is too large");
+ // if(zip_HASH_BITS < 8 || zip_MAX_MATCH != 258)
+ // alert("error: Code too clever");
+
+ var zip_DIST_BUFSIZE = zip_LIT_BUFSIZE;
+ var zip_HASH_SIZE = 1 << zip_HASH_BITS;
+ var zip_HASH_MASK = zip_HASH_SIZE - 1;
+ var zip_WMASK = zip_WSIZE - 1;
+ var zip_NIL = 0; // Tail of hash chains
+
+ var zip_TOO_FAR = 4096;
+ var zip_MIN_LOOKAHEAD = zip_MAX_MATCH + zip_MIN_MATCH + 1;
+ var zip_MAX_DIST = zip_WSIZE - zip_MIN_LOOKAHEAD;
+ var zip_SMALLEST = 1;
+ var zip_MAX_BITS = 15;
+ var zip_MAX_BL_BITS = 7;
+ var zip_LENGTH_CODES = 29;
+ var zip_LITERALS = 256;
+ var zip_END_BLOCK = 256;
+ var zip_L_CODES = zip_LITERALS + 1 + zip_LENGTH_CODES;
+ var zip_D_CODES = 30;
+ var zip_BL_CODES = 19;
+ var zip_REP_3_6 = 16;
+ var zip_REPZ_3_10 = 17;
+ var zip_REPZ_11_138 = 18;
+ var zip_HEAP_SIZE = 2 * zip_L_CODES + 1;
+
+ var zip_H_SHIFT = _parseInt$2((zip_HASH_BITS + zip_MIN_MATCH - 1) / zip_MIN_MATCH);
+ /* variables */
+
+
+ var zip_free_queue;
+ var zip_qhead;
+ var zip_qtail;
+ var zip_initflag;
+ var zip_outbuf = null;
+ var zip_outcnt;
+ var zip_outoff;
+ var zip_complete;
+ var zip_window;
+ var zip_d_buf;
+ var zip_l_buf;
+ var zip_prev;
+ var zip_bi_buf;
+ var zip_bi_valid;
+ var zip_block_start;
+ var zip_ins_h;
+ var zip_hash_head;
+ var zip_prev_match;
+ var zip_match_available;
+ var zip_match_length;
+ var zip_prev_length;
+ var zip_strstart;
+ var zip_match_start;
+ var zip_eofile;
+ var zip_lookahead;
+ var zip_max_chain_length;
+ var zip_max_lazy_match;
+ var zip_compr_level;
+ var zip_good_match;
+ var zip_dyn_ltree;
+ var zip_dyn_dtree;
+ var zip_static_ltree;
+ var zip_static_dtree;
+ var zip_bl_tree;
+ var zip_l_desc;
+ var zip_d_desc;
+ var zip_bl_desc;
+ var zip_bl_count;
+ var zip_heap;
+ var zip_heap_len;
+ var zip_heap_max;
+ var zip_depth;
+ var zip_length_code;
+ var zip_dist_code;
+ var zip_base_length;
+ var zip_base_dist;
+ var zip_flag_buf;
+ var zip_last_lit;
+ var zip_last_dist;
+ var zip_last_flags;
+ var zip_flags;
+ var zip_flag_bit;
+ var zip_opt_len;
+ var zip_static_len;
+ var zip_deflate_data;
+ var zip_deflate_pos;
+ /* objects (deflate) */
+
+ function zip_DeflateCT() {
+ this.fc = 0; // frequency count or bit string
+
+ this.dl = 0; // father node in Huffman tree or length of bit string
+ }
+
+ function zip_DeflateTreeDesc() {
+ this.dyn_tree = null; // the dynamic tree
+
+ this.static_tree = null; // corresponding static tree or NULL
+
+ this.extra_bits = null; // extra bits for each code or NULL
+
+ this.extra_base = 0; // base index for extra_bits
+
+ this.elems = 0; // max number of elements in the tree
+
+ this.max_length = 0; // max bit length for the codes
+
+ this.max_code = 0; // largest code with non zero frequency
+ }
+ /* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+
+ function zip_DeflateConfiguration(a, b, c, d) {
+ this.good_length = a; // reduce lazy search above this match length
+
+ this.max_lazy = b; // do not perform lazy search above this match length
+
+ this.nice_length = c; // quit search above this match length
+
+ this.max_chain = d;
+ }
+
+ function zip_DeflateBuffer() {
+ this.next = null;
+ this.len = 0;
+ this.ptr = new Array(zip_OUTBUFSIZ);
+ this.off = 0;
+ }
+ /* constant tables */
+
+
+ var zip_extra_lbits = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
+ var zip_extra_dbits = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
+ var zip_extra_blbits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7];
+ var zip_bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
+ var zip_configuration_table = [new zip_DeflateConfiguration(0, 0, 0, 0), new zip_DeflateConfiguration(4, 4, 8, 4), new zip_DeflateConfiguration(4, 5, 16, 8), new zip_DeflateConfiguration(4, 6, 32, 32), new zip_DeflateConfiguration(4, 4, 16, 16), new zip_DeflateConfiguration(8, 16, 32, 32), new zip_DeflateConfiguration(8, 16, 128, 128), new zip_DeflateConfiguration(8, 32, 128, 256), new zip_DeflateConfiguration(32, 128, 258, 1024), new zip_DeflateConfiguration(32, 258, 258, 4096)];
+ /* routines (deflate) */
+
+ function zip_deflate_start(level) {
+ var i;
+ if (!level) level = zip_DEFAULT_LEVEL;else if (level < 1) level = 1;else if (level > 9) level = 9;
+ zip_compr_level = level;
+ zip_initflag = false;
+ zip_eofile = false;
+ if (zip_outbuf != null) return;
+ zip_free_queue = zip_qhead = zip_qtail = null;
+ zip_outbuf = new Array(zip_OUTBUFSIZ);
+ zip_window = new Array(zip_window_size);
+ zip_d_buf = new Array(zip_DIST_BUFSIZE);
+ zip_l_buf = new Array(zip_INBUFSIZ + zip_INBUF_EXTRA);
+ zip_prev = new Array(1 << zip_BITS);
+ zip_dyn_ltree = new Array(zip_HEAP_SIZE);
+
+ for (i = 0; i < zip_HEAP_SIZE; i++) {
+ zip_dyn_ltree[i] = new zip_DeflateCT();
+ }
+
+ zip_dyn_dtree = new Array(2 * zip_D_CODES + 1);
+
+ for (i = 0; i < 2 * zip_D_CODES + 1; i++) {
+ zip_dyn_dtree[i] = new zip_DeflateCT();
+ }
+
+ zip_static_ltree = new Array(zip_L_CODES + 2);
+
+ for (i = 0; i < zip_L_CODES + 2; i++) {
+ zip_static_ltree[i] = new zip_DeflateCT();
+ }
+
+ zip_static_dtree = new Array(zip_D_CODES);
+
+ for (i = 0; i < zip_D_CODES; i++) {
+ zip_static_dtree[i] = new zip_DeflateCT();
+ }
+
+ zip_bl_tree = new Array(2 * zip_BL_CODES + 1);
+
+ for (i = 0; i < 2 * zip_BL_CODES + 1; i++) {
+ zip_bl_tree[i] = new zip_DeflateCT();
+ }
+
+ zip_l_desc = new zip_DeflateTreeDesc();
+ zip_d_desc = new zip_DeflateTreeDesc();
+ zip_bl_desc = new zip_DeflateTreeDesc();
+ zip_bl_count = new Array(zip_MAX_BITS + 1);
+ zip_heap = new Array(2 * zip_L_CODES + 1);
+ zip_depth = new Array(2 * zip_L_CODES + 1);
+ zip_length_code = new Array(zip_MAX_MATCH - zip_MIN_MATCH + 1);
+ zip_dist_code = new Array(512);
+ zip_base_length = new Array(zip_LENGTH_CODES);
+ zip_base_dist = new Array(zip_D_CODES);
+ zip_flag_buf = new Array(_parseInt$2(zip_LIT_BUFSIZE / 8));
+ }
+
+ function zip_reuse_queue(p) {
+ p.next = zip_free_queue;
+ zip_free_queue = p;
+ }
+
+ function zip_new_queue() {
+ var p;
+
+ if (zip_free_queue != null) {
+ p = zip_free_queue;
+ zip_free_queue = zip_free_queue.next;
+ } else p = new zip_DeflateBuffer();
+
+ p.next = null;
+ p.len = p.off = 0;
+ return p;
+ }
+
+ function zip_head1(i) {
+ return zip_prev[zip_WSIZE + i];
+ }
+
+ function zip_head2(i, val) {
+ return zip_prev[zip_WSIZE + i] = val;
+ }
+ /* put_byte is used for the compressed output, put_ubyte for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_ubyte
+ * (to be cleaned up).
+ */
+
+
+ function zip_put_byte(c) {
+ zip_outbuf[zip_outoff + zip_outcnt++] = c;
+ if (zip_outoff + zip_outcnt == zip_OUTBUFSIZ) zip_qoutbuf();
+ }
+ /* Output a 16 bit value, lsb first */
+
+
+ function zip_put_short(w) {
+ w &= 0xffff;
+
+ if (zip_outoff + zip_outcnt < zip_OUTBUFSIZ - 2) {
+ zip_outbuf[zip_outoff + zip_outcnt++] = w & 0xff;
+ zip_outbuf[zip_outoff + zip_outcnt++] = w >>> 8;
+ } else {
+ zip_put_byte(w & 0xff);
+ zip_put_byte(w >>> 8);
+ }
+ }
+ /* ==========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of s are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+
+
+ function zip_INSERT_STRING() {
+ zip_ins_h = (zip_ins_h << zip_H_SHIFT ^ zip_window[zip_strstart + zip_MIN_MATCH - 1] & 0xff) & zip_HASH_MASK;
+ zip_hash_head = zip_head1(zip_ins_h);
+ zip_prev[zip_strstart & zip_WMASK] = zip_hash_head;
+ zip_head2(zip_ins_h, zip_strstart);
+ }
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+
+ function zip_SEND_CODE(c, tree) {
+ zip_send_bits(tree[c].fc, tree[c].dl);
+ }
+ /* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+
+ function zip_D_CODE(dist) {
+ return (dist < 256 ? zip_dist_code[dist] : zip_dist_code[256 + (dist >> 7)]) & 0xff;
+ }
+ /* ==========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+
+
+ function zip_SMALLER(tree, n, m) {
+ return tree[n].fc < tree[m].fc || tree[n].fc == tree[m].fc && zip_depth[n] <= zip_depth[m];
+ }
+ /* ==========================================================================
+ * read string data
+ */
+
+
+ function zip_read_buff(buff, offset, n) {
+ var i;
+
+ for (i = 0; i < n && zip_deflate_pos < zip_deflate_data.length; i++) {
+ buff[offset + i] = zip_deflate_data.charCodeAt(zip_deflate_pos++) & 0xff;
+ }
+
+ return i;
+ }
+ /* ==========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+
+
+ function zip_lm_init() {
+ var j;
+ /* Initialize the hash table. */
+
+ for (j = 0; j < zip_HASH_SIZE; j++) {
+ // zip_head2(j, zip_NIL);
+ zip_prev[zip_WSIZE + j] = 0;
+ }
+ /* prev will be initialized on the fly */
+
+ /* Set the default configuration parameters:
+ */
+
+
+ zip_max_lazy_match = zip_configuration_table[zip_compr_level].max_lazy;
+ zip_good_match = zip_configuration_table[zip_compr_level].good_length;
+ zip_max_chain_length = zip_configuration_table[zip_compr_level].max_chain;
+ zip_strstart = 0;
+ zip_block_start = 0;
+ zip_lookahead = zip_read_buff(zip_window, 0, 2 * zip_WSIZE);
+
+ if (zip_lookahead <= 0) {
+ zip_eofile = true;
+ zip_lookahead = 0;
+ return;
+ }
+
+ zip_eofile = false;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+
+ while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) {
+ zip_fill_window();
+ }
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+
+
+ zip_ins_h = 0;
+
+ for (j = 0; j < zip_MIN_MATCH - 1; j++) {
+ // UPDATE_HASH(ins_h, window[j]);
+ zip_ins_h = (zip_ins_h << zip_H_SHIFT ^ zip_window[j] & 0xff) & zip_HASH_MASK;
+ }
+ }
+ /* ==========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+
+ function zip_longest_match(cur_match) {
+ var chain_length = zip_max_chain_length; // max hash chain length
+
+ var scanp = zip_strstart; // current string
+
+ var matchp; // matched string
+
+ var len; // length of current match
+
+ var best_len = zip_prev_length; // best match length so far
+
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+ var limit = zip_strstart > zip_MAX_DIST ? zip_strstart - zip_MAX_DIST : zip_NIL;
+ var strendp = zip_strstart + zip_MAX_MATCH;
+ var scan_end1 = zip_window[scanp + best_len - 1];
+ var scan_end = zip_window[scanp + best_len];
+ /* Do not waste too much time if we already have a good match: */
+
+ if (zip_prev_length >= zip_good_match) chain_length >>= 2; // Assert(encoder->strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ // Assert(cur_match < encoder->strstart, "no future");
+ matchp = cur_match;
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+
+ if (zip_window[matchp + best_len] != scan_end || zip_window[matchp + best_len - 1] != scan_end1 || zip_window[matchp] != zip_window[scanp] || zip_window[++matchp] != zip_window[scanp + 1]) {
+ continue;
+ }
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+
+
+ scanp += 2;
+ matchp++;
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+
+ do {} while (zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && zip_window[++scanp] == zip_window[++matchp] && scanp < strendp);
+
+ len = zip_MAX_MATCH - (strendp - scanp);
+ scanp = strendp - zip_MAX_MATCH;
+
+ if (len > best_len) {
+ zip_match_start = cur_match;
+ best_len = len;
+
+ {
+ if (len >= zip_MAX_MATCH) break;
+ }
+
+ scan_end1 = zip_window[scanp + best_len - 1];
+ scan_end = zip_window[scanp + best_len];
+ }
+ } while ((cur_match = zip_prev[cur_match & zip_WMASK]) > limit && --chain_length != 0);
+
+ return best_len;
+ }
+ /* ==========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ * file reads are performed for at least two bytes (required for the
+ * translate_eol option).
+ */
+
+
+ function zip_fill_window() {
+ var n;
+ var m; // Amount of free space at the end of the window.
+
+ var more = zip_window_size - zip_lookahead - zip_strstart;
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+
+ if (more == -1) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+ } else if (zip_strstart >= zip_WSIZE + zip_MAX_DIST) {
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ // Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
+ // System.arraycopy(window, WSIZE, window, 0, WSIZE);
+ for (n = 0; n < zip_WSIZE; n++) {
+ zip_window[n] = zip_window[n + zip_WSIZE];
+ }
+
+ zip_match_start -= zip_WSIZE;
+ zip_strstart -= zip_WSIZE;
+ /* we now have strstart >= MAX_DIST: */
+
+ zip_block_start -= zip_WSIZE;
+
+ for (n = 0; n < zip_HASH_SIZE; n++) {
+ m = zip_head1(n);
+ zip_head2(n, m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL);
+ }
+
+ for (n = 0; n < zip_WSIZE; n++) {
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ m = zip_prev[n];
+ zip_prev[n] = m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL;
+ }
+
+ more += zip_WSIZE;
+ } // At this point, more >= 2
+
+
+ if (!zip_eofile) {
+ n = zip_read_buff(zip_window, zip_strstart + zip_lookahead, more);
+ if (n <= 0) zip_eofile = true;else zip_lookahead += n;
+ }
+ }
+ /* ==========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluationof matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+
+
+ function zip_deflate_fast() {
+ while (zip_lookahead != 0 && zip_qhead == null) {
+ var flush; // set if current block must be flushed
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+
+ zip_INSERT_STRING();
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+
+ if (zip_hash_head != zip_NIL && zip_strstart - zip_hash_head <= zip_MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ zip_match_length = zip_longest_match(zip_hash_head);
+ /* longest_match() sets match_start */
+
+ if (zip_match_length > zip_lookahead) zip_match_length = zip_lookahead;
+ }
+
+ if (zip_match_length >= zip_MIN_MATCH) {
+ // check_match(strstart, match_start, match_length);
+ flush = zip_ct_tally(zip_strstart - zip_match_start, zip_match_length - zip_MIN_MATCH);
+ zip_lookahead -= zip_match_length;
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+
+ if (zip_match_length <= zip_max_lazy_match) {
+ zip_match_length--; // string at strstart already in hash table
+
+ do {
+ zip_strstart++;
+ zip_INSERT_STRING();
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since
+ * the next lookahead bytes will be emitted as literals.
+ */
+ } while (--zip_match_length != 0);
+
+ zip_strstart++;
+ } else {
+ zip_strstart += zip_match_length;
+ zip_match_length = 0;
+ zip_ins_h = zip_window[zip_strstart] & 0xff; // UPDATE_HASH(ins_h, window[strstart + 1]);
+
+ zip_ins_h = (zip_ins_h << zip_H_SHIFT ^ zip_window[zip_strstart + 1] & 0xff) & zip_HASH_MASK; // #if MIN_MATCH != 3
+ // Call UPDATE_HASH() MIN_MATCH-3 more times
+ // #endif
+ }
+ } else {
+ /* No match, output a literal byte */
+ flush = zip_ct_tally(0, zip_window[zip_strstart] & 0xff);
+ zip_lookahead--;
+ zip_strstart++;
+ }
+
+ if (flush) {
+ zip_flush_block(0);
+ zip_block_start = zip_strstart;
+ }
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+
+
+ while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) {
+ zip_fill_window();
+ }
+ }
+ }
+
+ function zip_deflate_better() {
+ /* Process the input block. */
+ while (zip_lookahead != 0 && zip_qhead == null) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ zip_INSERT_STRING();
+ /* Find the longest match, discarding those <= prev_length.
+ */
+
+ zip_prev_length = zip_match_length;
+ zip_prev_match = zip_match_start;
+ zip_match_length = zip_MIN_MATCH - 1;
+
+ if (zip_hash_head != zip_NIL && zip_prev_length < zip_max_lazy_match && zip_strstart - zip_hash_head <= zip_MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ zip_match_length = zip_longest_match(zip_hash_head);
+ /* longest_match() sets match_start */
+
+ if (zip_match_length > zip_lookahead) zip_match_length = zip_lookahead;
+ /* Ignore a length 3 match if it is too distant: */
+
+ if (zip_match_length == zip_MIN_MATCH && zip_strstart - zip_match_start > zip_TOO_FAR) {
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ zip_match_length--;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+
+
+ if (zip_prev_length >= zip_MIN_MATCH && zip_match_length <= zip_prev_length) {
+ var flush; // set if current block must be flushed
+ // check_match(strstart - 1, prev_match, prev_length);
+
+ flush = zip_ct_tally(zip_strstart - 1 - zip_prev_match, zip_prev_length - zip_MIN_MATCH);
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+
+ zip_lookahead -= zip_prev_length - 1;
+ zip_prev_length -= 2;
+
+ do {
+ zip_strstart++;
+ zip_INSERT_STRING();
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since the
+ * next lookahead bytes will always be emitted as literals.
+ */
+ } while (--zip_prev_length != 0);
+
+ zip_match_available = 0;
+ zip_match_length = zip_MIN_MATCH - 1;
+ zip_strstart++;
+
+ if (flush) {
+ zip_flush_block(0);
+ zip_block_start = zip_strstart;
+ }
+ } else if (zip_match_available != 0) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ if (zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff)) {
+ zip_flush_block(0);
+ zip_block_start = zip_strstart;
+ }
+
+ zip_strstart++;
+ zip_lookahead--;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ zip_match_available = 1;
+ zip_strstart++;
+ zip_lookahead--;
+ }
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+
+
+ while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile) {
+ zip_fill_window();
+ }
+ }
+ }
+
+ function zip_init_deflate() {
+ if (zip_eofile) return;
+ zip_bi_buf = 0;
+ zip_bi_valid = 0;
+ zip_ct_init();
+ zip_lm_init();
+ zip_qhead = null;
+ zip_outcnt = 0;
+ zip_outoff = 0;
+
+ if (zip_compr_level <= 3) {
+ zip_prev_length = zip_MIN_MATCH - 1;
+ zip_match_length = 0;
+ } else {
+ zip_match_length = zip_MIN_MATCH - 1;
+ zip_match_available = 0;
+ }
+
+ zip_complete = false;
+ }
+ /* ==========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+
+
+ function zip_deflate_internal(buff, off, buff_size) {
+ var n;
+
+ if (!zip_initflag) {
+ zip_init_deflate();
+ zip_initflag = true;
+
+ if (zip_lookahead == 0) {
+ // empty
+ zip_complete = true;
+ return 0;
+ }
+ }
+
+ if ((n = zip_qcopy(buff, off, buff_size)) == buff_size) return buff_size;
+ if (zip_complete) return n;
+ if (zip_compr_level <= 3) // optimized for speed
+ zip_deflate_fast();else zip_deflate_better();
+
+ if (zip_lookahead == 0) {
+ if (zip_match_available != 0) zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff);
+ zip_flush_block(1);
+ zip_complete = true;
+ }
+
+ return n + zip_qcopy(buff, n + off, buff_size - n);
+ }
+
+ function zip_qcopy(buff, off, buff_size) {
+ var n;
+ var i;
+ var j;
+ n = 0;
+
+ while (zip_qhead != null && n < buff_size) {
+ i = buff_size - n;
+ if (i > zip_qhead.len) i = zip_qhead.len; // System.arraycopy(qhead.ptr, qhead.off, buff, off + n, i);
+
+ for (j = 0; j < i; j++) {
+ buff[off + n + j] = zip_qhead.ptr[zip_qhead.off + j];
+ }
+
+ zip_qhead.off += i;
+ zip_qhead.len -= i;
+ n += i;
+
+ if (zip_qhead.len == 0) {
+ var p;
+ p = zip_qhead;
+ zip_qhead = zip_qhead.next;
+ zip_reuse_queue(p);
+ }
+ }
+
+ if (n == buff_size) return n;
+
+ if (zip_outoff < zip_outcnt) {
+ i = buff_size - n;
+ if (i > zip_outcnt - zip_outoff) i = zip_outcnt - zip_outoff; // System.arraycopy(outbuf, outoff, buff, off + n, i);
+
+ for (j = 0; j < i; j++) {
+ buff[off + n + j] = zip_outbuf[zip_outoff + j];
+ }
+
+ zip_outoff += i;
+ n += i;
+ if (zip_outcnt == zip_outoff) zip_outcnt = zip_outoff = 0;
+ }
+
+ return n;
+ }
+ /* ==========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+
+
+ function zip_ct_init() {
+ var n; // iterates over tree elements
+
+ var bits; // bit counter
+
+ var length; // length value
+
+ var code; // code value
+
+ var dist; // distance index
+
+ if (zip_static_dtree[0].dl != 0) return; // ct_init already called
+
+ zip_l_desc.dyn_tree = zip_dyn_ltree;
+ zip_l_desc.static_tree = zip_static_ltree;
+ zip_l_desc.extra_bits = zip_extra_lbits;
+ zip_l_desc.extra_base = zip_LITERALS + 1;
+ zip_l_desc.elems = zip_L_CODES;
+ zip_l_desc.max_length = zip_MAX_BITS;
+ zip_l_desc.max_code = 0;
+ zip_d_desc.dyn_tree = zip_dyn_dtree;
+ zip_d_desc.static_tree = zip_static_dtree;
+ zip_d_desc.extra_bits = zip_extra_dbits;
+ zip_d_desc.extra_base = 0;
+ zip_d_desc.elems = zip_D_CODES;
+ zip_d_desc.max_length = zip_MAX_BITS;
+ zip_d_desc.max_code = 0;
+ zip_bl_desc.dyn_tree = zip_bl_tree;
+ zip_bl_desc.static_tree = null;
+ zip_bl_desc.extra_bits = zip_extra_blbits;
+ zip_bl_desc.extra_base = 0;
+ zip_bl_desc.elems = zip_BL_CODES;
+ zip_bl_desc.max_length = zip_MAX_BL_BITS;
+ zip_bl_desc.max_code = 0; // Initialize the mapping length (0..255) -> length code (0..28)
+
+ length = 0;
+
+ for (code = 0; code < zip_LENGTH_CODES - 1; code++) {
+ zip_base_length[code] = length;
+
+ for (n = 0; n < 1 << zip_extra_lbits[code]; n++) {
+ zip_length_code[length++] = code;
+ }
+ } // Assert (length == 256, "ct_init: length != 256");
+
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+
+
+ zip_length_code[length - 1] = code;
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+
+ dist = 0;
+
+ for (code = 0; code < 16; code++) {
+ zip_base_dist[code] = dist;
+
+ for (n = 0; n < 1 << zip_extra_dbits[code]; n++) {
+ zip_dist_code[dist++] = code;
+ }
+ } // Assert (dist == 256, "ct_init: dist != 256");
+
+
+ dist >>= 7; // from now on, all distances are divided by 128
+
+ for (; code < zip_D_CODES; code++) {
+ zip_base_dist[code] = dist << 7;
+
+ for (n = 0; n < 1 << zip_extra_dbits[code] - 7; n++) {
+ zip_dist_code[256 + dist++] = code;
+ }
+ } // Assert (dist == 256, "ct_init: 256+dist != 512");
+ // Construct the codes of the static literal tree
+
+
+ for (bits = 0; bits <= zip_MAX_BITS; bits++) {
+ zip_bl_count[bits] = 0;
+ }
+
+ n = 0;
+
+ while (n <= 143) {
+ zip_static_ltree[n++].dl = 8;
+ zip_bl_count[8]++;
+ }
+
+ while (n <= 255) {
+ zip_static_ltree[n++].dl = 9;
+ zip_bl_count[9]++;
+ }
+
+ while (n <= 279) {
+ zip_static_ltree[n++].dl = 7;
+ zip_bl_count[7]++;
+ }
+
+ while (n <= 287) {
+ zip_static_ltree[n++].dl = 8;
+ zip_bl_count[8]++;
+ }
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+
+
+ zip_gen_codes(zip_static_ltree, zip_L_CODES + 1);
+ /* The static distance tree is trivial: */
+
+ for (n = 0; n < zip_D_CODES; n++) {
+ zip_static_dtree[n].dl = 5;
+ zip_static_dtree[n].fc = zip_bi_reverse(n, 5);
+ } // Initialize the first block of the first file:
+
+
+ zip_init_block();
+ }
+ /* ==========================================================================
+ * Initialize a new block.
+ */
+
+
+ function zip_init_block() {
+ var n; // iterates over tree elements
+ // Initialize the trees.
+
+ for (n = 0; n < zip_L_CODES; n++) {
+ zip_dyn_ltree[n].fc = 0;
+ }
+
+ for (n = 0; n < zip_D_CODES; n++) {
+ zip_dyn_dtree[n].fc = 0;
+ }
+
+ for (n = 0; n < zip_BL_CODES; n++) {
+ zip_bl_tree[n].fc = 0;
+ }
+
+ zip_dyn_ltree[zip_END_BLOCK].fc = 1;
+ zip_opt_len = zip_static_len = 0;
+ zip_last_lit = zip_last_dist = zip_last_flags = 0;
+ zip_flags = 0;
+ zip_flag_bit = 1;
+ }
+ /* ==========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+
+
+ function zip_pqdownheap(tree, // the tree to restore
+ k) {
+ // node to move down
+ var v = zip_heap[k];
+ var j = k << 1; // left son of k
+
+ while (j <= zip_heap_len) {
+ // Set j to the smallest of the two sons:
+ if (j < zip_heap_len && zip_SMALLER(tree, zip_heap[j + 1], zip_heap[j])) j++; // Exit if v is smaller than both sons
+
+ if (zip_SMALLER(tree, v, zip_heap[j])) break; // Exchange v with the smallest son
+
+ zip_heap[k] = zip_heap[j];
+ k = j; // And continue down the tree, setting j to the left son of k
+
+ j <<= 1;
+ }
+
+ zip_heap[k] = v;
+ }
+ /* ==========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+
+
+ function zip_gen_bitlen(desc) {
+ // the tree descriptor
+ var tree = desc.dyn_tree;
+ var extra = desc.extra_bits;
+ var base = desc.extra_base;
+ var max_code = desc.max_code;
+ var max_length = desc.max_length;
+ var stree = desc.static_tree;
+ var h; // heap index
+
+ var n;
+ var m; // iterate over the tree elements
+
+ var bits; // bit length
+
+ var xbits; // extra bits
+
+ var f; // frequency
+
+ var overflow = 0; // number of elements with bit length too large
+
+ for (bits = 0; bits <= zip_MAX_BITS; bits++) {
+ zip_bl_count[bits] = 0;
+ }
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+
+
+ tree[zip_heap[zip_heap_max]].dl = 0; // root of the heap
+
+ for (h = zip_heap_max + 1; h < zip_HEAP_SIZE; h++) {
+ n = zip_heap[h];
+ bits = tree[tree[n].dl].dl + 1;
+
+ if (bits > max_length) {
+ bits = max_length;
+ overflow++;
+ }
+
+ tree[n].dl = bits; // We overwrite tree[n].dl which is no longer needed
+
+ if (n > max_code) continue; // not a leaf node
+
+ zip_bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n - base];
+ f = tree[n].fc;
+ zip_opt_len += f * (bits + xbits);
+ if (stree != null) zip_static_len += f * (stree[n].dl + xbits);
+ }
+
+ if (overflow == 0) return; // This happens for example on obj2 and pic of the Calgary corpus
+ // Find the first bit length which could increase:
+
+ do {
+ bits = max_length - 1;
+
+ while (zip_bl_count[bits] == 0) {
+ bits--;
+ }
+
+ zip_bl_count[bits]--; // move one leaf down the tree
+
+ zip_bl_count[bits + 1] += 2; // move one overflow item as its brother
+
+ zip_bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+
+ overflow -= 2;
+ } while (overflow > 0);
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+
+
+ for (bits = max_length; bits != 0; bits--) {
+ n = zip_bl_count[bits];
+
+ while (n != 0) {
+ m = zip_heap[--h];
+ if (m > max_code) continue;
+
+ if (tree[m].dl != bits) {
+ zip_opt_len += (bits - tree[m].dl) * tree[m].fc;
+ tree[m].fc = bits;
+ }
+
+ n--;
+ }
+ }
+ }
+ /* ==========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+
+
+ function zip_gen_codes(tree, // the tree to decorate
+ max_code) {
+ // largest code with non zero frequency
+ var next_code = new Array(zip_MAX_BITS + 1); // next code value for each bit length
+
+ var code = 0; // running code value
+
+ var bits; // bit index
+
+ var n; // code index
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+
+ for (bits = 1; bits <= zip_MAX_BITS; bits++) {
+ code = code + zip_bl_count[bits - 1] << 1;
+ next_code[bits] = code;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ // Assert (code + encoder->bl_count[MAX_BITS]-1 == (1<> 1; n >= 1; n--) {
+ zip_pqdownheap(tree, n);
+ }
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+
+
+ do {
+ n = zip_heap[zip_SMALLEST];
+ zip_heap[zip_SMALLEST] = zip_heap[zip_heap_len--];
+ zip_pqdownheap(tree, zip_SMALLEST);
+ m = zip_heap[zip_SMALLEST]; // m = node of next least frequency
+ // keep the nodes sorted by frequency
+
+ zip_heap[--zip_heap_max] = n;
+ zip_heap[--zip_heap_max] = m; // Create a new node father of n and m
+
+ tree[node].fc = tree[n].fc + tree[m].fc; // depth[node] = (char)(MAX(depth[n], depth[m]) + 1);
+
+ if (zip_depth[n] > zip_depth[m] + 1) zip_depth[node] = zip_depth[n];else zip_depth[node] = zip_depth[m] + 1;
+ tree[n].dl = tree[m].dl = node; // and insert the new node in the heap
+
+ zip_heap[zip_SMALLEST] = node++;
+ zip_pqdownheap(tree, zip_SMALLEST);
+ } while (zip_heap_len >= 2);
+
+ zip_heap[--zip_heap_max] = zip_heap[zip_SMALLEST];
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+
+ zip_gen_bitlen(desc); // The field len is now set, we can generate the bit codes
+
+ zip_gen_codes(tree, max_code);
+ }
+ /* ==========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+
+
+ function zip_scan_tree(tree, // the tree to be scanned
+ max_code) {
+ // and its largest code of non zero frequency
+ var n; // iterates over all tree elements
+
+ var prevlen = -1; // last emitted length
+
+ var curlen; // length of current code
+
+ var nextlen = tree[0].dl; // length of next code
+
+ var count = 0; // repeat count of the current code
+
+ var max_count = 7; // max repeat count
+
+ var min_count = 4; // min repeat count
+
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ }
+
+ tree[max_code + 1].dl = 0xffff; // guard
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen;
+ nextlen = tree[n + 1].dl;
+ if (++count < max_count && curlen == nextlen) continue;else if (count < min_count) zip_bl_tree[curlen].fc += count;else if (curlen != 0) {
+ if (curlen != prevlen) zip_bl_tree[curlen].fc++;
+ zip_bl_tree[zip_REP_3_6].fc++;
+ } else if (count <= 10) zip_bl_tree[zip_REPZ_3_10].fc++;else zip_bl_tree[zip_REPZ_11_138].fc++;
+ count = 0;
+ prevlen = curlen;
+
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6;
+ min_count = 3;
+ } else {
+ max_count = 7;
+ min_count = 4;
+ }
+ }
+ }
+ /* ==========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+
+
+ function zip_send_tree(tree, // the tree to be scanned
+ max_code) {
+ // and its largest code of non zero frequency
+ var n; // iterates over all tree elements
+
+ var prevlen = -1; // last emitted length
+
+ var curlen; // length of current code
+
+ var nextlen = tree[0].dl; // length of next code
+
+ var count = 0; // repeat count of the current code
+
+ var max_count = 7; // max repeat count
+
+ var min_count = 4;
+ /* guard already set */
+ // min repeat count
+
+ /* tree[max_code+1].dl = -1; */
+
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ }
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen;
+ nextlen = tree[n + 1].dl;
+
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do {
+ zip_SEND_CODE(curlen, zip_bl_tree);
+ } while (--count != 0);
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ zip_SEND_CODE(curlen, zip_bl_tree);
+ count--;
+ } // Assert(count >= 3 && count <= 6, " 3_6?");
+
+
+ zip_SEND_CODE(zip_REP_3_6, zip_bl_tree);
+ zip_send_bits(count - 3, 2);
+ } else if (count <= 10) {
+ zip_SEND_CODE(zip_REPZ_3_10, zip_bl_tree);
+ zip_send_bits(count - 3, 3);
+ } else {
+ zip_SEND_CODE(zip_REPZ_11_138, zip_bl_tree);
+ zip_send_bits(count - 11, 7);
+ }
+
+ count = 0;
+ prevlen = curlen;
+
+ if (nextlen == 0) {
+ max_count = 138;
+ min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6;
+ min_count = 3;
+ } else {
+ max_count = 7;
+ min_count = 4;
+ }
+ }
+ }
+ /* ==========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+
+
+ function zip_build_bl_tree() {
+ var max_blindex; // index of last bit length code of non zero freq
+ // Determine the bit length frequencies for literal and distance trees
+
+ zip_scan_tree(zip_dyn_ltree, zip_l_desc.max_code);
+ zip_scan_tree(zip_dyn_dtree, zip_d_desc.max_code); // Build the bit length tree:
+
+ zip_build_tree(zip_bl_desc);
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+
+ for (max_blindex = zip_BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+ if (zip_bl_tree[zip_bl_order[max_blindex]].dl != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+
+
+ zip_opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; // Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ // encoder->opt_len, encoder->static_len));
+
+ return max_blindex;
+ }
+ /* ==========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+
+
+ function zip_send_all_trees(lcodes, dcodes, blcodes) {
+ // number of codes for each tree
+ var rank; // index in bl_order
+ // Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ // Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ // "too many codes");
+ // Tracev((stderr, "\nbl counts: "));
+
+ zip_send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
+
+ zip_send_bits(dcodes - 1, 5);
+ zip_send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
+
+ for (rank = 0; rank < blcodes; rank++) {
+ // Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ zip_send_bits(zip_bl_tree[zip_bl_order[rank]].dl, 3);
+ } // send the literal tree
+
+
+ zip_send_tree(zip_dyn_ltree, lcodes - 1); // send the distance tree
+
+ zip_send_tree(zip_dyn_dtree, dcodes - 1);
+ }
+ /* ==========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+
+
+ function zip_flush_block(eof) {
+ // true if this is the last block for a file
+ var opt_lenb;
+ var static_lenb; // opt_len and static_len in bytes
+
+ var max_blindex; // index of last bit length code of non zero freq
+
+ var stored_len; // length of input block
+
+ stored_len = zip_strstart - zip_block_start;
+ zip_flag_buf[zip_last_flags] = zip_flags; // Save the flags for the last 8 items
+ // Construct the literal and distance trees
+
+ zip_build_tree(zip_l_desc); // Tracev((stderr, "\nlit data: dyn %ld, stat %ld",
+ // encoder->opt_len, encoder->static_len));
+
+ zip_build_tree(zip_d_desc); // Tracev((stderr, "\ndist data: dyn %ld, stat %ld",
+ // encoder->opt_len, encoder->static_len));
+
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+
+ max_blindex = zip_build_bl_tree(); // Determine the best encoding. Compute first the block length in bytes
+
+ opt_lenb = zip_opt_len + 3 + 7 >> 3;
+ static_lenb = zip_static_len + 3 + 7 >> 3; // Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ // opt_lenb, encoder->opt_len,
+ // static_lenb, encoder->static_len, stored_len,
+ // encoder->last_lit, encoder->last_dist));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ if (stored_len + 4 <= opt_lenb && // 4: two words for the lengths
+ zip_block_start >= 0) {
+ var i;
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+
+ zip_send_bits((zip_STORED_BLOCK << 1) + eof, 3);
+ /* send block type */
+
+ zip_bi_windup();
+ /* align on byte boundary */
+
+ zip_put_short(stored_len);
+ zip_put_short(~stored_len); // copy block
+
+ /*
+ p = &window[block_start];
+ for(i = 0; i < stored_len; i++)
+ put_byte(p[i]);
+ */
+
+ for (i = 0; i < stored_len; i++) {
+ zip_put_byte(zip_window[zip_block_start + i]);
+ }
+ } else if (static_lenb == opt_lenb) {
+ zip_send_bits((zip_STATIC_TREES << 1) + eof, 3);
+ zip_compress_block(zip_static_ltree, zip_static_dtree);
+ } else {
+ zip_send_bits((zip_DYN_TREES << 1) + eof, 3);
+ zip_send_all_trees(zip_l_desc.max_code + 1, zip_d_desc.max_code + 1, max_blindex + 1);
+ zip_compress_block(zip_dyn_ltree, zip_dyn_dtree);
+ }
+
+ zip_init_block();
+ if (eof != 0) zip_bi_windup();
+ }
+ /* ==========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+
+
+ function zip_ct_tally(dist, // distance of matched string
+ lc) {
+ // match length-MIN_MATCH or unmatched char (if dist==0)
+ zip_l_buf[zip_last_lit++] = lc;
+
+ if (dist == 0) {
+ // lc is the unmatched char
+ zip_dyn_ltree[lc].fc++;
+ } else {
+ // Here, lc is the match length - MIN_MATCH
+ dist--; // dist = match distance - 1
+ // Assert((ush)dist < (ush)MAX_DIST &&
+ // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ // (ush)D_CODE(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ zip_dyn_ltree[zip_length_code[lc] + zip_LITERALS + 1].fc++;
+ zip_dyn_dtree[zip_D_CODE(dist)].fc++;
+ zip_d_buf[zip_last_dist++] = dist;
+ zip_flags |= zip_flag_bit;
+ }
+
+ zip_flag_bit <<= 1; // Output the flags if they fill a byte
+
+ if ((zip_last_lit & 7) == 0) {
+ zip_flag_buf[zip_last_flags++] = zip_flags;
+ zip_flags = 0;
+ zip_flag_bit = 1;
+ } // Try to guess if it is profitable to stop the current block here
+
+
+ if (zip_compr_level > 2 && (zip_last_lit & 0xfff) == 0) {
+ // Compute an upper bound for the compressed length
+ var out_length = zip_last_lit * 8;
+ var in_length = zip_strstart - zip_block_start;
+ var dcode;
+
+ for (dcode = 0; dcode < zip_D_CODES; dcode++) {
+ out_length += zip_dyn_dtree[dcode].fc * (5 + zip_extra_dbits[dcode]);
+ }
+
+ out_length >>= 3; // Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ // encoder->last_lit, encoder->last_dist, in_length, out_length,
+ // 100L - out_length*100L/in_length));
+
+ if (zip_last_dist < _parseInt$2(zip_last_lit / 2) && out_length < _parseInt$2(in_length / 2)) return true;
+ }
+
+ return zip_last_lit == zip_LIT_BUFSIZE - 1 || zip_last_dist == zip_DIST_BUFSIZE;
+ /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+ }
+ /* ==========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+
+
+ function zip_compress_block(ltree, // literal tree
+ dtree) {
+ // distance tree
+ var dist; // distance of matched string
+
+ var lc; // match length or unmatched char (if dist == 0)
+
+ var lx = 0; // running index in l_buf
+
+ var dx = 0; // running index in d_buf
+
+ var fx = 0; // running index in flag_buf
+
+ var flag = 0; // current flags
+
+ var code; // the code to send
+
+ var extra; // number of extra bits to send
+
+ if (zip_last_lit != 0) do {
+ if ((lx & 7) == 0) flag = zip_flag_buf[fx++];
+ lc = zip_l_buf[lx++] & 0xff;
+
+ if ((flag & 1) == 0) {
+ zip_SEND_CODE(lc, ltree);
+ /* send a literal byte */
+ // Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ // Here, lc is the match length - MIN_MATCH
+ code = zip_length_code[lc];
+ zip_SEND_CODE(code + zip_LITERALS + 1, ltree); // send the length code
+
+ extra = zip_extra_lbits[code];
+
+ if (extra != 0) {
+ lc -= zip_base_length[code];
+ zip_send_bits(lc, extra); // send the extra length bits
+ }
+
+ dist = zip_d_buf[dx++]; // Here, dist is the match distance - 1
+
+ code = zip_D_CODE(dist); // Assert (code < D_CODES, "bad d_code");
+
+ zip_SEND_CODE(code, dtree); // send the distance code
+
+ extra = zip_extra_dbits[code];
+
+ if (extra != 0) {
+ dist -= zip_base_dist[code];
+ zip_send_bits(dist, extra); // send the extra distance bits
+ }
+ } // literal or match pair ?
+
+
+ flag >>= 1;
+ } while (lx < zip_last_lit);
+ zip_SEND_CODE(zip_END_BLOCK, ltree);
+ }
+ /* ==========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+
+
+ var zip_Buf_size = 16; // bit size of bi_buf
+
+ function zip_send_bits(value, // value to send
+ length) {
+ // number of bits
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (zip_bi_valid > zip_Buf_size - length) {
+ zip_bi_buf |= value << zip_bi_valid;
+ zip_put_short(zip_bi_buf);
+ zip_bi_buf = value >> zip_Buf_size - zip_bi_valid;
+ zip_bi_valid += length - zip_Buf_size;
+ } else {
+ zip_bi_buf |= value << zip_bi_valid;
+ zip_bi_valid += length;
+ }
+ }
+ /* ==========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+
+
+ function zip_bi_reverse(code, // the value to invert
+ len) {
+ // its bit length
+ var res = 0;
+
+ do {
+ res |= code & 1;
+ code >>= 1;
+ res <<= 1;
+ } while (--len > 0);
+
+ return res >> 1;
+ }
+ /* ==========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+
+
+ function zip_bi_windup() {
+ if (zip_bi_valid > 8) {
+ zip_put_short(zip_bi_buf);
+ } else if (zip_bi_valid > 0) {
+ zip_put_byte(zip_bi_buf);
+ }
+
+ zip_bi_buf = 0;
+ zip_bi_valid = 0;
+ }
+
+ function zip_qoutbuf() {
+ if (zip_outcnt != 0) {
+ var q;
+ var i;
+ q = zip_new_queue();
+ if (zip_qhead == null) zip_qhead = zip_qtail = q;else zip_qtail = zip_qtail.next = q;
+ q.len = zip_outcnt - zip_outoff; // System.arraycopy(zip_outbuf, zip_outoff, q.ptr, 0, q.len);
+
+ for (i = 0; i < q.len; i++) {
+ q.ptr[i] = zip_outbuf[zip_outoff + i];
+ }
+
+ zip_outcnt = zip_outoff = 0;
+ }
+ }
+
+ return function deflate(str, level) {
+ var i;
+ var j;
+ zip_deflate_data = str;
+ zip_deflate_pos = 0;
+ if (typeof level === 'undefined') level = zip_DEFAULT_LEVEL;
+ zip_deflate_start(level);
+ var buff = new Array(1024);
+ var aout = [];
+
+ while ((i = zip_deflate_internal(buff, 0, buff.length)) > 0) {
+ var cbuf = new Array(i);
+
+ for (j = 0; j < i; j++) {
+ cbuf[j] = String.fromCharCode(buff[j]);
+ }
+
+ aout[aout.length] = cbuf.join('');
+ }
+
+ zip_deflate_data = null; // G.C.
+
+ return aout.join('');
+ };
+ }();
+
+ function ownKeys$b(object, enumerableOnly) { var keys = keys$3(object); if (getOwnPropertySymbols$2) { var symbols = getOwnPropertySymbols$2(object); enumerableOnly && (symbols = filter$3(symbols).call(symbols, function (sym) { return getOwnPropertyDescriptor$3(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+ function _objectSpread$a(target) { for (var i = 1; i < arguments.length; i++) { var _context4, _context5; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? forEach$3(_context4 = ownKeys$b(Object(source), !0)).call(_context4, function (key) { _defineProperty(target, key, source[key]); }) : getOwnPropertyDescriptors$2 ? defineProperties$2(target, getOwnPropertyDescriptors$2(source)) : forEach$3(_context5 = ownKeys$b(Object(source))).call(_context5, function (key) { defineProperty$5(target, key, getOwnPropertyDescriptor$3(source, key)); }); } return target; }
+
+ function encode64(data) {
+ var r = '';
+
+ for (var i = 0; i < data.length; i += 3) {
+ if (i + 2 === data.length) {
+ r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0);
+ } else if (i + 1 === data.length) {
+ r += append3bytes(data.charCodeAt(i), 0, 0);
+ } else {
+ r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), data.charCodeAt(i + 2));
+ }
+ }
+
+ return r;
+ }
+
+ function append3bytes(b1, b2, b3) {
+ var c1 = b1 >> 2;
+ var c2 = (b1 & 0x3) << 4 | b2 >> 4;
+ var c3 = (b2 & 0xf) << 2 | b3 >> 6;
+ var c4 = b3 & 0x3f;
+ var r = '';
+ r += encode6bit(c1 & 0x3f);
+ r += encode6bit(c2 & 0x3f);
+ r += encode6bit(c3 & 0x3f);
+ r += encode6bit(c4 & 0x3f);
+ return r;
+ }
+
+ function encode6bit(b1) {
+ var b = b1;
+
+ if (b < 10) {
+ return String.fromCharCode(48 + b);
+ }
+
+ b -= 10;
+
+ if (b < 26) {
+ return String.fromCharCode(65 + b);
+ }
+
+ b -= 26;
+
+ if (b < 26) {
+ return String.fromCharCode(97 + b);
+ }
+
+ b -= 26;
+
+ if (b === 0) {
+ return '-';
+ }
+
+ if (b === 1) {
+ return '_';
+ }
+
+ return '?';
+ }
+
+ function compress(s1, url) {
+ var _context;
+
+ var s = unescape(encodeURIComponent(s1));
+ return concat$5(_context = "".concat(url, "/svg/")).call(_context, encode64(deflate(s, 9)));
+ }
+
+ var PlantUMLCodeEngine = /*#__PURE__*/function () {
+ function PlantUMLCodeEngine() {
+ var _plantUMLOptions$base;
+
+ var plantUMLOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ _classCallCheck(this, PlantUMLCodeEngine);
+
+ var defaultUrl = 'http://www.plantuml.com/plantuml';
+ this.baseUrl = (_plantUMLOptions$base = plantUMLOptions.baseUrl) !== null && _plantUMLOptions$base !== void 0 ? _plantUMLOptions$base : defaultUrl;
+ }
+
+ _createClass(PlantUMLCodeEngine, [{
+ key: "render",
+ value: function render(src, sign) {
+ var _context2, _context3;
+
+ var $sign = sign;
+
+ if (!$sign) {
+ $sign = Math.round(Math.random() * 100000000);
+ }
+
+ var graphId = concat$5(_context2 = "plantuml-".concat($sign, "-")).call(_context2, new Date().getTime());
+
+ return concat$5(_context3 = "
");
+ }
+ }], [{
+ key: "install",
+ value: function install(cherryOptions, args) {
+ var _cherryOptions$engine;
+
+ mergeWith_1(cherryOptions, {
+ engine: {
+ syntax: {
+ codeBlock: {
+ customRenderer: {
+ plantuml: new PlantUMLCodeEngine(_objectSpread$a(_objectSpread$a({}, args), (_cherryOptions$engine = cherryOptions.engine.syntax.plantuml) !== null && _cherryOptions$engine !== void 0 ? _cherryOptions$engine : {}))
+ }
+ }
+ }
+ }
+ });
+ }
+ }]);
+
+ return PlantUMLCodeEngine;
+ }();
+
+ /*! For license information please see mermaid.esm.min.mjs.LICENSE.txt */
+ var t={2536:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,6],n=[1,7],r=[1,8],i=[1,9],a=[1,16],o=[1,11],s=[1,12],l=[1,13],u=[1,14],h=[1,15],f=[1,27],d=[1,33],p=[1,34],g=[1,35],y=[1,36],m=[1,37],b=[1,72],v=[1,73],_=[1,74],x=[1,75],k=[1,76],w=[1,77],T=[1,78],E=[1,38],C=[1,39],S=[1,40],A=[1,41],M=[1,42],N=[1,43],O=[1,44],D=[1,45],B=[1,46],L=[1,47],I=[1,48],F=[1,49],R=[1,50],P=[1,51],j=[1,52],z=[1,53],Y=[1,54],U=[1,55],$=[1,56],W=[1,57],q=[1,59],H=[1,60],V=[1,61],G=[1,62],X=[1,63],Z=[1,64],Q=[1,65],K=[1,66],J=[1,67],tt=[1,68],et=[1,69],nt=[24,52],rt=[24,44,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84],it=[15,24,44,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84],at=[1,94],ot=[1,95],st=[1,96],ct=[1,97],lt=[15,24,52],ut=[7,8,9,10,18,22,25,26,27,28],ht=[15,24,43,52],ft=[15,24,43,52,86,87,89,90],dt=[15,43],pt=[44,46,47,48,49,50,51,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84],gt={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,directive:6,direction_tb:7,direction_bt:8,direction_rl:9,direction_lr:10,graphConfig:11,openDirective:12,typeDirective:13,closeDirective:14,NEWLINE:15,":":16,argDirective:17,open_directive:18,type_directive:19,arg_directive:20,close_directive:21,C4_CONTEXT:22,statements:23,EOF:24,C4_CONTAINER:25,C4_COMPONENT:26,C4_DYNAMIC:27,C4_DEPLOYMENT:28,otherStatements:29,diagramStatements:30,otherStatement:31,title:32,accDescription:33,acc_title:34,acc_title_value:35,acc_descr:36,acc_descr_value:37,acc_descr_multiline_value:38,boundaryStatement:39,boundaryStartStatement:40,boundaryStopStatement:41,boundaryStart:42,LBRACE:43,ENTERPRISE_BOUNDARY:44,attributes:45,SYSTEM_BOUNDARY:46,BOUNDARY:47,CONTAINER_BOUNDARY:48,NODE:49,NODE_L:50,NODE_R:51,RBRACE:52,diagramStatement:53,PERSON:54,PERSON_EXT:55,SYSTEM:56,SYSTEM_DB:57,SYSTEM_QUEUE:58,SYSTEM_EXT:59,SYSTEM_EXT_DB:60,SYSTEM_EXT_QUEUE:61,CONTAINER:62,CONTAINER_DB:63,CONTAINER_QUEUE:64,CONTAINER_EXT:65,CONTAINER_EXT_DB:66,CONTAINER_EXT_QUEUE:67,COMPONENT:68,COMPONENT_DB:69,COMPONENT_QUEUE:70,COMPONENT_EXT:71,COMPONENT_EXT_DB:72,COMPONENT_EXT_QUEUE:73,REL:74,BIREL:75,REL_U:76,REL_D:77,REL_L:78,REL_R:79,REL_B:80,REL_INDEX:81,UPDATE_EL_STYLE:82,UPDATE_REL_STYLE:83,UPDATE_LAYOUT_CONFIG:84,attribute:85,STR:86,STR_KEY:87,STR_VALUE:88,ATTRIBUTE:89,ATTRIBUTE_EMPTY:90,$accept:0,$end:1},terminals_:{2:"error",7:"direction_tb",8:"direction_bt",9:"direction_rl",10:"direction_lr",15:"NEWLINE",16:":",18:"open_directive",19:"type_directive",20:"arg_directive",21:"close_directive",22:"C4_CONTEXT",24:"EOF",25:"C4_CONTAINER",26:"C4_COMPONENT",27:"C4_DYNAMIC",28:"C4_DEPLOYMENT",32:"title",33:"accDescription",34:"acc_title",35:"acc_title_value",36:"acc_descr",37:"acc_descr_value",38:"acc_descr_multiline_value",43:"LBRACE",44:"ENTERPRISE_BOUNDARY",46:"SYSTEM_BOUNDARY",47:"BOUNDARY",48:"CONTAINER_BOUNDARY",49:"NODE",50:"NODE_L",51:"NODE_R",52:"RBRACE",54:"PERSON",55:"PERSON_EXT",56:"SYSTEM",57:"SYSTEM_DB",58:"SYSTEM_QUEUE",59:"SYSTEM_EXT",60:"SYSTEM_EXT_DB",61:"SYSTEM_EXT_QUEUE",62:"CONTAINER",63:"CONTAINER_DB",64:"CONTAINER_QUEUE",65:"CONTAINER_EXT",66:"CONTAINER_EXT_DB",67:"CONTAINER_EXT_QUEUE",68:"COMPONENT",69:"COMPONENT_DB",70:"COMPONENT_QUEUE",71:"COMPONENT_EXT",72:"COMPONENT_EXT_DB",73:"COMPONENT_EXT_QUEUE",74:"REL",75:"BIREL",76:"REL_U",77:"REL_D",78:"REL_L",79:"REL_R",80:"REL_B",81:"REL_INDEX",82:"UPDATE_EL_STYLE",83:"UPDATE_REL_STYLE",84:"UPDATE_LAYOUT_CONFIG",86:"STR",87:"STR_KEY",88:"STR_VALUE",89:"ATTRIBUTE",90:"ATTRIBUTE_EMPTY"},productions_:[0,[3,1],[3,1],[3,2],[5,1],[5,1],[5,1],[5,1],[4,1],[6,4],[6,6],[12,1],[13,1],[17,1],[14,1],[11,4],[11,4],[11,4],[11,4],[11,4],[23,1],[23,1],[23,2],[29,1],[29,2],[29,3],[31,1],[31,1],[31,2],[31,2],[31,1],[39,3],[40,3],[40,3],[40,4],[42,2],[42,2],[42,2],[42,2],[42,2],[42,2],[42,2],[41,1],[30,1],[30,2],[30,3],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,1],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[53,2],[45,1],[45,2],[85,1],[85,2],[85,1],[85,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:r.setDirection("TB");break;case 5:r.setDirection("BT");break;case 6:r.setDirection("RL");break;case 7:r.setDirection("LR");break;case 11:console.log("open_directive: ",a[s]),r.parseDirective("%%{","open_directive");break;case 12:break;case 13:a[s]=a[s].trim().replace(/'/g,'"'),console.log("arg_directive: ",a[s]),r.parseDirective(a[s],"arg_directive");break;case 14:console.log("close_directive: ",a[s]),r.parseDirective("}%%","close_directive","c4Context");break;case 15:case 16:case 17:case 18:case 19:r.setC4Type(a[s-3]);break;case 26:r.setTitle(a[s].substring(6)),this.$=a[s].substring(6);break;case 27:r.setAccDescription(a[s].substring(15)),this.$=a[s].substring(15);break;case 28:this.$=a[s].trim(),r.setTitle(this.$);break;case 29:case 30:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 35:case 36:console.log(a[s-1],JSON.stringify(a[s])),a[s].splice(2,0,"ENTERPRISE"),r.addPersonOrSystemBoundary(...a[s]),this.$=a[s];break;case 37:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystemBoundary(...a[s]),this.$=a[s];break;case 38:console.log(a[s-1],JSON.stringify(a[s])),a[s].splice(2,0,"CONTAINER"),r.addContainerBoundary(...a[s]),this.$=a[s];break;case 39:console.log(a[s-1],JSON.stringify(a[s])),r.addDeploymentNode("node",...a[s]),this.$=a[s];break;case 40:console.log(a[s-1],JSON.stringify(a[s])),r.addDeploymentNode("nodeL",...a[s]),this.$=a[s];break;case 41:console.log(a[s-1],JSON.stringify(a[s])),r.addDeploymentNode("nodeR",...a[s]),this.$=a[s];break;case 42:r.popBoundaryParseStack();break;case 46:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("person",...a[s]),this.$=a[s];break;case 47:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("external_person",...a[s]),this.$=a[s];break;case 48:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("system",...a[s]),this.$=a[s];break;case 49:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("system_db",...a[s]),this.$=a[s];break;case 50:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("system_queue",...a[s]),this.$=a[s];break;case 51:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("external_system",...a[s]),this.$=a[s];break;case 52:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("external_system_db",...a[s]),this.$=a[s];break;case 53:console.log(a[s-1],JSON.stringify(a[s])),r.addPersonOrSystem("external_system_queue",...a[s]),this.$=a[s];break;case 54:console.log(a[s-1],JSON.stringify(a[s])),r.addContainer("container",...a[s]),this.$=a[s];break;case 55:console.log(a[s-1],JSON.stringify(a[s])),r.addContainer("container_db",...a[s]),this.$=a[s];break;case 56:console.log(a[s-1],JSON.stringify(a[s])),r.addContainer("container_queue",...a[s]),this.$=a[s];break;case 57:console.log(a[s-1],JSON.stringify(a[s])),r.addContainer("external_container",...a[s]),this.$=a[s];break;case 58:console.log(a[s-1],JSON.stringify(a[s])),r.addContainer("external_container_db",...a[s]),this.$=a[s];break;case 59:console.log(a[s-1],JSON.stringify(a[s])),r.addContainer("external_container_queue",...a[s]),this.$=a[s];break;case 60:console.log(a[s-1],JSON.stringify(a[s])),r.addComponent("component",...a[s]),this.$=a[s];break;case 61:console.log(a[s-1],JSON.stringify(a[s])),r.addComponent("component_db",...a[s]),this.$=a[s];break;case 62:console.log(a[s-1],JSON.stringify(a[s])),r.addComponent("component_queue",...a[s]),this.$=a[s];break;case 63:console.log(a[s-1],JSON.stringify(a[s])),r.addComponent("external_component",...a[s]),this.$=a[s];break;case 64:console.log(a[s-1],JSON.stringify(a[s])),r.addComponent("external_component_db",...a[s]),this.$=a[s];break;case 65:console.log(a[s-1],JSON.stringify(a[s])),r.addComponent("external_component_queue",...a[s]),this.$=a[s];break;case 67:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("rel",...a[s]),this.$=a[s];break;case 68:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("birel",...a[s]),this.$=a[s];break;case 69:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("rel_u",...a[s]),this.$=a[s];break;case 70:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("rel_d",...a[s]),this.$=a[s];break;case 71:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("rel_l",...a[s]),this.$=a[s];break;case 72:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("rel_r",...a[s]),this.$=a[s];break;case 73:console.log(a[s-1],JSON.stringify(a[s])),r.addRel("rel_b",...a[s]),this.$=a[s];break;case 74:console.log(a[s-1],JSON.stringify(a[s])),a[s].splice(0,1),r.addRel("rel",...a[s]),this.$=a[s];break;case 75:console.log(a[s-1],JSON.stringify(a[s])),r.updateElStyle("update_el_style",...a[s]),this.$=a[s];break;case 76:console.log(a[s-1],JSON.stringify(a[s])),r.updateRelStyle("update_rel_style",...a[s]),this.$=a[s];break;case 77:console.log(a[s-1],JSON.stringify(a[s])),r.updateLayoutConfig("update_layout_config",...a[s]),this.$=a[s];break;case 78:console.log("PUSH ATTRIBUTE: ",a[s]),this.$=[a[s]];break;case 79:console.log("PUSH ATTRIBUTE: ",a[s-1]),a[s].unshift(a[s-1]),this.$=a[s];break;case 80:case 82:this.$=a[s].trim();break;case 81:console.log("kv: ",a[s-1],a[s]);let t={};t[a[s-1].trim()]=a[s].trim(),this.$=t;break;case 83:this.$="";}},table:[{3:1,4:2,5:3,6:4,7:e,8:n,9:r,10:i,11:5,12:10,18:a,22:o,25:s,26:l,27:u,28:h},{1:[3]},{1:[2,1]},{1:[2,2]},{3:17,4:2,5:3,6:4,7:e,8:n,9:r,10:i,11:5,12:10,18:a,22:o,25:s,26:l,27:u,28:h},{1:[2,8]},{1:[2,4]},{1:[2,5]},{1:[2,6]},{1:[2,7]},{13:18,19:[1,19]},{15:[1,20]},{15:[1,21]},{15:[1,22]},{15:[1,23]},{15:[1,24]},{19:[2,11]},{1:[2,3]},{14:25,16:[1,26],21:f},t([16,21],[2,12]),{23:28,29:29,30:30,31:31,32:d,33:p,34:g,36:y,38:m,39:58,40:70,42:71,44:b,46:v,47:_,48:x,49:k,50:w,51:T,53:32,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et},{23:79,29:29,30:30,31:31,32:d,33:p,34:g,36:y,38:m,39:58,40:70,42:71,44:b,46:v,47:_,48:x,49:k,50:w,51:T,53:32,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et},{23:80,29:29,30:30,31:31,32:d,33:p,34:g,36:y,38:m,39:58,40:70,42:71,44:b,46:v,47:_,48:x,49:k,50:w,51:T,53:32,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et},{23:81,29:29,30:30,31:31,32:d,33:p,34:g,36:y,38:m,39:58,40:70,42:71,44:b,46:v,47:_,48:x,49:k,50:w,51:T,53:32,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et},{23:82,29:29,30:30,31:31,32:d,33:p,34:g,36:y,38:m,39:58,40:70,42:71,44:b,46:v,47:_,48:x,49:k,50:w,51:T,53:32,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et},{15:[1,83]},{17:84,20:[1,85]},{15:[2,14]},{24:[1,86]},t(nt,[2,20],{53:32,39:58,40:70,42:71,30:87,44:b,46:v,47:_,48:x,49:k,50:w,51:T,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et}),t(nt,[2,21]),t(rt,[2,23],{15:[1,88]}),t(nt,[2,43],{15:[1,89]}),t(it,[2,26]),t(it,[2,27]),{35:[1,90]},{37:[1,91]},t(it,[2,30]),{45:92,85:93,86:at,87:ot,89:st,90:ct},{45:98,85:93,86:at,87:ot,89:st,90:ct},{45:99,85:93,86:at,87:ot,89:st,90:ct},{45:100,85:93,86:at,87:ot,89:st,90:ct},{45:101,85:93,86:at,87:ot,89:st,90:ct},{45:102,85:93,86:at,87:ot,89:st,90:ct},{45:103,85:93,86:at,87:ot,89:st,90:ct},{45:104,85:93,86:at,87:ot,89:st,90:ct},{45:105,85:93,86:at,87:ot,89:st,90:ct},{45:106,85:93,86:at,87:ot,89:st,90:ct},{45:107,85:93,86:at,87:ot,89:st,90:ct},{45:108,85:93,86:at,87:ot,89:st,90:ct},{45:109,85:93,86:at,87:ot,89:st,90:ct},{45:110,85:93,86:at,87:ot,89:st,90:ct},{45:111,85:93,86:at,87:ot,89:st,90:ct},{45:112,85:93,86:at,87:ot,89:st,90:ct},{45:113,85:93,86:at,87:ot,89:st,90:ct},{45:114,85:93,86:at,87:ot,89:st,90:ct},{45:115,85:93,86:at,87:ot,89:st,90:ct},{45:116,85:93,86:at,87:ot,89:st,90:ct},t(lt,[2,66]),{45:117,85:93,86:at,87:ot,89:st,90:ct},{45:118,85:93,86:at,87:ot,89:st,90:ct},{45:119,85:93,86:at,87:ot,89:st,90:ct},{45:120,85:93,86:at,87:ot,89:st,90:ct},{45:121,85:93,86:at,87:ot,89:st,90:ct},{45:122,85:93,86:at,87:ot,89:st,90:ct},{45:123,85:93,86:at,87:ot,89:st,90:ct},{45:124,85:93,86:at,87:ot,89:st,90:ct},{45:125,85:93,86:at,87:ot,89:st,90:ct},{45:126,85:93,86:at,87:ot,89:st,90:ct},{45:127,85:93,86:at,87:ot,89:st,90:ct},{30:128,39:58,40:70,42:71,44:b,46:v,47:_,48:x,49:k,50:w,51:T,53:32,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et},{15:[1,130],43:[1,129]},{45:131,85:93,86:at,87:ot,89:st,90:ct},{45:132,85:93,86:at,87:ot,89:st,90:ct},{45:133,85:93,86:at,87:ot,89:st,90:ct},{45:134,85:93,86:at,87:ot,89:st,90:ct},{45:135,85:93,86:at,87:ot,89:st,90:ct},{45:136,85:93,86:at,87:ot,89:st,90:ct},{45:137,85:93,86:at,87:ot,89:st,90:ct},{24:[1,138]},{24:[1,139]},{24:[1,140]},{24:[1,141]},t(ut,[2,9]),{14:142,21:f},{21:[2,13]},{1:[2,15]},t(nt,[2,22]),t(rt,[2,24],{31:31,29:143,32:d,33:p,34:g,36:y,38:m}),t(nt,[2,44],{29:29,30:30,31:31,53:32,39:58,40:70,42:71,23:144,32:d,33:p,34:g,36:y,38:m,44:b,46:v,47:_,48:x,49:k,50:w,51:T,54:E,55:C,56:S,57:A,58:M,59:N,60:O,61:D,62:B,63:L,64:I,65:F,66:R,67:P,68:j,69:z,70:Y,71:U,72:$,73:W,74:q,75:H,76:V,77:G,78:X,79:Z,80:Q,81:K,82:J,83:tt,84:et}),t(it,[2,28]),t(it,[2,29]),t(lt,[2,46]),t(ht,[2,78],{85:93,45:145,86:at,87:ot,89:st,90:ct}),t(ft,[2,80]),{88:[1,146]},t(ft,[2,82]),t(ft,[2,83]),t(lt,[2,47]),t(lt,[2,48]),t(lt,[2,49]),t(lt,[2,50]),t(lt,[2,51]),t(lt,[2,52]),t(lt,[2,53]),t(lt,[2,54]),t(lt,[2,55]),t(lt,[2,56]),t(lt,[2,57]),t(lt,[2,58]),t(lt,[2,59]),t(lt,[2,60]),t(lt,[2,61]),t(lt,[2,62]),t(lt,[2,63]),t(lt,[2,64]),t(lt,[2,65]),t(lt,[2,67]),t(lt,[2,68]),t(lt,[2,69]),t(lt,[2,70]),t(lt,[2,71]),t(lt,[2,72]),t(lt,[2,73]),t(lt,[2,74]),t(lt,[2,75]),t(lt,[2,76]),t(lt,[2,77]),{41:147,52:[1,148]},{15:[1,149]},{43:[1,150]},t(dt,[2,35]),t(dt,[2,36]),t(dt,[2,37]),t(dt,[2,38]),t(dt,[2,39]),t(dt,[2,40]),t(dt,[2,41]),{1:[2,16]},{1:[2,17]},{1:[2,18]},{1:[2,19]},{15:[1,151]},t(rt,[2,25]),t(nt,[2,45]),t(ht,[2,79]),t(ft,[2,81]),t(lt,[2,31]),t(lt,[2,42]),t(pt,[2,32]),t(pt,[2,33],{15:[1,152]}),t(ut,[2,10]),t(pt,[2,34])],defaultActions:{2:[2,1],3:[2,2],5:[2,8],6:[2,4],7:[2,5],8:[2,6],9:[2,7],16:[2,11],17:[2,3],27:[2,14],85:[2,13],86:[2,15],138:[2,16],139:[2,17],140:[2,18],141:[2,19]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},yt={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),18;case 1:return 7;case 2:return 8;case 3:return 9;case 4:return 10;case 5:return this.begin("type_directive"),19;case 6:return this.popState(),this.begin("arg_directive"),16;case 7:return this.popState(),this.popState(),21;case 8:return 20;case 9:return 32;case 10:return 33;case 11:return this.begin("acc_title"),34;case 12:return this.popState(),"acc_title_value";case 13:return this.begin("acc_descr"),36;case 14:return this.popState(),"acc_descr_value";case 15:this.begin("acc_descr_multiline");break;case 16:this.popState();break;case 17:return "acc_descr_multiline_value";case 18:case 21:break;case 19:c;break;case 20:return 15;case 22:return 22;case 23:return 25;case 24:return 26;case 25:return 27;case 26:return 28;case 27:return this.begin("person_ext"),console.log("begin person_ext"),55;case 28:return this.begin("person"),console.log("begin person"),54;case 29:return this.begin("system_ext_queue"),console.log("begin system_ext_queue"),61;case 30:return this.begin("system_ext_db"),console.log("begin system_ext_db"),60;case 31:return this.begin("system_ext"),console.log("begin system_ext"),59;case 32:return this.begin("system_queue"),console.log("begin system_queue"),58;case 33:return this.begin("system_db"),console.log("begin system_db"),57;case 34:return this.begin("system"),console.log("begin system"),56;case 35:return this.begin("boundary"),console.log("begin boundary"),47;case 36:return this.begin("enterprise_boundary"),console.log("begin enterprise_boundary"),44;case 37:return this.begin("system_boundary"),console.log("begin system_boundary"),46;case 38:return this.begin("container_ext_queue"),console.log("begin container_ext_queue"),67;case 39:return this.begin("container_ext_db"),console.log("begin container_ext_db"),66;case 40:return this.begin("container_ext"),console.log("begin container_ext"),65;case 41:return this.begin("container_queue"),console.log("begin container_queue"),64;case 42:return this.begin("container_db"),console.log("begin container_db"),63;case 43:return this.begin("container"),console.log("begin container"),62;case 44:return this.begin("container_boundary"),console.log("begin container_boundary"),48;case 45:return this.begin("component_ext_queue"),console.log("begin component_ext_queue"),73;case 46:return this.begin("component_ext_db"),console.log("begin component_ext_db"),72;case 47:return this.begin("component_ext"),console.log("begin component_ext"),71;case 48:return this.begin("component_queue"),console.log("begin component_queue"),70;case 49:return this.begin("component_db"),console.log("begin component_db"),69;case 50:return this.begin("component"),console.log("begin component"),68;case 51:case 52:return this.begin("node"),console.log("begin node"),49;case 53:return this.begin("node_l"),console.log("begin node_l"),50;case 54:return this.begin("node_r"),console.log("begin node_r"),51;case 55:return this.begin("rel"),console.log("begin rel"),74;case 56:return this.begin("birel"),console.log("begin birel"),75;case 57:case 58:return this.begin("rel_u"),console.log("begin rel_u"),76;case 59:case 60:return this.begin("rel_d"),console.log("begin rel_d"),77;case 61:case 62:return this.begin("rel_l"),console.log("begin rel_l"),78;case 63:case 64:return this.begin("rel_r"),console.log("begin rel_r"),79;case 65:return this.begin("rel_b"),console.log("begin rel_b"),80;case 66:return this.begin("rel_index"),console.log("begin rel_index"),81;case 67:return this.begin("update_el_style"),console.log("begin update_el_style"),82;case 68:return this.begin("update_rel_style"),console.log("begin update_rel_style"),83;case 69:return this.begin("update_layout_config"),console.log("begin update_layout_config"),84;case 70:return "EOF_IN_STRUCT";case 71:return console.log("begin attribute with ATTRIBUTE_EMPTY"),this.begin("attribute"),"ATTRIBUTE_EMPTY";case 72:console.log("begin attribute"),this.begin("attribute");break;case 73:console.log("STOP attribute"),this.popState(),console.log("STOP diagram"),this.popState();break;case 74:return console.log(",,"),90;case 75:console.log(",");break;case 76:return console.log("ATTRIBUTE_EMPTY"),90;case 77:console.log("begin string"),this.begin("string");break;case 78:console.log("STOP string"),this.popState();break;case 79:return console.log("STR"),"STR";case 80:console.log("begin string_kv"),this.begin("string_kv");break;case 81:return console.log("STR_KEY"),this.begin("string_kv_key"),"STR_KEY";case 82:console.log("begin string_kv_value"),this.popState(),this.begin("string_kv_value");break;case 83:return console.log("STR_VALUE"),"STR_VALUE";case 84:console.log("STOP string_kv_value"),this.popState(),this.popState();break;case 85:return console.log("not STR"),"STR";case 86:return console.log("begin boundary block"),"LBRACE";case 87:return console.log("STOP boundary block"),"RBRACE";case 88:return "SPACE";case 89:return "EOL";case 90:return 24}},rules:[/^(?:%%\{)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:title\s[^#\n;]+)/,/^(?:accDescription\s[^#\n;]+)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:C4Context\b)/,/^(?:C4Container\b)/,/^(?:C4Component\b)/,/^(?:C4Dynamic\b)/,/^(?:C4Deployment\b)/,/^(?:Person_Ext\b)/,/^(?:Person\b)/,/^(?:SystemQueue_Ext\b)/,/^(?:SystemDb_Ext\b)/,/^(?:System_Ext\b)/,/^(?:SystemQueue\b)/,/^(?:SystemDb\b)/,/^(?:System\b)/,/^(?:Boundary\b)/,/^(?:Enterprise_Boundary\b)/,/^(?:System_Boundary\b)/,/^(?:ContainerQueue_Ext\b)/,/^(?:ContainerDb_Ext\b)/,/^(?:Container_Ext\b)/,/^(?:ContainerQueue\b)/,/^(?:ContainerDb\b)/,/^(?:Container\b)/,/^(?:Container_Boundary\b)/,/^(?:ComponentQueue_Ext\b)/,/^(?:ComponentDb_Ext\b)/,/^(?:Component_Ext\b)/,/^(?:ComponentQueue\b)/,/^(?:ComponentDb\b)/,/^(?:Component\b)/,/^(?:Deployment_Node\b)/,/^(?:Node\b)/,/^(?:Node_L\b)/,/^(?:Node_R\b)/,/^(?:Rel\b)/,/^(?:BiRel\b)/,/^(?:Rel_Up\b)/,/^(?:Rel_U\b)/,/^(?:Rel_Down\b)/,/^(?:Rel_D\b)/,/^(?:Rel_Left\b)/,/^(?:Rel_L\b)/,/^(?:Rel_Right\b)/,/^(?:Rel_R\b)/,/^(?:Rel_Back\b)/,/^(?:RelIndex\b)/,/^(?:UpdateElementStyle\b)/,/^(?:UpdateRelStyle\b)/,/^(?:UpdateLayoutConfig\b)/,/^(?:$)/,/^(?:[(][ ]*[,])/,/^(?:[(])/,/^(?:[)])/,/^(?:,,)/,/^(?:,)/,/^(?:[ ]*["]["])/,/^(?:[ ]*["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:[ ]*[\$])/,/^(?:[^=]*)/,/^(?:[=][ ]*["])/,/^(?:[^"]+)/,/^(?:["])/,/^(?:[^,]+)/,/^(?:\{)/,/^(?:\})/,/^(?:[\s]+)/,/^(?:[\n\r]+)/,/^(?:$)/],conditions:{acc_descr_multiline:{rules:[16,17],inclusive:!1},acc_descr:{rules:[14],inclusive:!1},acc_title:{rules:[12],inclusive:!1},close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[7,8],inclusive:!1},type_directive:{rules:[6,7],inclusive:!1},open_directive:{rules:[5],inclusive:!1},string_kv_value:{rules:[83,84],inclusive:!1},string_kv_key:{rules:[82],inclusive:!1},string_kv:{rules:[81],inclusive:!1},string:{rules:[78,79],inclusive:!1},attribute:{rules:[73,74,75,76,77,80,85],inclusive:!1},update_layout_config:{rules:[70,71,72,73],inclusive:!1},update_rel_style:{rules:[70,71,72,73],inclusive:!1},update_el_style:{rules:[70,71,72,73],inclusive:!1},rel_b:{rules:[70,71,72,73],inclusive:!1},rel_r:{rules:[70,71,72,73],inclusive:!1},rel_l:{rules:[70,71,72,73],inclusive:!1},rel_d:{rules:[70,71,72,73],inclusive:!1},rel_u:{rules:[70,71,72,73],inclusive:!1},rel_bi:{rules:[],inclusive:!1},rel:{rules:[70,71,72,73],inclusive:!1},node_r:{rules:[70,71,72,73],inclusive:!1},node_l:{rules:[70,71,72,73],inclusive:!1},node:{rules:[70,71,72,73],inclusive:!1},index:{rules:[],inclusive:!1},rel_index:{rules:[70,71,72,73],inclusive:!1},component_ext_queue:{rules:[],inclusive:!1},component_ext_db:{rules:[70,71,72,73],inclusive:!1},component_ext:{rules:[70,71,72,73],inclusive:!1},component_queue:{rules:[70,71,72,73],inclusive:!1},component_db:{rules:[70,71,72,73],inclusive:!1},component:{rules:[70,71,72,73],inclusive:!1},container_boundary:{rules:[70,71,72,73],inclusive:!1},container_ext_queue:{rules:[],inclusive:!1},container_ext_db:{rules:[70,71,72,73],inclusive:!1},container_ext:{rules:[70,71,72,73],inclusive:!1},container_queue:{rules:[70,71,72,73],inclusive:!1},container_db:{rules:[70,71,72,73],inclusive:!1},container:{rules:[70,71,72,73],inclusive:!1},birel:{rules:[70,71,72,73],inclusive:!1},system_boundary:{rules:[70,71,72,73],inclusive:!1},enterprise_boundary:{rules:[70,71,72,73],inclusive:!1},boundary:{rules:[70,71,72,73],inclusive:!1},system_ext_queue:{rules:[70,71,72,73],inclusive:!1},system_ext_db:{rules:[70,71,72,73],inclusive:!1},system_ext:{rules:[70,71,72,73],inclusive:!1},system_queue:{rules:[70,71,72,73],inclusive:!1},system_db:{rules:[70,71,72,73],inclusive:!1},system:{rules:[70,71,72,73],inclusive:!1},person_ext:{rules:[70,71,72,73],inclusive:!1},person:{rules:[70,71,72,73],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,13,15,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,86,87,88,89,90],inclusive:!0}}};function mt(){this.yy={};}return gt.lexer=yt,mt.prototype=gt,gt.Parser=mt,new mt}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(555).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},1362:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,7],r=[1,8],i=[1,9],a=[1,10],o=[1,13],s=[1,12],c=[1,16,25],l=[1,20],u=[1,31],h=[1,32],f=[1,33],d=[1,35],p=[1,38],g=[1,36],y=[1,37],m=[1,39],b=[1,40],v=[1,41],_=[1,42],x=[1,45],k=[1,46],w=[1,47],T=[1,48],E=[16,25],C=[1,62],S=[1,63],A=[1,64],M=[1,65],N=[1,66],O=[1,67],D=[1,68],B=[16,25,32,44,45,53,56,57,58,59,60,61,62,67,69],L=[16,25,30,32,44,45,49,53,56,57,58,59,60,61,62,67,69,84,85,86,87],I=[5,8,9,10,11,16,19,23,25],F=[53,84,85,86,87],R=[53,61,62,84,85,86,87],P=[53,56,57,58,59,60,84,85,86,87],j=[16,25,32],z=[1,100],Y={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,statments:5,direction:6,directive:7,direction_tb:8,direction_bt:9,direction_rl:10,direction_lr:11,graphConfig:12,openDirective:13,typeDirective:14,closeDirective:15,NEWLINE:16,":":17,argDirective:18,open_directive:19,type_directive:20,arg_directive:21,close_directive:22,CLASS_DIAGRAM:23,statements:24,EOF:25,statement:26,className:27,alphaNumToken:28,classLiteralName:29,GENERICTYPE:30,relationStatement:31,LABEL:32,classStatement:33,methodStatement:34,annotationStatement:35,clickStatement:36,cssClassStatement:37,acc_title:38,acc_title_value:39,acc_descr:40,acc_descr_value:41,acc_descr_multiline_value:42,CLASS:43,STYLE_SEPARATOR:44,STRUCT_START:45,members:46,STRUCT_STOP:47,ANNOTATION_START:48,ANNOTATION_END:49,MEMBER:50,SEPARATOR:51,relation:52,STR:53,relationType:54,lineType:55,AGGREGATION:56,EXTENSION:57,COMPOSITION:58,DEPENDENCY:59,LOLLIPOP:60,LINE:61,DOTTED_LINE:62,CALLBACK:63,LINK:64,LINK_TARGET:65,CLICK:66,CALLBACK_NAME:67,CALLBACK_ARGS:68,HREF:69,CSSCLASS:70,commentToken:71,textToken:72,graphCodeTokens:73,textNoTagsToken:74,TAGSTART:75,TAGEND:76,"==":77,"--":78,PCT:79,DEFAULT:80,SPACE:81,MINUS:82,keywords:83,UNICODE_TEXT:84,NUM:85,ALPHA:86,BQUOTE_STR:87,$accept:0,$end:1},terminals_:{2:"error",5:"statments",8:"direction_tb",9:"direction_bt",10:"direction_rl",11:"direction_lr",16:"NEWLINE",17:":",19:"open_directive",20:"type_directive",21:"arg_directive",22:"close_directive",23:"CLASS_DIAGRAM",25:"EOF",30:"GENERICTYPE",32:"LABEL",38:"acc_title",39:"acc_title_value",40:"acc_descr",41:"acc_descr_value",42:"acc_descr_multiline_value",43:"CLASS",44:"STYLE_SEPARATOR",45:"STRUCT_START",47:"STRUCT_STOP",48:"ANNOTATION_START",49:"ANNOTATION_END",50:"MEMBER",51:"SEPARATOR",53:"STR",56:"AGGREGATION",57:"EXTENSION",58:"COMPOSITION",59:"DEPENDENCY",60:"LOLLIPOP",61:"LINE",62:"DOTTED_LINE",63:"CALLBACK",64:"LINK",65:"LINK_TARGET",66:"CLICK",67:"CALLBACK_NAME",68:"CALLBACK_ARGS",69:"HREF",70:"CSSCLASS",73:"graphCodeTokens",75:"TAGSTART",76:"TAGEND",77:"==",78:"--",79:"PCT",80:"DEFAULT",81:"SPACE",82:"MINUS",83:"keywords",84:"UNICODE_TEXT",85:"NUM",86:"ALPHA",87:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[3,1],[3,2],[6,1],[6,1],[6,1],[6,1],[4,1],[7,4],[7,6],[13,1],[14,1],[18,1],[15,1],[12,4],[24,1],[24,2],[24,3],[27,1],[27,1],[27,2],[27,2],[27,2],[26,1],[26,2],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,2],[26,2],[26,1],[33,2],[33,4],[33,5],[33,7],[35,4],[46,1],[46,2],[34,1],[34,2],[34,1],[34,1],[31,3],[31,4],[31,4],[31,5],[52,3],[52,2],[52,2],[52,1],[54,1],[54,1],[54,1],[54,1],[54,1],[55,1],[55,1],[36,3],[36,4],[36,3],[36,4],[36,4],[36,5],[36,3],[36,4],[36,4],[36,5],[36,3],[36,4],[36,4],[36,5],[37,3],[71,1],[71,1],[72,1],[72,1],[72,1],[72,1],[72,1],[72,1],[72,1],[74,1],[74,1],[74,1],[74,1],[28,1],[28,1],[28,1],[29,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 5:r.setDirection("TB");break;case 6:r.setDirection("BT");break;case 7:r.setDirection("RL");break;case 8:r.setDirection("LR");break;case 12:r.parseDirective("%%{","open_directive");break;case 13:r.parseDirective(a[s],"type_directive");break;case 14:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 15:r.parseDirective("}%%","close_directive","class");break;case 20:case 21:this.$=a[s];break;case 22:this.$=a[s-1]+a[s];break;case 23:case 24:this.$=a[s-1]+"~"+a[s];break;case 25:r.addRelation(a[s]);break;case 26:a[s-1].title=r.cleanupLabel(a[s]),r.addRelation(a[s-1]);break;case 34:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 35:case 36:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 37:r.addClass(a[s]);break;case 38:r.addClass(a[s-2]),r.setCssClass(a[s-2],a[s]);break;case 39:r.addClass(a[s-3]),r.addMembers(a[s-3],a[s-1]);break;case 40:r.addClass(a[s-5]),r.setCssClass(a[s-5],a[s-3]),r.addMembers(a[s-5],a[s-1]);break;case 41:r.addAnnotation(a[s],a[s-2]);break;case 42:this.$=[a[s]];break;case 43:a[s].push(a[s-1]),this.$=a[s];break;case 44:case 46:case 47:break;case 45:r.addMember(a[s-1],r.cleanupLabel(a[s]));break;case 48:this.$={id1:a[s-2],id2:a[s],relation:a[s-1],relationTitle1:"none",relationTitle2:"none"};break;case 49:this.$={id1:a[s-3],id2:a[s],relation:a[s-1],relationTitle1:a[s-2],relationTitle2:"none"};break;case 50:this.$={id1:a[s-3],id2:a[s],relation:a[s-2],relationTitle1:"none",relationTitle2:a[s-1]};break;case 51:this.$={id1:a[s-4],id2:a[s],relation:a[s-2],relationTitle1:a[s-3],relationTitle2:a[s-1]};break;case 52:this.$={type1:a[s-2],type2:a[s],lineType:a[s-1]};break;case 53:this.$={type1:"none",type2:a[s],lineType:a[s-1]};break;case 54:this.$={type1:a[s-1],type2:"none",lineType:a[s]};break;case 55:this.$={type1:"none",type2:"none",lineType:a[s]};break;case 56:this.$=r.relationType.AGGREGATION;break;case 57:this.$=r.relationType.EXTENSION;break;case 58:this.$=r.relationType.COMPOSITION;break;case 59:this.$=r.relationType.DEPENDENCY;break;case 60:this.$=r.relationType.LOLLIPOP;break;case 61:this.$=r.lineType.LINE;break;case 62:this.$=r.lineType.DOTTED_LINE;break;case 63:case 69:this.$=a[s-2],r.setClickEvent(a[s-1],a[s]);break;case 64:case 70:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 65:case 73:this.$=a[s-2],r.setLink(a[s-1],a[s]);break;case 66:case 74:this.$=a[s-3],r.setLink(a[s-2],a[s-1],a[s]);break;case 67:case 75:this.$=a[s-3],r.setLink(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 68:case 76:this.$=a[s-4],r.setLink(a[s-3],a[s-2],a[s]),r.setTooltip(a[s-3],a[s-1]);break;case 71:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 72:this.$=a[s-4],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setTooltip(a[s-3],a[s]);break;case 77:r.setCssClass(a[s-1],a[s]);}},table:[{3:1,4:2,5:e,6:4,7:5,8:n,9:r,10:i,11:a,12:6,13:11,19:o,23:s},{1:[3]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{3:14,4:2,5:e,6:4,7:5,8:n,9:r,10:i,11:a,12:6,13:11,19:o,23:s},{1:[2,9]},t(c,[2,5]),t(c,[2,6]),t(c,[2,7]),t(c,[2,8]),{14:15,20:[1,16]},{16:[1,17]},{20:[2,12]},{1:[2,4]},{15:18,17:[1,19],22:l},t([17,22],[2,13]),{6:30,7:29,8:n,9:r,10:i,11:a,13:11,19:o,24:21,26:22,27:34,28:43,29:44,31:23,33:24,34:25,35:26,36:27,37:28,38:u,40:h,42:f,43:d,48:p,50:g,51:y,63:m,64:b,66:v,70:_,84:x,85:k,86:w,87:T},{16:[1,49]},{18:50,21:[1,51]},{16:[2,15]},{25:[1,52]},{16:[1,53],25:[2,17]},t(E,[2,25],{32:[1,54]}),t(E,[2,27]),t(E,[2,28]),t(E,[2,29]),t(E,[2,30]),t(E,[2,31]),t(E,[2,32]),t(E,[2,33]),{39:[1,55]},{41:[1,56]},t(E,[2,36]),t(E,[2,44],{52:57,54:60,55:61,32:[1,59],53:[1,58],56:C,57:S,58:A,59:M,60:N,61:O,62:D}),{27:69,28:43,29:44,84:x,85:k,86:w,87:T},t(E,[2,46]),t(E,[2,47]),{28:70,84:x,85:k,86:w},{27:71,28:43,29:44,84:x,85:k,86:w,87:T},{27:72,28:43,29:44,84:x,85:k,86:w,87:T},{27:73,28:43,29:44,84:x,85:k,86:w,87:T},{53:[1,74]},t(B,[2,20],{28:43,29:44,27:75,30:[1,76],84:x,85:k,86:w,87:T}),t(B,[2,21],{30:[1,77]}),t(L,[2,91]),t(L,[2,92]),t(L,[2,93]),t([16,25,30,32,44,45,53,56,57,58,59,60,61,62,67,69],[2,94]),t(I,[2,10]),{15:78,22:l},{22:[2,14]},{1:[2,16]},{6:30,7:29,8:n,9:r,10:i,11:a,13:11,19:o,24:79,25:[2,18],26:22,27:34,28:43,29:44,31:23,33:24,34:25,35:26,36:27,37:28,38:u,40:h,42:f,43:d,48:p,50:g,51:y,63:m,64:b,66:v,70:_,84:x,85:k,86:w,87:T},t(E,[2,26]),t(E,[2,34]),t(E,[2,35]),{27:80,28:43,29:44,53:[1,81],84:x,85:k,86:w,87:T},{52:82,54:60,55:61,56:C,57:S,58:A,59:M,60:N,61:O,62:D},t(E,[2,45]),{55:83,61:O,62:D},t(F,[2,55],{54:84,56:C,57:S,58:A,59:M,60:N}),t(R,[2,56]),t(R,[2,57]),t(R,[2,58]),t(R,[2,59]),t(R,[2,60]),t(P,[2,61]),t(P,[2,62]),t(E,[2,37],{44:[1,85],45:[1,86]}),{49:[1,87]},{53:[1,88]},{53:[1,89]},{67:[1,90],69:[1,91]},{28:92,84:x,85:k,86:w},t(B,[2,22]),t(B,[2,23]),t(B,[2,24]),{16:[1,93]},{25:[2,19]},t(j,[2,48]),{27:94,28:43,29:44,84:x,85:k,86:w,87:T},{27:95,28:43,29:44,53:[1,96],84:x,85:k,86:w,87:T},t(F,[2,54],{54:97,56:C,57:S,58:A,59:M,60:N}),t(F,[2,53]),{28:98,84:x,85:k,86:w},{46:99,50:z},{27:101,28:43,29:44,84:x,85:k,86:w,87:T},t(E,[2,63],{53:[1,102]}),t(E,[2,65],{53:[1,104],65:[1,103]}),t(E,[2,69],{53:[1,105],68:[1,106]}),t(E,[2,73],{53:[1,108],65:[1,107]}),t(E,[2,77]),t(I,[2,11]),t(j,[2,50]),t(j,[2,49]),{27:109,28:43,29:44,84:x,85:k,86:w,87:T},t(F,[2,52]),t(E,[2,38],{45:[1,110]}),{47:[1,111]},{46:112,47:[2,42],50:z},t(E,[2,41]),t(E,[2,64]),t(E,[2,66]),t(E,[2,67],{65:[1,113]}),t(E,[2,70]),t(E,[2,71],{53:[1,114]}),t(E,[2,74]),t(E,[2,75],{65:[1,115]}),t(j,[2,51]),{46:116,50:z},t(E,[2,39]),{47:[2,43]},t(E,[2,68]),t(E,[2,72]),t(E,[2,76]),{47:[1,117]},t(E,[2,40])],defaultActions:{2:[2,1],3:[2,2],4:[2,3],6:[2,9],13:[2,12],14:[2,4],20:[2,15],51:[2,14],52:[2,16],79:[2,19],112:[2,43]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},U={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),19;case 1:return 8;case 2:return 9;case 3:return 10;case 4:return 11;case 5:return this.begin("type_directive"),20;case 6:return this.popState(),this.begin("arg_directive"),17;case 7:return this.popState(),this.popState(),22;case 8:return 21;case 9:case 10:case 19:case 27:break;case 11:return this.begin("acc_title"),38;case 12:return this.popState(),"acc_title_value";case 13:return this.begin("acc_descr"),40;case 14:return this.popState(),"acc_descr_value";case 15:this.begin("acc_descr_multiline");break;case 16:case 37:case 40:case 43:case 46:case 49:case 52:this.popState();break;case 17:return "acc_descr_multiline_value";case 18:return 16;case 20:case 21:return 23;case 22:return this.begin("struct"),45;case 23:return "EDGE_STATE";case 24:return "EOF_IN_STRUCT";case 25:return "OPEN_IN_STRUCT";case 26:return this.popState(),47;case 28:return "MEMBER";case 29:return 43;case 30:return 70;case 31:return 63;case 32:return 64;case 33:return 66;case 34:return 48;case 35:return 49;case 36:this.begin("generic");break;case 38:return "GENERICTYPE";case 39:this.begin("string");break;case 41:return "STR";case 42:this.begin("bqstring");break;case 44:return "BQUOTE_STR";case 45:this.begin("href");break;case 47:return 69;case 48:this.begin("callback_name");break;case 50:this.popState(),this.begin("callback_args");break;case 51:return 67;case 53:return 68;case 54:case 55:case 56:case 57:return 65;case 58:case 59:return 57;case 60:case 61:return 59;case 62:return 58;case 63:return 56;case 64:return 60;case 65:return 61;case 66:return 62;case 67:return 32;case 68:return 44;case 69:return 82;case 70:return "DOT";case 71:return "PLUS";case 72:return 79;case 73:case 74:return "EQUALS";case 75:return 86;case 76:return "PUNCTUATION";case 77:return 85;case 78:return 84;case 79:return 81;case 80:return 25}},rules:[/^(?:%%\{)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:[{])/,/^(?:\[\*\])/,/^(?:$)/,/^(?:[{])/,/^(?:[}])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:class\b)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:[~])/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:[`])/,/^(?:[`])/,/^(?:[^`]+)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:\s*\(\))/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\s)/,/^(?:$)/],conditions:{acc_descr_multiline:{rules:[16,17],inclusive:!1},acc_descr:{rules:[14],inclusive:!1},acc_title:{rules:[12],inclusive:!1},arg_directive:{rules:[7,8],inclusive:!1},type_directive:{rules:[6,7],inclusive:!1},open_directive:{rules:[5],inclusive:!1},callback_args:{rules:[52,53],inclusive:!1},callback_name:{rules:[49,50,51],inclusive:!1},href:{rules:[46,47],inclusive:!1},struct:{rules:[23,24,25,26,27,28],inclusive:!1},generic:{rules:[37,38],inclusive:!1},bqstring:{rules:[43,44],inclusive:!1},string:{rules:[40,41],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,13,15,18,19,20,21,22,23,29,30,31,32,33,34,35,36,39,42,45,48,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80],inclusive:!0}}};function $(){this.yy={};}return Y.lexer=U,$.prototype=Y,Y.Parser=$,new $}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8218).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},5890:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,23,25,27,29,30,49],i=[1,17],a=[1,18],o=[1,19],s=[1,20],c=[1,21],l=[1,24],u=[1,29],h=[1,30],f=[1,31],d=[1,32],p=[6,9,11,15,20,23,25,27,29,30,42,43,44,45,49],g=[1,45],y=[30,46,47],m=[4,6,9,11,23,25,27,29,30,49],b=[42,43,44,45],v=[22,37],_=[1,64],x={trace:function(){},yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,entityName:17,relSpec:18,role:19,BLOCK_START:20,attributes:21,BLOCK_STOP:22,title:23,title_value:24,acc_title:25,acc_title_value:26,acc_descr:27,acc_descr_value:28,acc_descr_multiline_value:29,ALPHANUM:30,".":31,attribute:32,attributeType:33,attributeName:34,attributeKeyType:35,attributeComment:36,ATTRIBUTE_WORD:37,ATTRIBUTE_KEY:38,COMMENT:39,cardinality:40,relType:41,ZERO_OR_ONE:42,ZERO_OR_MORE:43,ONE_OR_MORE:44,ONLY_ONE:45,NON_IDENTIFYING:46,IDENTIFYING:47,WORD:48,open_directive:49,type_directive:50,arg_directive:51,close_directive:52,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",20:"BLOCK_START",22:"BLOCK_STOP",23:"title",24:"title_value",25:"acc_title",26:"acc_title_value",27:"acc_descr",28:"acc_descr_value",29:"acc_descr_multiline_value",30:"ALPHANUM",31:".",37:"ATTRIBUTE_WORD",38:"ATTRIBUTE_KEY",39:"COMMENT",42:"ZERO_OR_ONE",43:"ZERO_OR_MORE",44:"ONE_OR_MORE",45:"ONLY_ONE",46:"NON_IDENTIFYING",47:"IDENTIFYING",48:"WORD",49:"open_directive",50:"type_directive",51:"arg_directive",52:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,5],[10,4],[10,3],[10,1],[10,2],[10,2],[10,2],[10,1],[17,1],[17,3],[21,1],[21,2],[32,2],[32,3],[32,3],[32,4],[33,1],[34,1],[35,1],[36,1],[18,3],[40,1],[40,1],[40,1],[40,1],[41,1],[41,1],[19,1],[19,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:break;case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:case 20:case 28:case 29:case 30:case 40:this.$=a[s];break;case 12:r.addEntity(a[s-4]),r.addEntity(a[s-2]),r.addRelationship(a[s-4],a[s],a[s-2],a[s-3]);break;case 13:r.addEntity(a[s-3]),r.addAttributes(a[s-3],a[s-1]);break;case 14:r.addEntity(a[s-2]);break;case 15:r.addEntity(a[s]);break;case 16:case 17:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 18:case 19:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 21:this.$=a[s-2]+a[s-1]+a[s];break;case 22:this.$=[a[s]];break;case 23:a[s].push(a[s-1]),this.$=a[s];break;case 24:this.$={attributeType:a[s-1],attributeName:a[s]};break;case 25:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeKeyType:a[s]};break;case 26:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeComment:a[s]};break;case 27:this.$={attributeType:a[s-3],attributeName:a[s-2],attributeKeyType:a[s-1],attributeComment:a[s]};break;case 31:case 39:this.$=a[s].replace(/"/g,"");break;case 32:this.$={cardA:a[s],relType:a[s-1],cardB:a[s-2]};break;case 33:this.$=r.Cardinality.ZERO_OR_ONE;break;case 34:this.$=r.Cardinality.ZERO_OR_MORE;break;case 35:this.$=r.Cardinality.ONE_OR_MORE;break;case 36:this.$=r.Cardinality.ONLY_ONE;break;case 37:this.$=r.Identification.NON_IDENTIFYING;break;case 38:this.$=r.Identification.IDENTIFYING;break;case 41:r.parseDirective("%%{","open_directive");break;case 42:r.parseDirective(a[s],"type_directive");break;case 43:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 44:r.parseDirective("}%%","close_directive","er");}},table:[{3:1,4:e,7:3,12:4,49:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,49:n},{13:8,50:[1,9]},{50:[2,41]},{6:[1,10],7:15,8:11,9:[1,12],10:13,11:[1,14],12:4,17:16,23:i,25:a,27:o,29:s,30:c,49:n},{1:[2,2]},{14:22,15:[1,23],52:l},t([15,52],[2,42]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:15,10:25,12:4,17:16,23:i,25:a,27:o,29:s,30:c,49:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,15],{18:26,40:28,20:[1,27],42:u,43:h,44:f,45:d}),{24:[1,33]},{26:[1,34]},{28:[1,35]},t(r,[2,19]),t(p,[2,20],{31:[1,36]}),{11:[1,37]},{16:38,51:[1,39]},{11:[2,44]},t(r,[2,5]),{17:40,30:c},{21:41,22:[1,42],32:43,33:44,37:g},{41:46,46:[1,47],47:[1,48]},t(y,[2,33]),t(y,[2,34]),t(y,[2,35]),t(y,[2,36]),t(r,[2,16]),t(r,[2,17]),t(r,[2,18]),{17:49,30:c},t(m,[2,9]),{14:50,52:l},{52:[2,43]},{15:[1,51]},{22:[1,52]},t(r,[2,14]),{21:53,22:[2,22],32:43,33:44,37:g},{34:54,37:[1,55]},{37:[2,28]},{40:56,42:u,43:h,44:f,45:d},t(b,[2,37]),t(b,[2,38]),t(p,[2,21]),{11:[1,57]},{19:58,30:[1,60],48:[1,59]},t(r,[2,13]),{22:[2,23]},t(v,[2,24],{35:61,36:62,38:[1,63],39:_}),t([22,37,38,39],[2,29]),{30:[2,32]},t(m,[2,10]),t(r,[2,12]),t(r,[2,39]),t(r,[2,40]),t(v,[2,25],{36:65,39:_}),t(v,[2,26]),t([22,37,39],[2,30]),t(v,[2,31]),t(v,[2,27])],defaultActions:{5:[2,41],7:[2,2],24:[2,44],39:[2,43],45:[2,28],53:[2,23],56:[2,32]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},k={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("acc_title"),25;case 1:return this.popState(),"acc_title_value";case 2:return this.begin("acc_descr"),27;case 3:return this.popState(),"acc_descr_value";case 4:this.begin("acc_descr_multiline");break;case 5:this.popState();break;case 6:return "acc_descr_multiline_value";case 7:return this.begin("open_directive"),49;case 8:return this.begin("type_directive"),50;case 9:return this.popState(),this.begin("arg_directive"),15;case 10:return this.popState(),this.popState(),52;case 11:return 51;case 12:case 13:case 15:case 20:case 25:break;case 14:return 11;case 16:return 9;case 17:return 48;case 18:return 4;case 19:return this.begin("block"),20;case 21:return 38;case 22:case 23:return 37;case 24:return 39;case 26:return this.popState(),22;case 27:case 40:return e.yytext[0];case 28:case 32:return 42;case 29:case 33:return 43;case 30:case 34:return 44;case 31:return 45;case 35:case 37:case 38:return 46;case 36:return 47;case 39:return 30;case 41:return 6}},rules:[/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:[\s]+)/i,/^(?:"[^"]*")/i,/^(?:erDiagram\b)/i,/^(?:\{)/i,/^(?:\s+)/i,/^(?:\b((?:PK)|(?:FK))\b)/i,/^(?:(.*?)[~](.*?)*[~])/i,/^(?:[A-Za-z][A-Za-z0-9\-_\[\]]*)/i,/^(?:"[^"]*")/i,/^(?:[\n]+)/i,/^(?:\})/i,/^(?:.)/i,/^(?:\|o\b)/i,/^(?:\}o\b)/i,/^(?:\}\|)/i,/^(?:\|\|)/i,/^(?:o\|)/i,/^(?:o\{)/i,/^(?:\|\{)/i,/^(?:\.\.)/i,/^(?:--)/i,/^(?:\.-)/i,/^(?:-\.)/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:.)/i,/^(?:$)/i],conditions:{acc_descr_multiline:{rules:[5,6],inclusive:!1},acc_descr:{rules:[3],inclusive:!1},acc_title:{rules:[1],inclusive:!1},open_directive:{rules:[8],inclusive:!1},type_directive:{rules:[9,10],inclusive:!1},arg_directive:{rules:[10,11],inclusive:!1},block:{rules:[20,21,22,23,24,25,26,27],inclusive:!1},INITIAL:{rules:[0,2,4,7,12,13,14,15,16,17,18,19,28,29,30,31,32,33,34,35,36,37,38,39,40,41],inclusive:!0}}};function w(){this.yy={};}return x.lexer=k,w.prototype=x,x.Parser=w,new w}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8009).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},3602:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,9],n=[1,7],r=[1,6],i=[1,8],a=[1,20,21,22,23,38,44,46,48,52,66,67,86,87,88,89,90,91,95,105,106,109,111,112,118,119,120,121,122,123,124,125,126,127],o=[2,10],s=[1,20],c=[1,21],l=[1,22],u=[1,23],h=[1,30],f=[1,32],d=[1,33],p=[1,34],g=[1,62],y=[1,48],m=[1,52],b=[1,36],v=[1,37],_=[1,38],x=[1,39],k=[1,40],w=[1,56],T=[1,63],E=[1,51],C=[1,53],S=[1,55],A=[1,59],M=[1,60],N=[1,41],O=[1,42],D=[1,43],B=[1,44],L=[1,61],I=[1,50],F=[1,54],R=[1,57],P=[1,58],j=[1,49],z=[1,66],Y=[1,71],U=[1,20,21,22,23,38,42,44,46,48,52,66,67,86,87,88,89,90,91,95,105,106,109,111,112,118,119,120,121,122,123,124,125,126,127],$=[1,75],W=[1,74],q=[1,76],H=[20,21,23,81,82],V=[1,99],G=[1,104],X=[1,107],Z=[1,108],Q=[1,101],K=[1,106],J=[1,109],tt=[1,102],et=[1,114],nt=[1,113],rt=[1,103],it=[1,105],at=[1,110],ot=[1,111],st=[1,112],ct=[1,115],lt=[20,21,22,23,81,82],ut=[20,21,22,23,53,81,82],ht=[20,21,22,23,40,52,53,55,57,59,61,63,65,66,67,69,71,73,74,76,81,82,91,95,105,106,109,111,112,122,123,124,125,126,127],ft=[20,21,23],dt=[20,21,23,52,66,67,81,82,91,95,105,106,109,111,112,122,123,124,125,126,127],pt=[1,12,20,21,22,23,24,38,42,44,46,48,52,66,67,86,87,88,89,90,91,95,105,106,109,111,112,118,119,120,121,122,123,124,125,126,127],gt=[52,66,67,91,95,105,106,109,111,112,122,123,124,125,126,127],yt=[1,149],mt=[1,157],bt=[1,158],vt=[1,159],_t=[1,160],xt=[1,144],kt=[1,145],wt=[1,141],Tt=[1,152],Et=[1,153],Ct=[1,154],St=[1,155],At=[1,156],Mt=[1,161],Nt=[1,162],Ot=[1,147],Dt=[1,150],Bt=[1,146],Lt=[1,143],It=[20,21,22,23,38,42,44,46,48,52,66,67,86,87,88,89,90,91,95,105,106,109,111,112,118,119,120,121,122,123,124,125,126,127],Ft=[1,165],Rt=[20,21,22,23,26,52,66,67,91,105,106,109,111,112,122,123,124,125,126,127],Pt=[20,21,22,23,24,26,38,40,41,42,52,56,58,60,62,64,66,67,68,70,72,73,75,77,81,82,86,87,88,89,90,91,92,95,105,106,109,111,112,113,114,122,123,124,125,126,127],jt=[12,21,22,24],zt=[22,106],Yt=[1,250],Ut=[1,245],$t=[1,246],Wt=[1,254],qt=[1,251],Ht=[1,248],Vt=[1,247],Gt=[1,249],Xt=[1,252],Zt=[1,253],Qt=[1,255],Kt=[1,273],Jt=[20,21,23,106],te=[20,21,22,23,66,67,86,102,105,106,109,110,111,112,113],ee={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,directive:5,openDirective:6,typeDirective:7,closeDirective:8,separator:9,":":10,argDirective:11,open_directive:12,type_directive:13,arg_directive:14,close_directive:15,graphConfig:16,document:17,line:18,statement:19,SEMI:20,NEWLINE:21,SPACE:22,EOF:23,GRAPH:24,NODIR:25,DIR:26,FirstStmtSeperator:27,ending:28,endToken:29,spaceList:30,spaceListNewline:31,verticeStatement:32,styleStatement:33,linkStyleStatement:34,classDefStatement:35,classStatement:36,clickStatement:37,subgraph:38,text:39,SQS:40,SQE:41,end:42,direction:43,acc_title:44,acc_title_value:45,acc_descr:46,acc_descr_value:47,acc_descr_multiline_value:48,link:49,node:50,vertex:51,AMP:52,STYLE_SEPARATOR:53,idString:54,DOUBLECIRCLESTART:55,DOUBLECIRCLEEND:56,PS:57,PE:58,"(-":59,"-)":60,STADIUMSTART:61,STADIUMEND:62,SUBROUTINESTART:63,SUBROUTINEEND:64,VERTEX_WITH_PROPS_START:65,ALPHA:66,COLON:67,PIPE:68,CYLINDERSTART:69,CYLINDEREND:70,DIAMOND_START:71,DIAMOND_STOP:72,TAGEND:73,TRAPSTART:74,TRAPEND:75,INVTRAPSTART:76,INVTRAPEND:77,linkStatement:78,arrowText:79,TESTSTR:80,START_LINK:81,LINK:82,textToken:83,STR:84,keywords:85,STYLE:86,LINKSTYLE:87,CLASSDEF:88,CLASS:89,CLICK:90,DOWN:91,UP:92,textNoTags:93,textNoTagsToken:94,DEFAULT:95,stylesOpt:96,alphaNum:97,CALLBACKNAME:98,CALLBACKARGS:99,HREF:100,LINK_TARGET:101,HEX:102,numList:103,INTERPOLATE:104,NUM:105,COMMA:106,style:107,styleComponent:108,MINUS:109,UNIT:110,BRKT:111,DOT:112,PCT:113,TAGSTART:114,alphaNumToken:115,idStringToken:116,alphaNumStatement:117,direction_tb:118,direction_bt:119,direction_rl:120,direction_lr:121,PUNCTUATION:122,UNICODE_TEXT:123,PLUS:124,EQUALS:125,MULT:126,UNDERSCORE:127,graphCodeTokens:128,ARROW_CROSS:129,ARROW_POINT:130,ARROW_CIRCLE:131,ARROW_OPEN:132,QUOTE:133,$accept:0,$end:1},terminals_:{2:"error",10:":",12:"open_directive",13:"type_directive",14:"arg_directive",15:"close_directive",20:"SEMI",21:"NEWLINE",22:"SPACE",23:"EOF",24:"GRAPH",25:"NODIR",26:"DIR",38:"subgraph",40:"SQS",41:"SQE",42:"end",44:"acc_title",45:"acc_title_value",46:"acc_descr",47:"acc_descr_value",48:"acc_descr_multiline_value",52:"AMP",53:"STYLE_SEPARATOR",55:"DOUBLECIRCLESTART",56:"DOUBLECIRCLEEND",57:"PS",58:"PE",59:"(-",60:"-)",61:"STADIUMSTART",62:"STADIUMEND",63:"SUBROUTINESTART",64:"SUBROUTINEEND",65:"VERTEX_WITH_PROPS_START",66:"ALPHA",67:"COLON",68:"PIPE",69:"CYLINDERSTART",70:"CYLINDEREND",71:"DIAMOND_START",72:"DIAMOND_STOP",73:"TAGEND",74:"TRAPSTART",75:"TRAPEND",76:"INVTRAPSTART",77:"INVTRAPEND",80:"TESTSTR",81:"START_LINK",82:"LINK",84:"STR",86:"STYLE",87:"LINKSTYLE",88:"CLASSDEF",89:"CLASS",90:"CLICK",91:"DOWN",92:"UP",95:"DEFAULT",98:"CALLBACKNAME",99:"CALLBACKARGS",100:"HREF",101:"LINK_TARGET",102:"HEX",104:"INTERPOLATE",105:"NUM",106:"COMMA",109:"MINUS",110:"UNIT",111:"BRKT",112:"DOT",113:"PCT",114:"TAGSTART",118:"direction_tb",119:"direction_bt",120:"direction_rl",121:"direction_lr",122:"PUNCTUATION",123:"UNICODE_TEXT",124:"PLUS",125:"EQUALS",126:"MULT",127:"UNDERSCORE",129:"ARROW_CROSS",130:"ARROW_POINT",131:"ARROW_CIRCLE",132:"ARROW_OPEN",133:"QUOTE"},productions_:[0,[3,1],[3,2],[5,4],[5,6],[6,1],[7,1],[11,1],[8,1],[4,2],[17,0],[17,2],[18,1],[18,1],[18,1],[18,1],[18,1],[16,2],[16,2],[16,2],[16,3],[28,2],[28,1],[29,1],[29,1],[29,1],[27,1],[27,1],[27,2],[31,2],[31,2],[31,1],[31,1],[30,2],[30,1],[19,2],[19,2],[19,2],[19,2],[19,2],[19,2],[19,9],[19,6],[19,4],[19,1],[19,2],[19,2],[19,1],[9,1],[9,1],[9,1],[32,3],[32,4],[32,2],[32,1],[50,1],[50,5],[50,3],[51,4],[51,4],[51,6],[51,4],[51,4],[51,4],[51,8],[51,4],[51,4],[51,4],[51,6],[51,4],[51,4],[51,4],[51,4],[51,4],[51,1],[49,2],[49,3],[49,3],[49,1],[49,3],[78,1],[79,3],[39,1],[39,2],[39,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[93,1],[93,2],[35,5],[35,5],[36,5],[37,2],[37,4],[37,3],[37,5],[37,2],[37,4],[37,4],[37,6],[37,2],[37,4],[37,2],[37,4],[37,4],[37,6],[33,5],[33,5],[34,5],[34,5],[34,9],[34,9],[34,7],[34,7],[103,1],[103,3],[96,1],[96,3],[107,1],[107,2],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[83,1],[83,1],[83,1],[83,1],[83,1],[83,1],[94,1],[94,1],[94,1],[94,1],[54,1],[54,2],[97,1],[97,2],[117,1],[117,1],[117,1],[117,1],[43,1],[43,1],[43,1],[43,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[115,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[116,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1],[128,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 5:r.parseDirective("%%{","open_directive");break;case 6:r.parseDirective(a[s],"type_directive");break;case 7:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 8:r.parseDirective("}%%","close_directive","flowchart");break;case 10:case 36:case 37:case 38:case 39:case 40:this.$=[];break;case 11:a[s]!==[]&&a[s-1].push(a[s]),this.$=a[s-1];break;case 12:case 82:case 84:case 96:case 152:case 154:case 155:case 78:case 150:this.$=a[s];break;case 19:r.setDirection("TB"),this.$="TB";break;case 20:r.setDirection(a[s-1]),this.$=a[s-1];break;case 35:this.$=a[s-1].nodes;break;case 41:this.$=r.addSubGraph(a[s-6],a[s-1],a[s-4]);break;case 42:this.$=r.addSubGraph(a[s-3],a[s-1],a[s-3]);break;case 43:this.$=r.addSubGraph(void 0,a[s-1],void 0);break;case 45:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 46:case 47:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 51:r.addLink(a[s-2].stmt,a[s],a[s-1]),this.$={stmt:a[s],nodes:a[s].concat(a[s-2].nodes)};break;case 52:r.addLink(a[s-3].stmt,a[s-1],a[s-2]),this.$={stmt:a[s-1],nodes:a[s-1].concat(a[s-3].nodes)};break;case 53:this.$={stmt:a[s-1],nodes:a[s-1]};break;case 54:this.$={stmt:a[s],nodes:a[s]};break;case 55:case 123:case 125:this.$=[a[s]];break;case 56:this.$=a[s-4].concat(a[s]);break;case 57:this.$=[a[s-2]],r.setClass(a[s-2],a[s]);break;case 58:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"square");break;case 59:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"doublecircle");break;case 60:this.$=a[s-5],r.addVertex(a[s-5],a[s-2],"circle");break;case 61:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"ellipse");break;case 62:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"stadium");break;case 63:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"subroutine");break;case 64:this.$=a[s-7],r.addVertex(a[s-7],a[s-1],"rect",void 0,void 0,void 0,Object.fromEntries([[a[s-5],a[s-3]]]));break;case 65:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"cylinder");break;case 66:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"round");break;case 67:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"diamond");break;case 68:this.$=a[s-5],r.addVertex(a[s-5],a[s-2],"hexagon");break;case 69:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"odd");break;case 70:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"trapezoid");break;case 71:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"inv_trapezoid");break;case 72:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"lean_right");break;case 73:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"lean_left");break;case 74:this.$=a[s],r.addVertex(a[s]);break;case 75:a[s-1].text=a[s],this.$=a[s-1];break;case 76:case 77:a[s-2].text=a[s-1],this.$=a[s-2];break;case 79:var c=r.destructLink(a[s],a[s-2]);this.$={type:c.type,stroke:c.stroke,length:c.length,text:a[s-1]};break;case 80:c=r.destructLink(a[s]),this.$={type:c.type,stroke:c.stroke,length:c.length};break;case 81:this.$=a[s-1];break;case 83:case 97:case 153:case 151:this.$=a[s-1]+""+a[s];break;case 98:case 99:this.$=a[s-4],r.addClass(a[s-2],a[s]);break;case 100:this.$=a[s-4],r.setClass(a[s-2],a[s]);break;case 101:case 109:this.$=a[s-1],r.setClickEvent(a[s-1],a[s]);break;case 102:case 110:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2]),r.setTooltip(a[s-3],a[s]);break;case 103:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 104:this.$=a[s-4],r.setClickEvent(a[s-4],a[s-3],a[s-2]),r.setTooltip(a[s-4],a[s]);break;case 105:case 111:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 106:case 112:this.$=a[s-3],r.setLink(a[s-3],a[s-2]),r.setTooltip(a[s-3],a[s]);break;case 107:case 113:this.$=a[s-3],r.setLink(a[s-3],a[s-2],a[s]);break;case 108:case 114:this.$=a[s-5],r.setLink(a[s-5],a[s-4],a[s]),r.setTooltip(a[s-5],a[s-2]);break;case 115:this.$=a[s-4],r.addVertex(a[s-2],void 0,void 0,a[s]);break;case 116:case 118:this.$=a[s-4],r.updateLink(a[s-2],a[s]);break;case 117:this.$=a[s-4],r.updateLink([a[s-2]],a[s]);break;case 119:this.$=a[s-8],r.updateLinkInterpolate([a[s-6]],a[s-2]),r.updateLink([a[s-6]],a[s]);break;case 120:this.$=a[s-8],r.updateLinkInterpolate(a[s-6],a[s-2]),r.updateLink(a[s-6],a[s]);break;case 121:this.$=a[s-6],r.updateLinkInterpolate([a[s-4]],a[s]);break;case 122:this.$=a[s-6],r.updateLinkInterpolate(a[s-4],a[s]);break;case 124:case 126:a[s-2].push(a[s]),this.$=a[s-2];break;case 128:this.$=a[s-1]+a[s];break;case 156:this.$="v";break;case 157:this.$="-";break;case 158:this.$={stmt:"dir",value:"TB"};break;case 159:this.$={stmt:"dir",value:"BT"};break;case 160:this.$={stmt:"dir",value:"RL"};break;case 161:this.$={stmt:"dir",value:"LR"};}},table:[{3:1,4:2,5:3,6:5,12:e,16:4,21:n,22:r,24:i},{1:[3]},{1:[2,1]},{3:10,4:2,5:3,6:5,12:e,16:4,21:n,22:r,24:i},t(a,o,{17:11}),{7:12,13:[1,13]},{16:14,21:n,22:r,24:i},{16:15,21:n,22:r,24:i},{25:[1,16],26:[1,17]},{13:[2,5]},{1:[2,2]},{1:[2,9],18:18,19:19,20:s,21:c,22:l,23:u,32:24,33:25,34:26,35:27,36:28,37:29,38:h,43:31,44:f,46:d,48:p,50:35,51:45,52:g,54:46,66:y,67:m,86:b,87:v,88:_,89:x,90:k,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,118:N,119:O,120:D,121:B,122:L,123:I,124:F,125:R,126:P,127:j},{8:64,10:[1,65],15:z},t([10,15],[2,6]),t(a,[2,17]),t(a,[2,18]),t(a,[2,19]),{20:[1,68],21:[1,69],22:Y,27:67,30:70},t(U,[2,11]),t(U,[2,12]),t(U,[2,13]),t(U,[2,14]),t(U,[2,15]),t(U,[2,16]),{9:72,20:$,21:W,23:q,49:73,78:77,81:[1,78],82:[1,79]},{9:80,20:$,21:W,23:q},{9:81,20:$,21:W,23:q},{9:82,20:$,21:W,23:q},{9:83,20:$,21:W,23:q},{9:84,20:$,21:W,23:q},{9:86,20:$,21:W,22:[1,85],23:q},t(U,[2,44]),{45:[1,87]},{47:[1,88]},t(U,[2,47]),t(H,[2,54],{30:89,22:Y}),{22:[1,90]},{22:[1,91]},{22:[1,92]},{22:[1,93]},{26:V,52:G,66:X,67:Z,84:[1,97],91:Q,97:96,98:[1,94],100:[1,95],105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(U,[2,158]),t(U,[2,159]),t(U,[2,160]),t(U,[2,161]),t(lt,[2,55],{53:[1,116]}),t(ut,[2,74],{116:129,40:[1,117],52:g,55:[1,118],57:[1,119],59:[1,120],61:[1,121],63:[1,122],65:[1,123],66:y,67:m,69:[1,124],71:[1,125],73:[1,126],74:[1,127],76:[1,128],91:w,95:T,105:E,106:C,109:S,111:A,112:M,122:L,123:I,124:F,125:R,126:P,127:j}),t(ht,[2,150]),t(ht,[2,175]),t(ht,[2,176]),t(ht,[2,177]),t(ht,[2,178]),t(ht,[2,179]),t(ht,[2,180]),t(ht,[2,181]),t(ht,[2,182]),t(ht,[2,183]),t(ht,[2,184]),t(ht,[2,185]),t(ht,[2,186]),t(ht,[2,187]),t(ht,[2,188]),t(ht,[2,189]),t(ht,[2,190]),{9:130,20:$,21:W,23:q},{11:131,14:[1,132]},t(ft,[2,8]),t(a,[2,20]),t(a,[2,26]),t(a,[2,27]),{21:[1,133]},t(dt,[2,34],{30:134,22:Y}),t(U,[2,35]),{50:135,51:45,52:g,54:46,66:y,67:m,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,122:L,123:I,124:F,125:R,126:P,127:j},t(pt,[2,48]),t(pt,[2,49]),t(pt,[2,50]),t(gt,[2,78],{79:136,68:[1,138],80:[1,137]}),{22:yt,24:mt,26:bt,38:vt,39:139,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t([52,66,67,68,80,91,95,105,106,109,111,112,122,123,124,125,126,127],[2,80]),t(U,[2,36]),t(U,[2,37]),t(U,[2,38]),t(U,[2,39]),t(U,[2,40]),{22:yt,24:mt,26:bt,38:vt,39:163,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(It,o,{17:164}),t(U,[2,45]),t(U,[2,46]),t(H,[2,53],{52:Ft}),{26:V,52:G,66:X,67:Z,91:Q,97:166,102:[1,167],105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},{95:[1,168],103:169,105:[1,170]},{26:V,52:G,66:X,67:Z,91:Q,95:[1,171],97:172,105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},{26:V,52:G,66:X,67:Z,91:Q,97:173,105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ft,[2,101],{22:[1,174],99:[1,175]}),t(ft,[2,105],{22:[1,176]}),t(ft,[2,109],{115:100,117:178,22:[1,177],26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,122:rt,123:it,124:at,125:ot,126:st,127:ct}),t(ft,[2,111],{22:[1,179]}),t(Rt,[2,152]),t(Rt,[2,154]),t(Rt,[2,155]),t(Rt,[2,156]),t(Rt,[2,157]),t(Pt,[2,162]),t(Pt,[2,163]),t(Pt,[2,164]),t(Pt,[2,165]),t(Pt,[2,166]),t(Pt,[2,167]),t(Pt,[2,168]),t(Pt,[2,169]),t(Pt,[2,170]),t(Pt,[2,171]),t(Pt,[2,172]),t(Pt,[2,173]),t(Pt,[2,174]),{52:g,54:180,66:y,67:m,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,122:L,123:I,124:F,125:R,126:P,127:j},{22:yt,24:mt,26:bt,38:vt,39:181,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:182,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:184,42:_t,52:G,57:[1,183],66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:185,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:186,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:187,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{66:[1,188]},{22:yt,24:mt,26:bt,38:vt,39:189,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:190,42:_t,52:G,66:X,67:Z,71:[1,191],73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:192,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:193,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:194,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ht,[2,151]),t(jt,[2,3]),{8:195,15:z},{15:[2,7]},t(a,[2,28]),t(dt,[2,33]),t(H,[2,51],{30:196,22:Y}),t(gt,[2,75],{22:[1,197]}),{22:[1,198]},{22:yt,24:mt,26:bt,38:vt,39:199,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,73:xt,81:kt,82:[1,200],83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(Pt,[2,82]),t(Pt,[2,84]),t(Pt,[2,140]),t(Pt,[2,141]),t(Pt,[2,142]),t(Pt,[2,143]),t(Pt,[2,144]),t(Pt,[2,145]),t(Pt,[2,146]),t(Pt,[2,147]),t(Pt,[2,148]),t(Pt,[2,149]),t(Pt,[2,85]),t(Pt,[2,86]),t(Pt,[2,87]),t(Pt,[2,88]),t(Pt,[2,89]),t(Pt,[2,90]),t(Pt,[2,91]),t(Pt,[2,92]),t(Pt,[2,93]),t(Pt,[2,94]),t(Pt,[2,95]),{9:203,20:$,21:W,22:yt,23:q,24:mt,26:bt,38:vt,40:[1,202],42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{18:18,19:19,20:s,21:c,22:l,23:u,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,204],43:31,44:f,46:d,48:p,50:35,51:45,52:g,54:46,66:y,67:m,86:b,87:v,88:_,89:x,90:k,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,118:N,119:O,120:D,121:B,122:L,123:I,124:F,125:R,126:P,127:j},{22:Y,30:205},{22:[1,206],26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,115:100,117:178,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:[1,207]},{22:[1,208]},{22:[1,209],106:[1,210]},t(zt,[2,123]),{22:[1,211]},{22:[1,212],26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,115:100,117:178,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:[1,213],26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,115:100,117:178,122:rt,123:it,124:at,125:ot,126:st,127:ct},{84:[1,214]},t(ft,[2,103],{22:[1,215]}),{84:[1,216],101:[1,217]},{84:[1,218]},t(Rt,[2,153]),{84:[1,219],101:[1,220]},t(lt,[2,57],{116:129,52:g,66:y,67:m,91:w,95:T,105:E,106:C,109:S,111:A,112:M,122:L,123:I,124:F,125:R,126:P,127:j}),{22:yt,24:mt,26:bt,38:vt,41:[1,221],42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,56:[1,222],66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:223,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,58:[1,224],66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,60:[1,225],66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,62:[1,226],66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,64:[1,227],66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{67:[1,228]},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,70:[1,229],73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,72:[1,230],73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,39:231,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,41:[1,232],42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,73:xt,75:[1,233],77:[1,234],81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,73:xt,75:[1,236],77:[1,235],81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{9:237,20:$,21:W,23:q},t(H,[2,52],{52:Ft}),t(gt,[2,77]),t(gt,[2,76]),{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,68:[1,238],73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(gt,[2,79]),t(Pt,[2,83]),{22:yt,24:mt,26:bt,38:vt,39:239,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(It,o,{17:240}),t(U,[2,43]),{51:241,52:g,54:46,66:y,67:m,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,122:L,123:I,124:F,125:R,126:P,127:j},{22:Yt,66:Ut,67:$t,86:Wt,96:242,102:qt,105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{22:Yt,66:Ut,67:$t,86:Wt,96:256,102:qt,105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{22:Yt,66:Ut,67:$t,86:Wt,96:257,102:qt,104:[1,258],105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{22:Yt,66:Ut,67:$t,86:Wt,96:259,102:qt,104:[1,260],105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{105:[1,261]},{22:Yt,66:Ut,67:$t,86:Wt,96:262,102:qt,105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{22:Yt,66:Ut,67:$t,86:Wt,96:263,102:qt,105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{26:V,52:G,66:X,67:Z,91:Q,97:264,105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ft,[2,102]),{84:[1,265]},t(ft,[2,106],{22:[1,266]}),t(ft,[2,107]),t(ft,[2,110]),t(ft,[2,112],{22:[1,267]}),t(ft,[2,113]),t(ut,[2,58]),t(ut,[2,59]),{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,58:[1,268],66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ut,[2,66]),t(ut,[2,61]),t(ut,[2,62]),t(ut,[2,63]),{66:[1,269]},t(ut,[2,65]),t(ut,[2,67]),{22:yt,24:mt,26:bt,38:vt,42:_t,52:G,66:X,67:Z,72:[1,270],73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ut,[2,69]),t(ut,[2,70]),t(ut,[2,72]),t(ut,[2,71]),t(ut,[2,73]),t(jt,[2,4]),t([22,52,66,67,91,95,105,106,109,111,112,122,123,124,125,126,127],[2,81]),{22:yt,24:mt,26:bt,38:vt,41:[1,271],42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{18:18,19:19,20:s,21:c,22:l,23:u,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,272],43:31,44:f,46:d,48:p,50:35,51:45,52:g,54:46,66:y,67:m,86:b,87:v,88:_,89:x,90:k,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,118:N,119:O,120:D,121:B,122:L,123:I,124:F,125:R,126:P,127:j},t(lt,[2,56]),t(ft,[2,115],{106:Kt}),t(Jt,[2,125],{108:274,22:Yt,66:Ut,67:$t,86:Wt,102:qt,105:Ht,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt}),t(te,[2,127]),t(te,[2,129]),t(te,[2,130]),t(te,[2,131]),t(te,[2,132]),t(te,[2,133]),t(te,[2,134]),t(te,[2,135]),t(te,[2,136]),t(te,[2,137]),t(te,[2,138]),t(te,[2,139]),t(ft,[2,116],{106:Kt}),t(ft,[2,117],{106:Kt}),{22:[1,275]},t(ft,[2,118],{106:Kt}),{22:[1,276]},t(zt,[2,124]),t(ft,[2,98],{106:Kt}),t(ft,[2,99],{106:Kt}),t(ft,[2,100],{115:100,117:178,26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,122:rt,123:it,124:at,125:ot,126:st,127:ct}),t(ft,[2,104]),{101:[1,277]},{101:[1,278]},{58:[1,279]},{68:[1,280]},{72:[1,281]},{9:282,20:$,21:W,23:q},t(U,[2,42]),{22:Yt,66:Ut,67:$t,86:Wt,102:qt,105:Ht,107:283,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},t(te,[2,128]),{26:V,52:G,66:X,67:Z,91:Q,97:284,105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},{26:V,52:G,66:X,67:Z,91:Q,97:285,105:K,106:J,109:tt,111:et,112:nt,115:100,117:98,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ft,[2,108]),t(ft,[2,114]),t(ut,[2,60]),{22:yt,24:mt,26:bt,38:vt,39:286,42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:140,84:wt,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},t(ut,[2,68]),t(It,o,{17:287}),t(Jt,[2,126],{108:274,22:Yt,66:Ut,67:$t,86:Wt,102:qt,105:Ht,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt}),t(ft,[2,121],{115:100,117:178,22:[1,288],26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,122:rt,123:it,124:at,125:ot,126:st,127:ct}),t(ft,[2,122],{115:100,117:178,22:[1,289],26:V,52:G,66:X,67:Z,91:Q,105:K,106:J,109:tt,111:et,112:nt,122:rt,123:it,124:at,125:ot,126:st,127:ct}),{22:yt,24:mt,26:bt,38:vt,41:[1,290],42:_t,52:G,66:X,67:Z,73:xt,81:kt,83:201,85:151,86:Tt,87:Et,88:Ct,89:St,90:At,91:Mt,92:Nt,94:142,95:Ot,105:K,106:J,109:Dt,111:et,112:nt,113:Bt,114:Lt,115:148,122:rt,123:it,124:at,125:ot,126:st,127:ct},{18:18,19:19,20:s,21:c,22:l,23:u,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,291],43:31,44:f,46:d,48:p,50:35,51:45,52:g,54:46,66:y,67:m,86:b,87:v,88:_,89:x,90:k,91:w,95:T,105:E,106:C,109:S,111:A,112:M,116:47,118:N,119:O,120:D,121:B,122:L,123:I,124:F,125:R,126:P,127:j},{22:Yt,66:Ut,67:$t,86:Wt,96:292,102:qt,105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},{22:Yt,66:Ut,67:$t,86:Wt,96:293,102:qt,105:Ht,107:243,108:244,109:Vt,110:Gt,111:Xt,112:Zt,113:Qt},t(ut,[2,64]),t(U,[2,41]),t(ft,[2,119],{106:Kt}),t(ft,[2,120],{106:Kt})],defaultActions:{2:[2,1],9:[2,5],10:[2,2],132:[2,7]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},ne={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),12;case 1:return this.begin("type_directive"),13;case 2:return this.popState(),this.begin("arg_directive"),10;case 3:return this.popState(),this.popState(),15;case 4:return 14;case 5:case 6:break;case 7:return this.begin("acc_title"),44;case 8:return this.popState(),"acc_title_value";case 9:return this.begin("acc_descr"),46;case 10:return this.popState(),"acc_descr_value";case 11:this.begin("acc_descr_multiline");break;case 12:case 15:case 24:case 27:case 30:case 33:this.popState();break;case 13:return "acc_descr_multiline_value";case 14:this.begin("string");break;case 16:return "STR";case 17:return 86;case 18:return 95;case 19:return 87;case 20:return 104;case 21:return 88;case 22:return 89;case 23:this.begin("href");break;case 25:return 100;case 26:this.begin("callbackname");break;case 28:this.popState(),this.begin("callbackargs");break;case 29:return 98;case 31:return 99;case 32:this.begin("click");break;case 34:return 90;case 35:case 36:return t.lex.firstGraph()&&this.begin("dir"),24;case 37:return 38;case 38:return 42;case 39:case 40:case 41:case 42:return 101;case 43:return this.popState(),25;case 44:case 45:case 46:case 47:case 48:case 49:case 50:case 51:case 52:case 53:return this.popState(),26;case 54:return 118;case 55:return 119;case 56:return 120;case 57:return 121;case 58:return 105;case 59:return 111;case 60:return 53;case 61:return 67;case 62:return 52;case 63:return 20;case 64:return 106;case 65:return 126;case 66:case 67:case 68:return 82;case 69:case 70:case 71:return 81;case 72:return 59;case 73:return 60;case 74:return 61;case 75:return 62;case 76:return 63;case 77:return 64;case 78:return 65;case 79:return 69;case 80:return 70;case 81:return 55;case 82:return 56;case 83:return 109;case 84:return 112;case 85:return 127;case 86:return 124;case 87:return 113;case 88:case 89:return 125;case 90:return 114;case 91:return 73;case 92:return 92;case 93:return "SEP";case 94:return 91;case 95:return 66;case 96:return 75;case 97:return 74;case 98:return 77;case 99:return 76;case 100:return 122;case 101:return 123;case 102:return 68;case 103:return 57;case 104:return 58;case 105:return 40;case 106:return 41;case 107:return 71;case 108:return 72;case 109:return 133;case 110:return 21;case 111:return 22;case 112:return 23}},rules:[/^(?:%%\{)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)[^\n]*)/,/^(?:[^\}]%%[^\n]*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:style\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\b)/,/^(?:class\b)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:click[\s]+)/,/^(?:[\s\n])/,/^(?:[^\s\n]*)/,/^(?:graph\b)/,/^(?:flowchart\b)/,/^(?:subgraph\b)/,/^(?:end\b\s*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:(\r?\n)*\s*\n)/,/^(?:\s*LR\b)/,/^(?:\s*RL\b)/,/^(?:\s*TB\b)/,/^(?:\s*BT\b)/,/^(?:\s*TD\b)/,/^(?:\s*BR\b)/,/^(?:\s*<)/,/^(?:\s*>)/,/^(?:\s*\^)/,/^(?:\s*v\b)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:[0-9]+)/,/^(?:#)/,/^(?::::)/,/^(?::)/,/^(?:&)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:\(-)/,/^(?:-\))/,/^(?:\(\[)/,/^(?:\]\))/,/^(?:\[\[)/,/^(?:\]\])/,/^(?:\[\|)/,/^(?:\[\()/,/^(?:\)\])/,/^(?:\(\(\()/,/^(?:\)\)\))/,/^(?:-)/,/^(?:\.)/,/^(?:[\_])/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:<)/,/^(?:>)/,/^(?:\^)/,/^(?:\\\|)/,/^(?:v\b)/,/^(?:[A-Za-z]+)/,/^(?:\\\])/,/^(?:\[\/)/,/^(?:\/\])/,/^(?:\[\\)/,/^(?:[!"#$%&'*+,-.`?\\_/])/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:")/,/^(?:(\r?\n)+)/,/^(?:\s)/,/^(?:$)/],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[30,31],inclusive:!1},callbackname:{rules:[27,28,29],inclusive:!1},href:{rules:[24,25],inclusive:!1},click:{rules:[33,34],inclusive:!1},vertex:{rules:[],inclusive:!1},dir:{rules:[43,44,45,46,47,48,49,50,51,52,53],inclusive:!1},acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},string:{rules:[15,16],inclusive:!1},INITIAL:{rules:[0,5,6,7,9,11,14,17,18,19,20,21,22,23,26,32,35,36,37,38,39,40,41,42,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112],inclusive:!0}}};function re(){this.yy={};}return ee.lexer=ne,re.prototype=ee,ee.Parser=re,new re}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(5354).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},9959:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[7,9,11,12,13,14,15,16,17,18,19,20,22,24,25,27,34,39],i=[1,15],a=[1,16],o=[1,17],s=[1,18],c=[1,19],l=[1,20],u=[1,21],h=[1,22],f=[1,23],d=[1,24],p=[1,25],g=[1,26],y=[1,28],m=[1,30],b=[1,33],v=[5,7,9,11,12,13,14,15,16,17,18,19,20,22,24,25,27,34,39],_={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,gantt:5,document:6,EOF:7,line:8,SPACE:9,statement:10,NL:11,dateFormat:12,inclusiveEndDates:13,topAxis:14,axisFormat:15,excludes:16,includes:17,todayMarker:18,title:19,acc_title:20,acc_title_value:21,acc_descr:22,acc_descr_value:23,acc_descr_multiline_value:24,section:25,clickStatement:26,taskTxt:27,taskData:28,openDirective:29,typeDirective:30,closeDirective:31,":":32,argDirective:33,click:34,callbackname:35,callbackargs:36,href:37,clickStatementDebug:38,open_directive:39,type_directive:40,arg_directive:41,close_directive:42,$accept:0,$end:1},terminals_:{2:"error",5:"gantt",7:"EOF",9:"SPACE",11:"NL",12:"dateFormat",13:"inclusiveEndDates",14:"topAxis",15:"axisFormat",16:"excludes",17:"includes",18:"todayMarker",19:"title",20:"acc_title",21:"acc_title_value",22:"acc_descr",23:"acc_descr_value",24:"acc_descr_multiline_value",25:"section",27:"taskTxt",28:"taskData",32:":",34:"click",35:"callbackname",36:"callbackargs",37:"href",39:"open_directive",40:"type_directive",41:"arg_directive",42:"close_directive"},productions_:[0,[3,2],[3,3],[6,0],[6,2],[8,2],[8,1],[8,1],[8,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,2],[10,1],[10,1],[10,1],[10,2],[10,1],[4,4],[4,6],[26,2],[26,3],[26,3],[26,4],[26,3],[26,4],[26,2],[38,2],[38,3],[38,3],[38,4],[38,3],[38,4],[38,2],[29,1],[30,1],[33,1],[31,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 2:return a[s-1];case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 9:r.setDateFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 10:r.enableInclusiveEndDates(),this.$=a[s].substr(18);break;case 11:r.TopAxis(),this.$=a[s].substr(8);break;case 12:r.setAxisFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 13:r.setExcludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 14:r.setIncludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 15:r.setTodayMarker(a[s].substr(12)),this.$=a[s].substr(12);break;case 16:r.setDiagramTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 17:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 18:case 19:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 20:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 22:r.addTask(a[s-1],a[s]),this.$="task";break;case 26:this.$=a[s-1],r.setClickEvent(a[s-1],a[s],null);break;case 27:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 28:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],null),r.setLink(a[s-2],a[s]);break;case 29:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setLink(a[s-3],a[s]);break;case 30:this.$=a[s-2],r.setClickEvent(a[s-2],a[s],null),r.setLink(a[s-2],a[s-1]);break;case 31:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-1],a[s]),r.setLink(a[s-3],a[s-2]);break;case 32:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 33:case 39:this.$=a[s-1]+" "+a[s];break;case 34:case 35:case 37:this.$=a[s-2]+" "+a[s-1]+" "+a[s];break;case 36:case 38:this.$=a[s-3]+" "+a[s-2]+" "+a[s-1]+" "+a[s];break;case 40:r.parseDirective("%%{","open_directive");break;case 41:r.parseDirective(a[s],"type_directive");break;case 42:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 43:r.parseDirective("}%%","close_directive","gantt");}},table:[{3:1,4:2,5:e,29:4,39:n},{1:[3]},{3:6,4:2,5:e,29:4,39:n},t(r,[2,3],{6:7}),{30:8,40:[1,9]},{40:[2,40]},{1:[2,1]},{4:29,7:[1,10],8:11,9:[1,12],10:13,11:[1,14],12:i,13:a,14:o,15:s,16:c,17:l,18:u,19:h,20:f,22:d,24:p,25:g,26:27,27:y,29:4,34:m,39:n},{31:31,32:[1,32],42:b},t([32,42],[2,41]),t(r,[2,8],{1:[2,2]}),t(r,[2,4]),{4:29,10:34,12:i,13:a,14:o,15:s,16:c,17:l,18:u,19:h,20:f,22:d,24:p,25:g,26:27,27:y,29:4,34:m,39:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,9]),t(r,[2,10]),t(r,[2,11]),t(r,[2,12]),t(r,[2,13]),t(r,[2,14]),t(r,[2,15]),t(r,[2,16]),{21:[1,35]},{23:[1,36]},t(r,[2,19]),t(r,[2,20]),t(r,[2,21]),{28:[1,37]},t(r,[2,23]),{35:[1,38],37:[1,39]},{11:[1,40]},{33:41,41:[1,42]},{11:[2,43]},t(r,[2,5]),t(r,[2,17]),t(r,[2,18]),t(r,[2,22]),t(r,[2,26],{36:[1,43],37:[1,44]}),t(r,[2,32],{35:[1,45]}),t(v,[2,24]),{31:46,42:b},{42:[2,42]},t(r,[2,27],{37:[1,47]}),t(r,[2,28]),t(r,[2,30],{36:[1,48]}),{11:[1,49]},t(r,[2,29]),t(r,[2,31]),t(v,[2,25])],defaultActions:{5:[2,40],6:[2,1],33:[2,43],42:[2,42]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},x={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),39;case 1:return this.begin("type_directive"),40;case 2:return this.popState(),this.begin("arg_directive"),32;case 3:return this.popState(),this.popState(),42;case 4:return 41;case 5:return this.begin("acc_title"),20;case 6:return this.popState(),"acc_title_value";case 7:return this.begin("acc_descr"),22;case 8:return this.popState(),"acc_descr_value";case 9:this.begin("acc_descr_multiline");break;case 10:case 20:case 23:case 26:case 29:this.popState();break;case 11:return "acc_descr_multiline_value";case 12:case 13:case 14:case 16:case 17:case 18:break;case 15:return 11;case 19:this.begin("href");break;case 21:return 37;case 22:this.begin("callbackname");break;case 24:this.popState(),this.begin("callbackargs");break;case 25:return 35;case 27:return 36;case 28:this.begin("click");break;case 30:return 34;case 31:return 5;case 32:return 12;case 33:return 13;case 34:return 14;case 35:return 15;case 36:return 17;case 37:return 16;case 38:return 18;case 39:return "date";case 40:return 19;case 41:return "accDescription";case 42:return 25;case 43:return 27;case 44:return 28;case 45:return 32;case 46:return 7;case 47:return "INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:topAxis\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:includes\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:accDescription\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[10,11],inclusive:!1},acc_descr:{rules:[8],inclusive:!1},acc_title:{rules:[6],inclusive:!1},close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[26,27],inclusive:!1},callbackname:{rules:[23,24,25],inclusive:!1},href:{rules:[20,21],inclusive:!1},click:{rules:[29,30],inclusive:!1},INITIAL:{rules:[0,5,7,9,12,13,14,15,16,17,18,19,22,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],inclusive:!0}}};function k(){this.yy={};}return _.lexer=x,k.prototype=_,_.Parser=k,new k}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(6878).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},2553:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,4],n=[1,7],r=[1,5],i=[1,9],a=[1,6],o=[2,6],s=[1,16],c=[6,8,14,20,22,24,25,27,29,32,35,39,49,53],l=[8,14,20,22,24,25,27,29,32,35,39],u=[8,13,14,20,22,24,25,27,29,32,35,39],h=[1,26],f=[6,8,14,49,53],d=[8,14,53],p=[1,64],g=[1,65],y=[1,66],m=[8,14,33,38,41,53],b={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,directive:5,GG:6,document:7,EOF:8,":":9,DIR:10,options:11,body:12,OPT:13,NL:14,line:15,statement:16,commitStatement:17,mergeStatement:18,cherryPickStatement:19,acc_title:20,acc_title_value:21,acc_descr:22,acc_descr_value:23,acc_descr_multiline_value:24,section:25,branchStatement:26,CHECKOUT:27,ID:28,BRANCH:29,ORDER:30,NUM:31,CHERRY_PICK:32,COMMIT_ID:33,STR:34,MERGE:35,COMMIT_TYPE:36,commitType:37,COMMIT_TAG:38,COMMIT:39,commit_arg:40,COMMIT_MSG:41,NORMAL:42,REVERSE:43,HIGHLIGHT:44,openDirective:45,typeDirective:46,closeDirective:47,argDirective:48,open_directive:49,type_directive:50,arg_directive:51,close_directive:52,";":53,$accept:0,$end:1},terminals_:{2:"error",6:"GG",8:"EOF",9:":",10:"DIR",13:"OPT",14:"NL",20:"acc_title",21:"acc_title_value",22:"acc_descr",23:"acc_descr_value",24:"acc_descr_multiline_value",25:"section",27:"CHECKOUT",28:"ID",29:"BRANCH",30:"ORDER",31:"NUM",32:"CHERRY_PICK",33:"COMMIT_ID",34:"STR",35:"MERGE",36:"COMMIT_TYPE",38:"COMMIT_TAG",39:"COMMIT",41:"COMMIT_MSG",42:"NORMAL",43:"REVERSE",44:"HIGHLIGHT",49:"open_directive",50:"type_directive",51:"arg_directive",52:"close_directive",53:";"},productions_:[0,[3,2],[3,2],[3,3],[3,4],[3,5],[7,0],[7,2],[11,2],[11,1],[12,0],[12,2],[15,2],[15,1],[16,1],[16,1],[16,1],[16,2],[16,2],[16,1],[16,1],[16,1],[16,2],[26,2],[26,4],[19,3],[18,2],[18,4],[18,4],[18,4],[18,6],[18,6],[18,6],[18,6],[18,6],[18,6],[18,8],[18,8],[18,8],[18,8],[18,8],[18,8],[17,2],[17,3],[17,3],[17,5],[17,5],[17,3],[17,5],[17,5],[17,5],[17,5],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,3],[17,5],[17,5],[17,5],[17,5],[17,5],[17,5],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,7],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[17,9],[40,0],[40,1],[37,1],[37,1],[37,1],[5,3],[5,5],[45,1],[46,1],[48,1],[47,1],[4,1],[4,1],[4,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 3:return a[s];case 4:return a[s-1];case 5:return r.setDirection(a[s-3]),a[s-1];case 7:r.setOptions(a[s-1]),this.$=a[s];break;case 8:a[s-1]+=a[s],this.$=a[s-1];break;case 10:this.$=[];break;case 11:a[s-1].push(a[s]),this.$=a[s-1];break;case 12:this.$=a[s-1];break;case 17:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 18:case 19:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 20:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 22:r.checkout(a[s]);break;case 23:r.branch(a[s]);break;case 24:r.branch(a[s-2],a[s]);break;case 25:r.cherryPick(a[s]);break;case 26:r.merge(a[s],"","","");break;case 27:r.merge(a[s-2],a[s],"","");break;case 28:r.merge(a[s-2],"",a[s],"");break;case 29:r.merge(a[s-2],"","",a[s]);break;case 30:r.merge(a[s-4],a[s],"",a[s-2]);break;case 31:r.merge(a[s-4],"",a[s],a[s-2]);break;case 32:r.merge(a[s-4],"",a[s-2],a[s]);break;case 33:r.merge(a[s-4],a[s-2],a[s],"");break;case 34:r.merge(a[s-4],a[s-2],"",a[s]);break;case 35:r.merge(a[s-4],a[s],a[s-2],"");break;case 36:r.merge(a[s-6],a[s-4],a[s-2],a[s]);break;case 37:r.merge(a[s-6],a[s],a[s-4],a[s-2]);break;case 38:r.merge(a[s-6],a[s-4],a[s],a[s-2]);break;case 39:r.merge(a[s-6],a[s-2],a[s-4],a[s]);break;case 40:r.merge(a[s-6],a[s],a[s-2],a[s-4]);break;case 41:r.merge(a[s-6],a[s-2],a[s],a[s-4]);break;case 42:r.commit(a[s]);break;case 43:r.commit("","",r.commitType.NORMAL,a[s]);break;case 44:r.commit("","",a[s],"");break;case 45:r.commit("","",a[s],a[s-2]);break;case 46:r.commit("","",a[s-2],a[s]);break;case 47:r.commit("",a[s],r.commitType.NORMAL,"");break;case 48:r.commit("",a[s-2],r.commitType.NORMAL,a[s]);break;case 49:r.commit("",a[s],r.commitType.NORMAL,a[s-2]);break;case 50:r.commit("",a[s-2],a[s],"");break;case 51:r.commit("",a[s],a[s-2],"");break;case 52:r.commit("",a[s-4],a[s-2],a[s]);break;case 53:r.commit("",a[s-4],a[s],a[s-2]);break;case 54:r.commit("",a[s-2],a[s-4],a[s]);break;case 55:r.commit("",a[s],a[s-4],a[s-2]);break;case 56:r.commit("",a[s],a[s-2],a[s-4]);break;case 57:r.commit("",a[s-2],a[s],a[s-4]);break;case 58:r.commit(a[s],"",r.commitType.NORMAL,"");break;case 59:r.commit(a[s],"",r.commitType.NORMAL,a[s-2]);break;case 60:r.commit(a[s-2],"",r.commitType.NORMAL,a[s]);break;case 61:r.commit(a[s-2],"",a[s],"");break;case 62:r.commit(a[s],"",a[s-2],"");break;case 63:r.commit(a[s],a[s-2],r.commitType.NORMAL,"");break;case 64:r.commit(a[s-2],a[s],r.commitType.NORMAL,"");break;case 65:r.commit(a[s-4],"",a[s-2],a[s]);break;case 66:r.commit(a[s-4],"",a[s],a[s-2]);break;case 67:r.commit(a[s-2],"",a[s-4],a[s]);break;case 68:r.commit(a[s],"",a[s-4],a[s-2]);break;case 69:r.commit(a[s],"",a[s-2],a[s-4]);break;case 70:r.commit(a[s-2],"",a[s],a[s-4]);break;case 71:r.commit(a[s-4],a[s],a[s-2],"");break;case 72:r.commit(a[s-4],a[s-2],a[s],"");break;case 73:r.commit(a[s-2],a[s],a[s-4],"");break;case 74:r.commit(a[s],a[s-2],a[s-4],"");break;case 75:r.commit(a[s],a[s-4],a[s-2],"");break;case 76:r.commit(a[s-2],a[s-4],a[s],"");break;case 77:r.commit(a[s-4],a[s],r.commitType.NORMAL,a[s-2]);break;case 78:r.commit(a[s-4],a[s-2],r.commitType.NORMAL,a[s]);break;case 79:r.commit(a[s-2],a[s],r.commitType.NORMAL,a[s-4]);break;case 80:r.commit(a[s],a[s-2],r.commitType.NORMAL,a[s-4]);break;case 81:r.commit(a[s],a[s-4],r.commitType.NORMAL,a[s-2]);break;case 82:r.commit(a[s-2],a[s-4],r.commitType.NORMAL,a[s]);break;case 83:r.commit(a[s-6],a[s-4],a[s-2],a[s]);break;case 84:r.commit(a[s-6],a[s-4],a[s],a[s-2]);break;case 85:r.commit(a[s-6],a[s-2],a[s-4],a[s]);break;case 86:r.commit(a[s-6],a[s],a[s-4],a[s-2]);break;case 87:r.commit(a[s-6],a[s-2],a[s],a[s-4]);break;case 88:r.commit(a[s-6],a[s],a[s-2],a[s-4]);break;case 89:r.commit(a[s-4],a[s-6],a[s-2],a[s]);break;case 90:r.commit(a[s-4],a[s-6],a[s],a[s-2]);break;case 91:r.commit(a[s-2],a[s-6],a[s-4],a[s]);break;case 92:r.commit(a[s],a[s-6],a[s-4],a[s-2]);break;case 93:r.commit(a[s-2],a[s-6],a[s],a[s-4]);break;case 94:r.commit(a[s],a[s-6],a[s-2],a[s-4]);break;case 95:r.commit(a[s],a[s-4],a[s-2],a[s-6]);break;case 96:r.commit(a[s-2],a[s-4],a[s],a[s-6]);break;case 97:r.commit(a[s],a[s-2],a[s-4],a[s-6]);break;case 98:r.commit(a[s-2],a[s],a[s-4],a[s-6]);break;case 99:r.commit(a[s-4],a[s-2],a[s],a[s-6]);break;case 100:r.commit(a[s-4],a[s],a[s-2],a[s-6]);break;case 101:r.commit(a[s-2],a[s-4],a[s-6],a[s]);break;case 102:r.commit(a[s],a[s-4],a[s-6],a[s-2]);break;case 103:r.commit(a[s-2],a[s],a[s-6],a[s-4]);break;case 104:r.commit(a[s],a[s-2],a[s-6],a[s-4]);break;case 105:r.commit(a[s-4],a[s-2],a[s-6],a[s]);break;case 106:r.commit(a[s-4],a[s],a[s-6],a[s-2]);break;case 107:this.$="";break;case 108:this.$=a[s];break;case 109:this.$=r.commitType.NORMAL;break;case 110:this.$=r.commitType.REVERSE;break;case 111:this.$=r.commitType.HIGHLIGHT;break;case 114:r.parseDirective("%%{","open_directive");break;case 115:r.parseDirective(a[s],"type_directive");break;case 116:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 117:r.parseDirective("}%%","close_directive","gitGraph");}},table:[{3:1,4:2,5:3,6:e,8:n,14:r,45:8,49:i,53:a},{1:[3]},{3:10,4:2,5:3,6:e,8:n,14:r,45:8,49:i,53:a},{3:11,4:2,5:3,6:e,8:n,14:r,45:8,49:i,53:a},{7:12,8:o,9:[1,13],10:[1,14],11:15,14:s},t(c,[2,118]),t(c,[2,119]),t(c,[2,120]),{46:17,50:[1,18]},{50:[2,114]},{1:[2,1]},{1:[2,2]},{8:[1,19]},{7:20,8:o,11:15,14:s},{9:[1,21]},t(l,[2,10],{12:22,13:[1,23]}),t(u,[2,9]),{9:[1,25],47:24,52:h},t([9,52],[2,115]),{1:[2,3]},{8:[1,27]},{7:28,8:o,11:15,14:s},{8:[2,7],14:[1,31],15:29,16:30,17:32,18:33,19:34,20:[1,35],22:[1,36],24:[1,37],25:[1,38],26:39,27:[1,40],29:[1,44],32:[1,43],35:[1,42],39:[1,41]},t(u,[2,8]),t(f,[2,112]),{48:45,51:[1,46]},t(f,[2,117]),{1:[2,4]},{8:[1,47]},t(l,[2,11]),{4:48,8:n,14:r,53:a},t(l,[2,13]),t(d,[2,14]),t(d,[2,15]),t(d,[2,16]),{21:[1,49]},{23:[1,50]},t(d,[2,19]),t(d,[2,20]),t(d,[2,21]),{28:[1,51]},t(d,[2,107],{40:52,33:[1,55],34:[1,57],36:[1,54],38:[1,53],41:[1,56]}),{28:[1,58]},{33:[1,59]},{28:[1,60]},{47:61,52:h},{52:[2,116]},{1:[2,5]},t(l,[2,12]),t(d,[2,17]),t(d,[2,18]),t(d,[2,22]),t(d,[2,42]),{34:[1,62]},{37:63,42:p,43:g,44:y},{34:[1,67]},{34:[1,68]},t(d,[2,108]),t(d,[2,26],{33:[1,69],36:[1,70],38:[1,71]}),{34:[1,72]},t(d,[2,23],{30:[1,73]}),t(f,[2,113]),t(d,[2,43],{33:[1,75],36:[1,74],41:[1,76]}),t(d,[2,44],{33:[1,78],38:[1,77],41:[1,79]}),t(m,[2,109]),t(m,[2,110]),t(m,[2,111]),t(d,[2,47],{36:[1,81],38:[1,80],41:[1,82]}),t(d,[2,58],{33:[1,85],36:[1,84],38:[1,83]}),{34:[1,86]},{37:87,42:p,43:g,44:y},{34:[1,88]},t(d,[2,25]),{31:[1,89]},{37:90,42:p,43:g,44:y},{34:[1,91]},{34:[1,92]},{34:[1,93]},{34:[1,94]},{34:[1,95]},{34:[1,96]},{37:97,42:p,43:g,44:y},{34:[1,98]},{34:[1,99]},{37:100,42:p,43:g,44:y},{34:[1,101]},t(d,[2,27],{36:[1,102],38:[1,103]}),t(d,[2,28],{33:[1,105],38:[1,104]}),t(d,[2,29],{33:[1,106],36:[1,107]}),t(d,[2,24]),t(d,[2,45],{33:[1,108],41:[1,109]}),t(d,[2,49],{36:[1,110],41:[1,111]}),t(d,[2,59],{33:[1,113],36:[1,112]}),t(d,[2,46],{33:[1,114],41:[1,115]}),t(d,[2,51],{38:[1,116],41:[1,117]}),t(d,[2,62],{33:[1,119],38:[1,118]}),t(d,[2,48],{36:[1,120],41:[1,121]}),t(d,[2,50],{38:[1,122],41:[1,123]}),t(d,[2,63],{36:[1,124],38:[1,125]}),t(d,[2,60],{33:[1,127],36:[1,126]}),t(d,[2,61],{33:[1,129],38:[1,128]}),t(d,[2,64],{36:[1,130],38:[1,131]}),{37:132,42:p,43:g,44:y},{34:[1,133]},{34:[1,134]},{34:[1,135]},{34:[1,136]},{37:137,42:p,43:g,44:y},{34:[1,138]},{34:[1,139]},{37:140,42:p,43:g,44:y},{34:[1,141]},{37:142,42:p,43:g,44:y},{34:[1,143]},{34:[1,144]},{34:[1,145]},{34:[1,146]},{34:[1,147]},{34:[1,148]},{34:[1,149]},{37:150,42:p,43:g,44:y},{34:[1,151]},{34:[1,152]},{34:[1,153]},{37:154,42:p,43:g,44:y},{34:[1,155]},{37:156,42:p,43:g,44:y},{34:[1,157]},{34:[1,158]},{34:[1,159]},{37:160,42:p,43:g,44:y},{34:[1,161]},t(d,[2,33],{38:[1,162]}),t(d,[2,34],{36:[1,163]}),t(d,[2,32],{33:[1,164]}),t(d,[2,35],{38:[1,165]}),t(d,[2,30],{36:[1,166]}),t(d,[2,31],{33:[1,167]}),t(d,[2,56],{41:[1,168]}),t(d,[2,69],{33:[1,169]}),t(d,[2,57],{41:[1,170]}),t(d,[2,80],{36:[1,171]}),t(d,[2,70],{33:[1,172]}),t(d,[2,79],{36:[1,173]}),t(d,[2,55],{41:[1,174]}),t(d,[2,68],{33:[1,175]}),t(d,[2,54],{41:[1,176]}),t(d,[2,74],{38:[1,177]}),t(d,[2,67],{33:[1,178]}),t(d,[2,73],{38:[1,179]}),t(d,[2,53],{41:[1,180]}),t(d,[2,81],{36:[1,181]}),t(d,[2,52],{41:[1,182]}),t(d,[2,75],{38:[1,183]}),t(d,[2,76],{38:[1,184]}),t(d,[2,82],{36:[1,185]}),t(d,[2,66],{33:[1,186]}),t(d,[2,77],{36:[1,187]}),t(d,[2,65],{33:[1,188]}),t(d,[2,71],{38:[1,189]}),t(d,[2,72],{38:[1,190]}),t(d,[2,78],{36:[1,191]}),{34:[1,192]},{37:193,42:p,43:g,44:y},{34:[1,194]},{34:[1,195]},{37:196,42:p,43:g,44:y},{34:[1,197]},{34:[1,198]},{34:[1,199]},{34:[1,200]},{37:201,42:p,43:g,44:y},{34:[1,202]},{37:203,42:p,43:g,44:y},{34:[1,204]},{34:[1,205]},{34:[1,206]},{34:[1,207]},{34:[1,208]},{34:[1,209]},{34:[1,210]},{37:211,42:p,43:g,44:y},{34:[1,212]},{34:[1,213]},{34:[1,214]},{37:215,42:p,43:g,44:y},{34:[1,216]},{37:217,42:p,43:g,44:y},{34:[1,218]},{34:[1,219]},{34:[1,220]},{37:221,42:p,43:g,44:y},t(d,[2,36]),t(d,[2,38]),t(d,[2,37]),t(d,[2,39]),t(d,[2,41]),t(d,[2,40]),t(d,[2,97]),t(d,[2,98]),t(d,[2,95]),t(d,[2,96]),t(d,[2,100]),t(d,[2,99]),t(d,[2,104]),t(d,[2,103]),t(d,[2,102]),t(d,[2,101]),t(d,[2,106]),t(d,[2,105]),t(d,[2,94]),t(d,[2,93]),t(d,[2,92]),t(d,[2,91]),t(d,[2,89]),t(d,[2,90]),t(d,[2,88]),t(d,[2,87]),t(d,[2,86]),t(d,[2,85]),t(d,[2,83]),t(d,[2,84])],defaultActions:{9:[2,114],10:[2,1],11:[2,2],19:[2,3],27:[2,4],46:[2,116],47:[2,5]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},v={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),49;case 1:return this.begin("type_directive"),50;case 2:return this.popState(),this.begin("arg_directive"),9;case 3:return this.popState(),this.popState(),52;case 4:return 51;case 5:return this.begin("acc_title"),20;case 6:return this.popState(),"acc_title_value";case 7:return this.begin("acc_descr"),22;case 8:return this.popState(),"acc_descr_value";case 9:this.begin("acc_descr_multiline");break;case 10:case 35:case 38:this.popState();break;case 11:return "acc_descr_multiline_value";case 12:return 14;case 13:case 14:case 15:break;case 16:return 6;case 17:return 39;case 18:return 33;case 19:return 36;case 20:return 41;case 21:return 42;case 22:return 43;case 23:return 44;case 24:return 38;case 25:return 29;case 26:return 30;case 27:return 35;case 28:return 32;case 29:return 27;case 30:case 31:return 10;case 32:return 9;case 33:return "CARET";case 34:this.begin("options");break;case 36:return 13;case 37:this.begin("string");break;case 39:return 34;case 40:return 31;case 41:return 28;case 42:return 8}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:gitGraph\b)/i,/^(?:commit\b)/i,/^(?:id:)/i,/^(?:type:)/i,/^(?:msg:)/i,/^(?:NORMAL\b)/i,/^(?:REVERSE\b)/i,/^(?:HIGHLIGHT\b)/i,/^(?:tag:)/i,/^(?:branch\b)/i,/^(?:order:)/i,/^(?:merge\b)/i,/^(?:cherry-pick\b)/i,/^(?:checkout\b)/i,/^(?:LR\b)/i,/^(?:BT\b)/i,/^(?::)/i,/^(?:\^)/i,/^(?:options\r?\n)/i,/^(?:[ \r\n\t]+end\b)/i,/^(?:[\s\S]+(?=[ \r\n\t]+end))/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[0-9]+)/i,/^(?:[a-zA-Z][-_\./a-zA-Z0-9]*[-_a-zA-Z0-9])/i,/^(?:$)/i],conditions:{acc_descr_multiline:{rules:[10,11],inclusive:!1},acc_descr:{rules:[8],inclusive:!1},acc_title:{rules:[6],inclusive:!1},close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},options:{rules:[35,36],inclusive:!1},string:{rules:[38,39],inclusive:!1},INITIAL:{rules:[0,5,7,9,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,37,40,41,42],inclusive:!0}}};function _(){this.yy={};}return b.lexer=v,_.prototype=b,b.Parser=_,new _}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8183).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},6765:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[6,9,10],n={trace:function(){},yy:{},symbols_:{error:2,start:3,info:4,document:5,EOF:6,line:7,statement:8,NL:9,showInfo:10,$accept:0,$end:1},terminals_:{2:"error",4:"info",6:"EOF",9:"NL",10:"showInfo"},productions_:[0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,1]],performAction:function(t,e,n,r,i,a,o){switch(a.length,i){case 1:return r;case 4:break;case 6:r.setInfo(!0);}},table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8]},{1:[2,1]},t(e,[2,3]),t(e,[2,4]),t(e,[2,5]),t(e,[2,6])],defaultActions:{4:[2,1]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},r={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 4;case 1:return 9;case 2:return "space";case 3:return 10;case 4:return 6;case 5:return "TXT"}},rules:[/^(?:info\b)/i,/^(?:[\s\n\r]+)/i,/^(?:[\s]+)/i,/^(?:showInfo\b)/i,/^(?:$)/i,/^(?:.)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5],inclusive:!0}}};function i(){this.yy={};}return n.lexer=r,i.prototype=n,n.Parser=i,new i}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(1428).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},7062:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,4],n=[1,5],r=[1,6],i=[1,7],a=[1,9],o=[1,11,13,15,17,19,20,26,27,28,29],s=[2,5],c=[1,6,11,13,15,17,19,20,26,27,28,29],l=[26,27,28],u=[2,8],h=[1,18],f=[1,19],d=[1,20],p=[1,21],g=[1,22],y=[1,23],m=[1,28],b=[6,26,27,28,29],v={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,directive:5,PIE:6,document:7,showData:8,line:9,statement:10,txt:11,value:12,title:13,title_value:14,acc_title:15,acc_title_value:16,acc_descr:17,acc_descr_value:18,acc_descr_multiline_value:19,section:20,openDirective:21,typeDirective:22,closeDirective:23,":":24,argDirective:25,NEWLINE:26,";":27,EOF:28,open_directive:29,type_directive:30,arg_directive:31,close_directive:32,$accept:0,$end:1},terminals_:{2:"error",6:"PIE",8:"showData",11:"txt",12:"value",13:"title",14:"title_value",15:"acc_title",16:"acc_title_value",17:"acc_descr",18:"acc_descr_value",19:"acc_descr_multiline_value",20:"section",24:":",26:"NEWLINE",27:";",28:"EOF",29:"open_directive",30:"type_directive",31:"arg_directive",32:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,3],[7,0],[7,2],[9,2],[10,0],[10,2],[10,2],[10,2],[10,2],[10,1],[10,1],[10,1],[5,3],[5,5],[4,1],[4,1],[4,1],[21,1],[22,1],[25,1],[23,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:r.setShowData(!0);break;case 7:this.$=a[s-1];break;case 9:r.addSection(a[s-1],r.cleanupValue(a[s]));break;case 10:this.$=a[s].trim(),r.setDiagramTitle(this.$);break;case 11:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 12:case 13:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 14:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 21:r.parseDirective("%%{","open_directive");break;case 22:r.parseDirective(a[s],"type_directive");break;case 23:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 24:r.parseDirective("}%%","close_directive","pie");}},table:[{3:1,4:2,5:3,6:e,21:8,26:n,27:r,28:i,29:a},{1:[3]},{3:10,4:2,5:3,6:e,21:8,26:n,27:r,28:i,29:a},{3:11,4:2,5:3,6:e,21:8,26:n,27:r,28:i,29:a},t(o,s,{7:12,8:[1,13]}),t(c,[2,18]),t(c,[2,19]),t(c,[2,20]),{22:14,30:[1,15]},{30:[2,21]},{1:[2,1]},{1:[2,2]},t(l,u,{21:8,9:16,10:17,5:24,1:[2,3],11:h,13:f,15:d,17:p,19:g,20:y,29:a}),t(o,s,{7:25}),{23:26,24:[1,27],32:m},t([24,32],[2,22]),t(o,[2,6]),{4:29,26:n,27:r,28:i},{12:[1,30]},{14:[1,31]},{16:[1,32]},{18:[1,33]},t(l,[2,13]),t(l,[2,14]),t(l,[2,15]),t(l,u,{21:8,9:16,10:17,5:24,1:[2,4],11:h,13:f,15:d,17:p,19:g,20:y,29:a}),t(b,[2,16]),{25:34,31:[1,35]},t(b,[2,24]),t(o,[2,7]),t(l,[2,9]),t(l,[2,10]),t(l,[2,11]),t(l,[2,12]),{23:36,32:m},{32:[2,23]},t(b,[2,17])],defaultActions:{9:[2,21],10:[2,1],11:[2,2],35:[2,23]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},_={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),29;case 1:return this.begin("type_directive"),30;case 2:return this.popState(),this.begin("arg_directive"),24;case 3:return this.popState(),this.popState(),32;case 4:return 31;case 5:case 6:case 8:case 9:break;case 7:return 26;case 10:return this.begin("title"),13;case 11:return this.popState(),"title_value";case 12:return this.begin("acc_title"),15;case 13:return this.popState(),"acc_title_value";case 14:return this.begin("acc_descr"),17;case 15:return this.popState(),"acc_descr_value";case 16:this.begin("acc_descr_multiline");break;case 17:case 20:this.popState();break;case 18:return "acc_descr_multiline_value";case 19:this.begin("string");break;case 21:return "txt";case 22:return 6;case 23:return 8;case 24:return "value";case 25:return 28}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:[\s]+)/i,/^(?:title\b)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:pie\b)/i,/^(?:showData\b)/i,/^(?::[\s]*[\d]+(?:\.[\d]+)?)/i,/^(?:$)/i],conditions:{acc_descr_multiline:{rules:[17,18],inclusive:!1},acc_descr:{rules:[15],inclusive:!1},acc_title:{rules:[13],inclusive:!1},close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},title:{rules:[11],inclusive:!1},string:{rules:[20,21],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,12,14,16,19,22,23,24,25],inclusive:!0}}};function x(){this.yy={};}return v.lexer=_,x.prototype=v,v.Parser=x,new x}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(4551).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},3176:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[1,6],i=[1,7],a=[1,8],o=[5,6,8,14,16,18,19,40,41,42,43,44,45,53,71,72],s=[1,22],c=[2,13],l=[1,26],u=[1,27],h=[1,28],f=[1,29],d=[1,30],p=[1,31],g=[1,24],y=[1,32],m=[1,33],b=[1,36],v=[71,72],_=[5,8,14,16,18,19,40,41,42,43,44,45,53,60,62,71,72],x=[1,56],k=[1,57],w=[1,58],T=[1,59],E=[1,60],C=[1,61],S=[1,62],A=[62,63],M=[1,74],N=[1,70],O=[1,71],D=[1,72],B=[1,73],L=[1,75],I=[1,79],F=[1,80],R=[1,77],P=[1,78],j=[5,8,14,16,18,19,40,41,42,43,44,45,53,71,72],z={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,openDirective:9,typeDirective:10,closeDirective:11,":":12,argDirective:13,acc_title:14,acc_title_value:15,acc_descr:16,acc_descr_value:17,acc_descr_multiline_value:18,open_directive:19,type_directive:20,arg_directive:21,close_directive:22,requirementDef:23,elementDef:24,relationshipDef:25,requirementType:26,requirementName:27,STRUCT_START:28,requirementBody:29,ID:30,COLONSEP:31,id:32,TEXT:33,text:34,RISK:35,riskLevel:36,VERIFYMTHD:37,verifyType:38,STRUCT_STOP:39,REQUIREMENT:40,FUNCTIONAL_REQUIREMENT:41,INTERFACE_REQUIREMENT:42,PERFORMANCE_REQUIREMENT:43,PHYSICAL_REQUIREMENT:44,DESIGN_CONSTRAINT:45,LOW_RISK:46,MED_RISK:47,HIGH_RISK:48,VERIFY_ANALYSIS:49,VERIFY_DEMONSTRATION:50,VERIFY_INSPECTION:51,VERIFY_TEST:52,ELEMENT:53,elementName:54,elementBody:55,TYPE:56,type:57,DOCREF:58,ref:59,END_ARROW_L:60,relationship:61,LINE:62,END_ARROW_R:63,CONTAINS:64,COPIES:65,DERIVES:66,SATISFIES:67,VERIFIES:68,REFINES:69,TRACES:70,unqString:71,qString:72,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",12:":",14:"acc_title",15:"acc_title_value",16:"acc_descr",17:"acc_descr_value",18:"acc_descr_multiline_value",19:"open_directive",20:"type_directive",21:"arg_directive",22:"close_directive",28:"STRUCT_START",30:"ID",31:"COLONSEP",33:"TEXT",35:"RISK",37:"VERIFYMTHD",39:"STRUCT_STOP",40:"REQUIREMENT",41:"FUNCTIONAL_REQUIREMENT",42:"INTERFACE_REQUIREMENT",43:"PERFORMANCE_REQUIREMENT",44:"PHYSICAL_REQUIREMENT",45:"DESIGN_CONSTRAINT",46:"LOW_RISK",47:"MED_RISK",48:"HIGH_RISK",49:"VERIFY_ANALYSIS",50:"VERIFY_DEMONSTRATION",51:"VERIFY_INSPECTION",52:"VERIFY_TEST",53:"ELEMENT",56:"TYPE",58:"DOCREF",60:"END_ARROW_L",62:"LINE",63:"END_ARROW_R",64:"CONTAINS",65:"COPIES",66:"DERIVES",67:"SATISFIES",68:"VERIFIES",69:"REFINES",70:"TRACES",71:"unqString",72:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,3],[4,5],[4,2],[4,2],[4,1],[9,1],[10,1],[13,1],[11,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[23,5],[29,5],[29,5],[29,5],[29,5],[29,2],[29,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[36,1],[36,1],[36,1],[38,1],[38,1],[38,1],[38,1],[24,5],[55,5],[55,5],[55,2],[55,1],[25,5],[25,5],[61,1],[61,1],[61,1],[61,1],[61,1],[61,1],[61,1],[27,1],[27,1],[32,1],[32,1],[34,1],[34,1],[54,1],[54,1],[57,1],[57,1],[59,1],[59,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 6:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 7:case 8:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 9:r.parseDirective("%%{","open_directive");break;case 10:r.parseDirective(a[s],"type_directive");break;case 11:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 12:r.parseDirective("}%%","close_directive","pie");break;case 13:this.$=[];break;case 19:r.addRequirement(a[s-3],a[s-4]);break;case 20:r.setNewReqId(a[s-2]);break;case 21:r.setNewReqText(a[s-2]);break;case 22:r.setNewReqRisk(a[s-2]);break;case 23:r.setNewReqVerifyMethod(a[s-2]);break;case 26:this.$=r.RequirementType.REQUIREMENT;break;case 27:this.$=r.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 28:this.$=r.RequirementType.INTERFACE_REQUIREMENT;break;case 29:this.$=r.RequirementType.PERFORMANCE_REQUIREMENT;break;case 30:this.$=r.RequirementType.PHYSICAL_REQUIREMENT;break;case 31:this.$=r.RequirementType.DESIGN_CONSTRAINT;break;case 32:this.$=r.RiskLevel.LOW_RISK;break;case 33:this.$=r.RiskLevel.MED_RISK;break;case 34:this.$=r.RiskLevel.HIGH_RISK;break;case 35:this.$=r.VerifyType.VERIFY_ANALYSIS;break;case 36:this.$=r.VerifyType.VERIFY_DEMONSTRATION;break;case 37:this.$=r.VerifyType.VERIFY_INSPECTION;break;case 38:this.$=r.VerifyType.VERIFY_TEST;break;case 39:r.addElement(a[s-3]);break;case 40:r.setNewElementType(a[s-2]);break;case 41:r.setNewElementDocRef(a[s-2]);break;case 44:r.addRelationship(a[s-2],a[s],a[s-4]);break;case 45:r.addRelationship(a[s-2],a[s-4],a[s]);break;case 46:this.$=r.Relationships.CONTAINS;break;case 47:this.$=r.Relationships.COPIES;break;case 48:this.$=r.Relationships.DERIVES;break;case 49:this.$=r.Relationships.SATISFIES;break;case 50:this.$=r.Relationships.VERIFIES;break;case 51:this.$=r.Relationships.REFINES;break;case 52:this.$=r.Relationships.TRACES;}},table:[{3:1,4:2,6:e,9:4,14:n,16:r,18:i,19:a},{1:[3]},{3:10,4:2,5:[1,9],6:e,9:4,14:n,16:r,18:i,19:a},{5:[1,11]},{10:12,20:[1,13]},{15:[1,14]},{17:[1,15]},t(o,[2,8]),{20:[2,9]},{3:16,4:2,6:e,9:4,14:n,16:r,18:i,19:a},{1:[2,2]},{4:21,5:s,7:17,8:c,9:4,14:n,16:r,18:i,19:a,23:18,24:19,25:20,26:23,32:25,40:l,41:u,42:h,43:f,44:d,45:p,53:g,71:y,72:m},{11:34,12:[1,35],22:b},t([12,22],[2,10]),t(o,[2,6]),t(o,[2,7]),{1:[2,1]},{8:[1,37]},{4:21,5:s,7:38,8:c,9:4,14:n,16:r,18:i,19:a,23:18,24:19,25:20,26:23,32:25,40:l,41:u,42:h,43:f,44:d,45:p,53:g,71:y,72:m},{4:21,5:s,7:39,8:c,9:4,14:n,16:r,18:i,19:a,23:18,24:19,25:20,26:23,32:25,40:l,41:u,42:h,43:f,44:d,45:p,53:g,71:y,72:m},{4:21,5:s,7:40,8:c,9:4,14:n,16:r,18:i,19:a,23:18,24:19,25:20,26:23,32:25,40:l,41:u,42:h,43:f,44:d,45:p,53:g,71:y,72:m},{4:21,5:s,7:41,8:c,9:4,14:n,16:r,18:i,19:a,23:18,24:19,25:20,26:23,32:25,40:l,41:u,42:h,43:f,44:d,45:p,53:g,71:y,72:m},{4:21,5:s,7:42,8:c,9:4,14:n,16:r,18:i,19:a,23:18,24:19,25:20,26:23,32:25,40:l,41:u,42:h,43:f,44:d,45:p,53:g,71:y,72:m},{27:43,71:[1,44],72:[1,45]},{54:46,71:[1,47],72:[1,48]},{60:[1,49],62:[1,50]},t(v,[2,26]),t(v,[2,27]),t(v,[2,28]),t(v,[2,29]),t(v,[2,30]),t(v,[2,31]),t(_,[2,55]),t(_,[2,56]),t(o,[2,4]),{13:51,21:[1,52]},t(o,[2,12]),{1:[2,3]},{8:[2,14]},{8:[2,15]},{8:[2,16]},{8:[2,17]},{8:[2,18]},{28:[1,53]},{28:[2,53]},{28:[2,54]},{28:[1,54]},{28:[2,59]},{28:[2,60]},{61:55,64:x,65:k,66:w,67:T,68:E,69:C,70:S},{61:63,64:x,65:k,66:w,67:T,68:E,69:C,70:S},{11:64,22:b},{22:[2,11]},{5:[1,65]},{5:[1,66]},{62:[1,67]},t(A,[2,46]),t(A,[2,47]),t(A,[2,48]),t(A,[2,49]),t(A,[2,50]),t(A,[2,51]),t(A,[2,52]),{63:[1,68]},t(o,[2,5]),{5:M,29:69,30:N,33:O,35:D,37:B,39:L},{5:I,39:F,55:76,56:R,58:P},{32:81,71:y,72:m},{32:82,71:y,72:m},t(j,[2,19]),{31:[1,83]},{31:[1,84]},{31:[1,85]},{31:[1,86]},{5:M,29:87,30:N,33:O,35:D,37:B,39:L},t(j,[2,25]),t(j,[2,39]),{31:[1,88]},{31:[1,89]},{5:I,39:F,55:90,56:R,58:P},t(j,[2,43]),t(j,[2,44]),t(j,[2,45]),{32:91,71:y,72:m},{34:92,71:[1,93],72:[1,94]},{36:95,46:[1,96],47:[1,97],48:[1,98]},{38:99,49:[1,100],50:[1,101],51:[1,102],52:[1,103]},t(j,[2,24]),{57:104,71:[1,105],72:[1,106]},{59:107,71:[1,108],72:[1,109]},t(j,[2,42]),{5:[1,110]},{5:[1,111]},{5:[2,57]},{5:[2,58]},{5:[1,112]},{5:[2,32]},{5:[2,33]},{5:[2,34]},{5:[1,113]},{5:[2,35]},{5:[2,36]},{5:[2,37]},{5:[2,38]},{5:[1,114]},{5:[2,61]},{5:[2,62]},{5:[1,115]},{5:[2,63]},{5:[2,64]},{5:M,29:116,30:N,33:O,35:D,37:B,39:L},{5:M,29:117,30:N,33:O,35:D,37:B,39:L},{5:M,29:118,30:N,33:O,35:D,37:B,39:L},{5:M,29:119,30:N,33:O,35:D,37:B,39:L},{5:I,39:F,55:120,56:R,58:P},{5:I,39:F,55:121,56:R,58:P},t(j,[2,20]),t(j,[2,21]),t(j,[2,22]),t(j,[2,23]),t(j,[2,40]),t(j,[2,41])],defaultActions:{8:[2,9],10:[2,2],16:[2,1],37:[2,3],38:[2,14],39:[2,15],40:[2,16],41:[2,17],42:[2,18],44:[2,53],45:[2,54],47:[2,59],48:[2,60],52:[2,11],93:[2,57],94:[2,58],96:[2,32],97:[2,33],98:[2,34],100:[2,35],101:[2,36],102:[2,37],103:[2,38],105:[2,61],106:[2,62],108:[2,63],109:[2,64]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},Y={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),19;case 1:return this.begin("type_directive"),20;case 2:return this.popState(),this.begin("arg_directive"),12;case 3:return this.popState(),this.popState(),22;case 4:return 21;case 5:return "title";case 6:return this.begin("acc_title"),14;case 7:return this.popState(),"acc_title_value";case 8:return this.begin("acc_descr"),16;case 9:return this.popState(),"acc_descr_value";case 10:this.begin("acc_descr_multiline");break;case 11:case 53:this.popState();break;case 12:return "acc_descr_multiline_value";case 13:return 5;case 14:case 15:case 16:break;case 17:return 8;case 18:return 6;case 19:return 28;case 20:return 39;case 21:return 31;case 22:return 30;case 23:return 33;case 24:return 35;case 25:return 37;case 26:return 40;case 27:return 41;case 28:return 42;case 29:return 43;case 30:return 44;case 31:return 45;case 32:return 46;case 33:return 47;case 34:return 48;case 35:return 49;case 36:return 50;case 37:return 51;case 38:return 52;case 39:return 53;case 40:return 64;case 41:return 65;case 42:return 66;case 43:return 67;case 44:return 68;case 45:return 69;case 46:return 70;case 47:return 56;case 48:return 58;case 49:return 60;case 50:return 63;case 51:return 62;case 52:this.begin("string");break;case 54:return "qString";case 55:return e.yytext=e.yytext.trim(),71}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:$)/i,/^(?:requirementDiagram\b)/i,/^(?:\{)/i,/^(?:\})/i,/^(?::)/i,/^(?:id\b)/i,/^(?:text\b)/i,/^(?:risk\b)/i,/^(?:verifyMethod\b)/i,/^(?:requirement\b)/i,/^(?:functionalRequirement\b)/i,/^(?:interfaceRequirement\b)/i,/^(?:performanceRequirement\b)/i,/^(?:physicalRequirement\b)/i,/^(?:designConstraint\b)/i,/^(?:low\b)/i,/^(?:medium\b)/i,/^(?:high\b)/i,/^(?:analysis\b)/i,/^(?:demonstration\b)/i,/^(?:inspection\b)/i,/^(?:test\b)/i,/^(?:element\b)/i,/^(?:contains\b)/i,/^(?:copies\b)/i,/^(?:derives\b)/i,/^(?:satisfies\b)/i,/^(?:verifies\b)/i,/^(?:refines\b)/i,/^(?:traces\b)/i,/^(?:type\b)/i,/^(?:docref\b)/i,/^(?:<-)/i,/^(?:->)/i,/^(?:-)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[\w][^\r\n\{\<\>\-\=]*)/i],conditions:{acc_descr_multiline:{rules:[11,12],inclusive:!1},acc_descr:{rules:[9],inclusive:!1},acc_title:{rules:[7],inclusive:!1},close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},unqString:{rules:[],inclusive:!1},token:{rules:[],inclusive:!1},string:{rules:[53,54],inclusive:!1},INITIAL:{rules:[0,5,6,8,10,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,55],inclusive:!0}}};function U(){this.yy={};}return z.lexer=Y,U.prototype=z,z.Parser=U,new U}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8800).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},6876:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,18],l=[1,19],u=[1,21],h=[1,22],f=[1,23],d=[1,29],p=[1,30],g=[1,31],y=[1,32],m=[1,33],b=[1,34],v=[1,35],_=[1,36],x=[1,37],k=[1,38],w=[1,39],T=[1,40],E=[1,43],C=[1,44],S=[1,45],A=[1,46],M=[1,47],N=[1,48],O=[1,51],D=[1,4,5,16,20,22,25,26,32,33,34,36,38,39,40,41,42,43,45,47,49,50,51,52,53,58,59,60,61,69,79],B=[4,5,16,20,22,25,26,32,33,34,36,38,39,40,41,42,43,45,47,49,53,58,59,60,61,69,79],L=[4,5,16,20,22,25,26,32,33,34,36,38,39,40,41,42,43,45,47,49,52,53,58,59,60,61,69,79],I=[4,5,16,20,22,25,26,32,33,34,36,38,39,40,41,42,43,45,47,49,51,53,58,59,60,61,69,79],F=[4,5,16,20,22,25,26,32,33,34,36,38,39,40,41,42,43,45,47,49,50,53,58,59,60,61,69,79],R=[67,68,69],P=[1,121],j=[1,4,5,7,16,20,22,25,26,32,33,34,36,38,39,40,41,42,43,45,47,49,50,51,52,53,58,59,60,61,69,79],z={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,directive:6,SD:7,document:8,line:9,statement:10,openDirective:11,typeDirective:12,closeDirective:13,":":14,argDirective:15,participant:16,actor:17,AS:18,restOfLine:19,participant_actor:20,signal:21,autonumber:22,NUM:23,off:24,activate:25,deactivate:26,note_statement:27,links_statement:28,link_statement:29,properties_statement:30,details_statement:31,title:32,legacy_title:33,acc_title:34,acc_title_value:35,acc_descr:36,acc_descr_value:37,acc_descr_multiline_value:38,loop:39,end:40,rect:41,opt:42,alt:43,else_sections:44,par:45,par_sections:46,critical:47,option_sections:48,break:49,option:50,and:51,else:52,note:53,placement:54,text2:55,over:56,actor_pair:57,links:58,link:59,properties:60,details:61,spaceList:62,",":63,left_of:64,right_of:65,signaltype:66,"+":67,"-":68,ACTOR:69,SOLID_OPEN_ARROW:70,DOTTED_OPEN_ARROW:71,SOLID_ARROW:72,DOTTED_ARROW:73,SOLID_CROSS:74,DOTTED_CROSS:75,SOLID_POINT:76,DOTTED_POINT:77,TXT:78,open_directive:79,type_directive:80,arg_directive:81,close_directive:82,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",7:"SD",14:":",16:"participant",18:"AS",19:"restOfLine",20:"participant_actor",22:"autonumber",23:"NUM",24:"off",25:"activate",26:"deactivate",32:"title",33:"legacy_title",34:"acc_title",35:"acc_title_value",36:"acc_descr",37:"acc_descr_value",38:"acc_descr_multiline_value",39:"loop",40:"end",41:"rect",42:"opt",43:"alt",45:"par",47:"critical",49:"break",50:"option",51:"and",52:"else",53:"note",56:"over",58:"links",59:"link",60:"properties",61:"details",63:",",64:"left_of",65:"right_of",67:"+",68:"-",69:"ACTOR",70:"SOLID_OPEN_ARROW",71:"DOTTED_OPEN_ARROW",72:"SOLID_ARROW",73:"DOTTED_ARROW",74:"SOLID_CROSS",75:"DOTTED_CROSS",76:"SOLID_POINT",77:"DOTTED_POINT",78:"TXT",79:"open_directive",80:"type_directive",81:"arg_directive",82:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[6,4],[6,6],[10,5],[10,3],[10,5],[10,3],[10,2],[10,4],[10,3],[10,3],[10,2],[10,3],[10,3],[10,2],[10,2],[10,2],[10,2],[10,2],[10,1],[10,1],[10,2],[10,2],[10,1],[10,4],[10,4],[10,4],[10,4],[10,4],[10,4],[10,4],[10,1],[48,1],[48,4],[46,1],[46,4],[44,1],[44,4],[27,4],[27,4],[28,3],[29,3],[30,3],[31,3],[62,2],[62,1],[57,3],[57,1],[54,1],[54,1],[21,5],[21,5],[21,4],[17,1],[66,1],[66,1],[66,1],[66,1],[66,1],[66,1],[66,1],[66,1],[55,1],[11,1],[12,1],[15,1],[13,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.apply(a[s]),a[s];case 5:case 9:this.$=[];break;case 6:a[s-1].push(a[s]),this.$=a[s-1];break;case 7:case 8:case 56:this.$=a[s];break;case 12:a[s-3].type="addParticipant",a[s-3].description=r.parseMessage(a[s-1]),this.$=a[s-3];break;case 13:a[s-1].type="addParticipant",this.$=a[s-1];break;case 14:a[s-3].type="addActor",a[s-3].description=r.parseMessage(a[s-1]),this.$=a[s-3];break;case 15:a[s-1].type="addActor",this.$=a[s-1];break;case 17:this.$={type:"sequenceIndex",sequenceIndex:Number(a[s-2]),sequenceIndexStep:Number(a[s-1]),sequenceVisible:!0,signalType:r.LINETYPE.AUTONUMBER};break;case 18:this.$={type:"sequenceIndex",sequenceIndex:Number(a[s-1]),sequenceIndexStep:1,sequenceVisible:!0,signalType:r.LINETYPE.AUTONUMBER};break;case 19:this.$={type:"sequenceIndex",sequenceVisible:!1,signalType:r.LINETYPE.AUTONUMBER};break;case 20:this.$={type:"sequenceIndex",sequenceVisible:!0,signalType:r.LINETYPE.AUTONUMBER};break;case 21:this.$={type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:a[s-1]};break;case 22:this.$={type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:a[s-1]};break;case 28:r.setDiagramTitle(a[s].substring(6)),this.$=a[s].substring(6);break;case 29:r.setDiagramTitle(a[s].substring(7)),this.$=a[s].substring(7);break;case 30:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 31:case 32:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 33:a[s-1].unshift({type:"loopStart",loopText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.LOOP_START}),a[s-1].push({type:"loopEnd",loopText:a[s-2],signalType:r.LINETYPE.LOOP_END}),this.$=a[s-1];break;case 34:a[s-1].unshift({type:"rectStart",color:r.parseMessage(a[s-2]),signalType:r.LINETYPE.RECT_START}),a[s-1].push({type:"rectEnd",color:r.parseMessage(a[s-2]),signalType:r.LINETYPE.RECT_END}),this.$=a[s-1];break;case 35:a[s-1].unshift({type:"optStart",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.OPT_START}),a[s-1].push({type:"optEnd",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.OPT_END}),this.$=a[s-1];break;case 36:a[s-1].unshift({type:"altStart",altText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.ALT_START}),a[s-1].push({type:"altEnd",signalType:r.LINETYPE.ALT_END}),this.$=a[s-1];break;case 37:a[s-1].unshift({type:"parStart",parText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.PAR_START}),a[s-1].push({type:"parEnd",signalType:r.LINETYPE.PAR_END}),this.$=a[s-1];break;case 38:a[s-1].unshift({type:"criticalStart",criticalText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.CRITICAL_START}),a[s-1].push({type:"criticalEnd",signalType:r.LINETYPE.CRITICAL_END}),this.$=a[s-1];break;case 39:a[s-1].unshift({type:"breakStart",breakText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.BREAK_START}),a[s-1].push({type:"breakEnd",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.BREAK_END}),this.$=a[s-1];break;case 42:this.$=a[s-3].concat([{type:"option",optionText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.CRITICAL_OPTION},a[s]]);break;case 44:this.$=a[s-3].concat([{type:"and",parText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.PAR_AND},a[s]]);break;case 46:this.$=a[s-3].concat([{type:"else",altText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.ALT_ELSE},a[s]]);break;case 47:this.$=[a[s-1],{type:"addNote",placement:a[s-2],actor:a[s-1].actor,text:a[s]}];break;case 48:a[s-2]=[].concat(a[s-1],a[s-1]).slice(0,2),a[s-2][0]=a[s-2][0].actor,a[s-2][1]=a[s-2][1].actor,this.$=[a[s-1],{type:"addNote",placement:r.PLACEMENT.OVER,actor:a[s-2].slice(0,2),text:a[s]}];break;case 49:this.$=[a[s-1],{type:"addLinks",actor:a[s-1].actor,text:a[s]}];break;case 50:this.$=[a[s-1],{type:"addALink",actor:a[s-1].actor,text:a[s]}];break;case 51:this.$=[a[s-1],{type:"addProperties",actor:a[s-1].actor,text:a[s]}];break;case 52:this.$=[a[s-1],{type:"addDetails",actor:a[s-1].actor,text:a[s]}];break;case 55:this.$=[a[s-2],a[s]];break;case 57:this.$=r.PLACEMENT.LEFTOF;break;case 58:this.$=r.PLACEMENT.RIGHTOF;break;case 59:this.$=[a[s-4],a[s-1],{type:"addMessage",from:a[s-4].actor,to:a[s-1].actor,signalType:a[s-3],msg:a[s]},{type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:a[s-1]}];break;case 60:this.$=[a[s-4],a[s-1],{type:"addMessage",from:a[s-4].actor,to:a[s-1].actor,signalType:a[s-3],msg:a[s]},{type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:a[s-4]}];break;case 61:this.$=[a[s-3],a[s-1],{type:"addMessage",from:a[s-3].actor,to:a[s-1].actor,signalType:a[s-2],msg:a[s]}];break;case 62:this.$={type:"addParticipant",actor:a[s]};break;case 63:this.$=r.LINETYPE.SOLID_OPEN;break;case 64:this.$=r.LINETYPE.DOTTED_OPEN;break;case 65:this.$=r.LINETYPE.SOLID;break;case 66:this.$=r.LINETYPE.DOTTED;break;case 67:this.$=r.LINETYPE.SOLID_CROSS;break;case 68:this.$=r.LINETYPE.DOTTED_CROSS;break;case 69:this.$=r.LINETYPE.SOLID_POINT;break;case 70:this.$=r.LINETYPE.DOTTED_POINT;break;case 71:this.$=r.parseMessage(a[s].trim().substring(1));break;case 72:r.parseDirective("%%{","open_directive");break;case 73:r.parseDirective(a[s],"type_directive");break;case 74:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 75:r.parseDirective("}%%","close_directive","sequence");}},table:[{3:1,4:e,5:n,6:4,7:r,11:6,79:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,11:6,79:i},{3:9,4:e,5:n,6:4,7:r,11:6,79:i},{3:10,4:e,5:n,6:4,7:r,11:6,79:i},t([1,4,5,16,20,22,25,26,32,33,34,36,38,39,41,42,43,45,47,49,53,58,59,60,61,69,79],a,{8:11}),{12:12,80:[1,13]},{80:[2,72]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,41:v,42:_,43:x,45:k,47:w,49:T,53:E,58:C,59:S,60:A,61:M,69:N,79:i},{13:49,14:[1,50],82:O},t([14,82],[2,73]),t(D,[2,6]),{6:41,10:52,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,41:v,42:_,43:x,45:k,47:w,49:T,53:E,58:C,59:S,60:A,61:M,69:N,79:i},t(D,[2,8]),t(D,[2,9]),{17:53,69:N},{17:54,69:N},{5:[1,55]},{5:[1,58],23:[1,56],24:[1,57]},{17:59,69:N},{17:60,69:N},{5:[1,61]},{5:[1,62]},{5:[1,63]},{5:[1,64]},{5:[1,65]},t(D,[2,28]),t(D,[2,29]),{35:[1,66]},{37:[1,67]},t(D,[2,32]),{19:[1,68]},{19:[1,69]},{19:[1,70]},{19:[1,71]},{19:[1,72]},{19:[1,73]},{19:[1,74]},t(D,[2,40]),{66:75,70:[1,76],71:[1,77],72:[1,78],73:[1,79],74:[1,80],75:[1,81],76:[1,82],77:[1,83]},{54:84,56:[1,85],64:[1,86],65:[1,87]},{17:88,69:N},{17:89,69:N},{17:90,69:N},{17:91,69:N},t([5,18,63,70,71,72,73,74,75,76,77,78],[2,62]),{5:[1,92]},{15:93,81:[1,94]},{5:[2,75]},t(D,[2,7]),{5:[1,96],18:[1,95]},{5:[1,98],18:[1,97]},t(D,[2,16]),{5:[1,100],23:[1,99]},{5:[1,101]},t(D,[2,20]),{5:[1,102]},{5:[1,103]},t(D,[2,23]),t(D,[2,24]),t(D,[2,25]),t(D,[2,26]),t(D,[2,27]),t(D,[2,30]),t(D,[2,31]),t(B,a,{8:104}),t(B,a,{8:105}),t(B,a,{8:106}),t(L,a,{44:107,8:108}),t(I,a,{46:109,8:110}),t(F,a,{48:111,8:112}),t(B,a,{8:113}),{17:116,67:[1,114],68:[1,115],69:N},t(R,[2,63]),t(R,[2,64]),t(R,[2,65]),t(R,[2,66]),t(R,[2,67]),t(R,[2,68]),t(R,[2,69]),t(R,[2,70]),{17:117,69:N},{17:119,57:118,69:N},{69:[2,57]},{69:[2,58]},{55:120,78:P},{55:122,78:P},{55:123,78:P},{55:124,78:P},t(j,[2,10]),{13:125,82:O},{82:[2,74]},{19:[1,126]},t(D,[2,13]),{19:[1,127]},t(D,[2,15]),{5:[1,128]},t(D,[2,18]),t(D,[2,19]),t(D,[2,21]),t(D,[2,22]),{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[1,129],41:v,42:_,43:x,45:k,47:w,49:T,53:E,58:C,59:S,60:A,61:M,69:N,79:i},{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[1,130],41:v,42:_,43:x,45:k,47:w,49:T,53:E,58:C,59:S,60:A,61:M,69:N,79:i},{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[1,131],41:v,42:_,43:x,45:k,47:w,49:T,53:E,58:C,59:S,60:A,61:M,69:N,79:i},{40:[1,132]},{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[2,45],41:v,42:_,43:x,45:k,47:w,49:T,52:[1,133],53:E,58:C,59:S,60:A,61:M,69:N,79:i},{40:[1,134]},{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[2,43],41:v,42:_,43:x,45:k,47:w,49:T,51:[1,135],53:E,58:C,59:S,60:A,61:M,69:N,79:i},{40:[1,136]},{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[2,41],41:v,42:_,43:x,45:k,47:w,49:T,50:[1,137],53:E,58:C,59:S,60:A,61:M,69:N,79:i},{4:o,5:s,6:41,9:14,10:16,11:6,16:c,17:42,20:l,21:20,22:u,25:h,26:f,27:24,28:25,29:26,30:27,31:28,32:d,33:p,34:g,36:y,38:m,39:b,40:[1,138],41:v,42:_,43:x,45:k,47:w,49:T,53:E,58:C,59:S,60:A,61:M,69:N,79:i},{17:139,69:N},{17:140,69:N},{55:141,78:P},{55:142,78:P},{55:143,78:P},{63:[1,144],78:[2,56]},{5:[2,49]},{5:[2,71]},{5:[2,50]},{5:[2,51]},{5:[2,52]},{5:[1,145]},{5:[1,146]},{5:[1,147]},t(D,[2,17]),t(D,[2,33]),t(D,[2,34]),t(D,[2,35]),t(D,[2,36]),{19:[1,148]},t(D,[2,37]),{19:[1,149]},t(D,[2,38]),{19:[1,150]},t(D,[2,39]),{55:151,78:P},{55:152,78:P},{5:[2,61]},{5:[2,47]},{5:[2,48]},{17:153,69:N},t(j,[2,11]),t(D,[2,12]),t(D,[2,14]),t(L,a,{8:108,44:154}),t(I,a,{8:110,46:155}),t(F,a,{8:112,48:156}),{5:[2,59]},{5:[2,60]},{78:[2,55]},{40:[2,46]},{40:[2,44]},{40:[2,42]}],defaultActions:{7:[2,72],8:[2,1],9:[2,2],10:[2,3],51:[2,75],86:[2,57],87:[2,58],94:[2,74],120:[2,49],121:[2,71],122:[2,50],123:[2,51],124:[2,52],141:[2,61],142:[2,47],143:[2,48],151:[2,59],152:[2,60],153:[2,55],154:[2,46],155:[2,44],156:[2,42]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},Y={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),79;case 1:return this.begin("type_directive"),80;case 2:return this.popState(),this.begin("arg_directive"),14;case 3:return this.popState(),this.popState(),82;case 4:return 81;case 5:case 52:case 65:return 5;case 6:case 7:case 8:case 9:case 10:break;case 11:return 23;case 12:return this.begin("ID"),16;case 13:return this.begin("ID"),20;case 14:return e.yytext=e.yytext.trim(),this.begin("ALIAS"),69;case 15:return this.popState(),this.popState(),this.begin("LINE"),18;case 16:return this.popState(),this.popState(),5;case 17:return this.begin("LINE"),39;case 18:return this.begin("LINE"),41;case 19:return this.begin("LINE"),42;case 20:return this.begin("LINE"),43;case 21:return this.begin("LINE"),52;case 22:return this.begin("LINE"),45;case 23:return this.begin("LINE"),51;case 24:return this.begin("LINE"),47;case 25:return this.begin("LINE"),50;case 26:return this.begin("LINE"),49;case 27:return this.popState(),19;case 28:return 40;case 29:return 64;case 30:return 65;case 31:return 58;case 32:return 59;case 33:return 60;case 34:return 61;case 35:return 56;case 36:return 53;case 37:return this.begin("ID"),25;case 38:return this.begin("ID"),26;case 39:return 32;case 40:return 33;case 41:return this.begin("acc_title"),34;case 42:return this.popState(),"acc_title_value";case 43:return this.begin("acc_descr"),36;case 44:return this.popState(),"acc_descr_value";case 45:this.begin("acc_descr_multiline");break;case 46:this.popState();break;case 47:return "acc_descr_multiline_value";case 48:return 7;case 49:return 22;case 50:return 24;case 51:return 63;case 53:return e.yytext=e.yytext.trim(),69;case 54:return 72;case 55:return 73;case 56:return 70;case 57:return 71;case 58:return 74;case 59:return 75;case 60:return 76;case 61:return 77;case 62:return 78;case 63:return 67;case 64:return 68;case 66:return "INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[0-9]+(?=[ \n]+))/i,/^(?:participant\b)/i,/^(?:actor\b)/i,/^(?:[^\->:\n,;]+?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:and\b)/i,/^(?:critical\b)/i,/^(?:option\b)/i,/^(?:break\b)/i,/^(?:(?:[:]?(?:no)?wrap)?[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:links\b)/i,/^(?:link\b)/i,/^(?:properties\b)/i,/^(?:details\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:title:\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:sequenceDiagram\b)/i,/^(?:autonumber\b)/i,/^(?:off\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\->:\n,;]+((?!(-x|--x|-\)|--\)))[\-]*[^\+\->:\n,;]+)*)/i,/^(?:->>)/i,/^(?:-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?:-[\)])/i,/^(?:--[\)])/i,/^(?::(?:(?:no)?wrap)?[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[46,47],inclusive:!1},acc_descr:{rules:[44],inclusive:!1},acc_title:{rules:[42],inclusive:!1},open_directive:{rules:[1,8],inclusive:!1},type_directive:{rules:[2,3,8],inclusive:!1},arg_directive:{rules:[3,4,8],inclusive:!1},ID:{rules:[7,8,14],inclusive:!1},ALIAS:{rules:[7,8,15,16],inclusive:!1},LINE:{rules:[7,8,27],inclusive:!1},INITIAL:{rules:[0,5,6,8,9,10,11,12,13,17,18,19,20,21,22,23,24,25,26,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,45,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66],inclusive:!0}}};function U(){this.yy={};}return z.lexer=Y,U.prototype=z,z.Parser=U,new U}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(1993).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},3584:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,19],l=[1,20],u=[1,21],h=[1,22],f=[1,33],d=[1,23],p=[1,24],g=[1,25],y=[1,26],m=[1,27],b=[1,30],v=[1,31],_=[1,32],x=[1,35],k=[1,36],w=[1,37],T=[1,38],E=[1,34],C=[1,41],S=[1,4,5,14,15,17,19,20,22,23,24,25,26,27,31,33,35,41,42,43,44,47,50],A=[1,4,5,12,13,14,15,17,19,20,22,23,24,25,26,27,31,33,35,41,42,43,44,47,50],M=[1,4,5,7,14,15,17,19,20,22,23,24,25,26,27,31,33,35,41,42,43,44,47,50],N=[4,5,14,15,17,19,20,22,23,24,25,26,27,31,33,35,41,42,43,44,47,50],O={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,directive:6,SD:7,document:8,line:9,statement:10,idStatement:11,DESCR:12,"--\x3e":13,HIDE_EMPTY:14,scale:15,WIDTH:16,COMPOSIT_STATE:17,STRUCT_START:18,STRUCT_STOP:19,STATE_DESCR:20,AS:21,ID:22,FORK:23,JOIN:24,CHOICE:25,CONCURRENT:26,note:27,notePosition:28,NOTE_TEXT:29,direction:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,openDirective:36,typeDirective:37,closeDirective:38,":":39,argDirective:40,direction_tb:41,direction_bt:42,direction_rl:43,direction_lr:44,eol:45,";":46,EDGE_STATE:47,left_of:48,right_of:49,open_directive:50,type_directive:51,arg_directive:52,close_directive:53,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",7:"SD",12:"DESCR",13:"--\x3e",14:"HIDE_EMPTY",15:"scale",16:"WIDTH",17:"COMPOSIT_STATE",18:"STRUCT_START",19:"STRUCT_STOP",20:"STATE_DESCR",21:"AS",22:"ID",23:"FORK",24:"JOIN",25:"CHOICE",26:"CONCURRENT",27:"note",29:"NOTE_TEXT",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",39:":",41:"direction_tb",42:"direction_bt",43:"direction_rl",44:"direction_lr",46:";",47:"EDGE_STATE",48:"left_of",49:"right_of",50:"open_directive",51:"type_directive",52:"arg_directive",53:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[10,1],[10,2],[10,3],[10,4],[10,1],[10,2],[10,1],[10,4],[10,3],[10,6],[10,1],[10,1],[10,1],[10,1],[10,4],[10,4],[10,1],[10,1],[10,2],[10,2],[10,1],[6,3],[6,5],[30,1],[30,1],[30,1],[30,1],[45,1],[45,1],[11,1],[11,1],[28,1],[28,1],[36,1],[37,1],[40,1],[38,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.setRootDoc(a[s]),a[s];case 5:this.$=[];break;case 6:"nl"!=a[s]&&(a[s-1].push(a[s]),this.$=a[s-1]);break;case 7:case 8:case 39:case 40:this.$=a[s];break;case 9:this.$="nl";break;case 10:this.$={stmt:"state",id:a[s],type:"default",description:""};break;case 11:this.$={stmt:"state",id:a[s-1],type:"default",description:r.trimColon(a[s])};break;case 12:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-2],type:"default",description:""},state2:{stmt:"state",id:a[s],type:"default",description:""}};break;case 13:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-3],type:"default",description:""},state2:{stmt:"state",id:a[s-1],type:"default",description:""},description:a[s].substr(1).trim()};break;case 17:this.$={stmt:"state",id:a[s-3],type:"default",description:"",doc:a[s-1]};break;case 18:var c=a[s],l=a[s-2].trim();if(a[s].match(":")){var u=a[s].split(":");c=u[0],l=[l,u[1]];}this.$={stmt:"state",id:c,type:"default",description:l};break;case 19:this.$={stmt:"state",id:a[s-3],type:"default",description:a[s-5],doc:a[s-1]};break;case 20:this.$={stmt:"state",id:a[s],type:"fork"};break;case 21:this.$={stmt:"state",id:a[s],type:"join"};break;case 22:this.$={stmt:"state",id:a[s],type:"choice"};break;case 23:this.$={stmt:"state",id:r.getDividerId(),type:"divider"};break;case 24:this.$={stmt:"state",id:a[s-1].trim(),note:{position:a[s-2].trim(),text:a[s].trim()}};break;case 28:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 29:case 30:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 33:r.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 34:r.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 35:r.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 36:r.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 43:r.parseDirective("%%{","open_directive");break;case 44:r.parseDirective(a[s],"type_directive");break;case 45:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 46:r.parseDirective("}%%","close_directive","state");}},table:[{3:1,4:e,5:n,6:4,7:r,36:6,50:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,36:6,50:i},{3:9,4:e,5:n,6:4,7:r,36:6,50:i},{3:10,4:e,5:n,6:4,7:r,36:6,50:i},t([1,4,5,14,15,17,20,22,23,24,25,26,27,31,33,35,41,42,43,44,47,50],a,{8:11}),{37:12,51:[1,13]},{51:[2,43]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:l,17:u,20:h,22:f,23:d,24:p,25:g,26:y,27:m,30:29,31:b,33:v,35:_,36:6,41:x,42:k,43:w,44:T,47:E,50:i},{38:39,39:[1,40],53:C},t([39,53],[2,44]),t(S,[2,6]),{6:28,10:42,11:18,14:c,15:l,17:u,20:h,22:f,23:d,24:p,25:g,26:y,27:m,30:29,31:b,33:v,35:_,36:6,41:x,42:k,43:w,44:T,47:E,50:i},t(S,[2,8]),t(S,[2,9]),t(S,[2,10],{12:[1,43],13:[1,44]}),t(S,[2,14]),{16:[1,45]},t(S,[2,16],{18:[1,46]}),{21:[1,47]},t(S,[2,20]),t(S,[2,21]),t(S,[2,22]),t(S,[2,23]),{28:48,29:[1,49],48:[1,50],49:[1,51]},t(S,[2,26]),t(S,[2,27]),{32:[1,52]},{34:[1,53]},t(S,[2,30]),t(A,[2,39]),t(A,[2,40]),t(S,[2,33]),t(S,[2,34]),t(S,[2,35]),t(S,[2,36]),t(M,[2,31]),{40:54,52:[1,55]},t(M,[2,46]),t(S,[2,7]),t(S,[2,11]),{11:56,22:f,47:E},t(S,[2,15]),t(N,a,{8:57}),{22:[1,58]},{22:[1,59]},{21:[1,60]},{22:[2,41]},{22:[2,42]},t(S,[2,28]),t(S,[2,29]),{38:61,53:C},{53:[2,45]},t(S,[2,12],{12:[1,62]}),{4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:l,17:u,19:[1,63],20:h,22:f,23:d,24:p,25:g,26:y,27:m,30:29,31:b,33:v,35:_,36:6,41:x,42:k,43:w,44:T,47:E,50:i},t(S,[2,18],{18:[1,64]}),{29:[1,65]},{22:[1,66]},t(M,[2,32]),t(S,[2,13]),t(S,[2,17]),t(N,a,{8:67}),t(S,[2,24]),t(S,[2,25]),{4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:l,17:u,19:[1,68],20:h,22:f,23:d,24:p,25:g,26:y,27:m,30:29,31:b,33:v,35:_,36:6,41:x,42:k,43:w,44:T,47:E,50:i},t(S,[2,19])],defaultActions:{7:[2,43],8:[2,1],9:[2,2],10:[2,3],50:[2,41],51:[2,42],55:[2,45]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},D={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:case 33:return 41;case 1:case 34:return 42;case 2:case 35:return 43;case 3:case 36:return 44;case 4:return this.begin("open_directive"),50;case 5:return this.begin("type_directive"),51;case 6:return this.popState(),this.begin("arg_directive"),39;case 7:return this.popState(),this.popState(),53;case 8:return 52;case 9:case 10:case 12:case 13:case 14:case 15:case 46:case 52:break;case 11:case 66:return 5;case 16:return this.pushState("SCALE"),15;case 17:return 16;case 18:case 24:case 40:case 43:this.popState();break;case 19:return this.begin("acc_title"),31;case 20:return this.popState(),"acc_title_value";case 21:return this.begin("acc_descr"),33;case 22:return this.popState(),"acc_descr_value";case 23:this.begin("acc_descr_multiline");break;case 25:return "acc_descr_multiline_value";case 26:this.pushState("STATE");break;case 27:case 30:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),23;case 28:case 31:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),24;case 29:case 32:return this.popState(),e.yytext=e.yytext.slice(0,-10).trim(),25;case 37:this.begin("STATE_STRING");break;case 38:return this.popState(),this.pushState("STATE_ID"),"AS";case 39:case 54:return this.popState(),"ID";case 41:return "STATE_DESCR";case 42:return 17;case 44:return this.popState(),this.pushState("struct"),18;case 45:return this.popState(),19;case 47:return this.begin("NOTE"),27;case 48:return this.popState(),this.pushState("NOTE_ID"),48;case 49:return this.popState(),this.pushState("NOTE_ID"),49;case 50:this.popState(),this.pushState("FLOATING_NOTE");break;case 51:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";case 53:return "NOTE_TEXT";case 55:return this.popState(),this.pushState("NOTE_TEXT"),22;case 56:return this.popState(),e.yytext=e.yytext.substr(2).trim(),29;case 57:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),29;case 58:case 59:return 7;case 60:return 14;case 61:return 47;case 62:return 22;case 63:return e.yytext=e.yytext.trim(),12;case 64:return 13;case 65:return 26;case 67:return "INVALID"}},rules:[/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:state\s+)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:.*\[\[choice\]\])/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:["])/i,/^(?:\s*as\s+)/i,/^(?:[^\n\{]*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n\s\{]+)/i,/^(?:\n)/i,/^(?:\{)/i,/^(?:\})/i,/^(?:[\n])/i,/^(?:note\s+)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:")/i,/^(?:\s*as\s*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n]*)/i,/^(?:\s*[^:\n\s\-]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:[\s\S]*?end note\b)/i,/^(?:stateDiagram\s+)/i,/^(?:stateDiagram-v2\s+)/i,/^(?:hide empty description\b)/i,/^(?:\[\*\])/i,/^(?:[^:\n\s\-\{]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:-->)/i,/^(?:--)/i,/^(?:$)/i,/^(?:.)/i],conditions:{LINE:{rules:[13,14],inclusive:!1},close_directive:{rules:[13,14],inclusive:!1},arg_directive:{rules:[7,8,13,14],inclusive:!1},type_directive:{rules:[6,7,13,14],inclusive:!1},open_directive:{rules:[5,13,14],inclusive:!1},struct:{rules:[13,14,26,33,34,35,36,45,46,47,61,62,63,64,65],inclusive:!1},FLOATING_NOTE_ID:{rules:[54],inclusive:!1},FLOATING_NOTE:{rules:[51,52,53],inclusive:!1},NOTE_TEXT:{rules:[56,57],inclusive:!1},NOTE_ID:{rules:[55],inclusive:!1},NOTE:{rules:[48,49,50],inclusive:!1},acc_descr_multiline:{rules:[24,25],inclusive:!1},acc_descr:{rules:[22],inclusive:!1},acc_title:{rules:[20],inclusive:!1},SCALE:{rules:[17,18],inclusive:!1},ALIAS:{rules:[],inclusive:!1},STATE_ID:{rules:[39],inclusive:!1},STATE_STRING:{rules:[40,41],inclusive:!1},FORK_STATE:{rules:[],inclusive:!1},STATE:{rules:[13,14,27,28,29,30,31,32,37,38,42,43,44],inclusive:!1},ID:{rules:[13,14],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,12,14,15,16,19,21,23,26,44,47,58,59,60,61,62,63,64,66,67],inclusive:!0}}};function B(){this.yy={};}return O.lexer=D,B.prototype=O,O.Parser=B,new B}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(3069).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},9763:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,17,18,20,22,23,24,26],i=[1,15],a=[1,16],o=[1,17],s=[1,18],c=[1,19],l=[1,20],u=[1,24],h=[4,6,9,11,17,18,20,22,23,24,26],f={trace:function(){},yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,title:17,acc_title:18,acc_title_value:19,acc_descr:20,acc_descr_value:21,acc_descr_multiline_value:22,section:23,taskName:24,taskData:25,open_directive:26,type_directive:27,arg_directive:28,close_directive:29,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",17:"title",18:"acc_title",19:"acc_title_value",20:"acc_descr",21:"acc_descr_value",22:"acc_descr_multiline_value",23:"section",24:"taskName",25:"taskData",26:"open_directive",27:"type_directive",28:"arg_directive",29:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,2],[10,2],[10,1],[10,1],[10,2],[10,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 11:r.setDiagramTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 12:this.$=a[s].trim(),r.setAccTitle(this.$);break;case 13:case 14:this.$=a[s].trim(),r.setAccDescription(this.$);break;case 15:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 16:r.addTask(a[s-1],a[s]),this.$="task";break;case 18:r.parseDirective("%%{","open_directive");break;case 19:r.parseDirective(a[s],"type_directive");break;case 20:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 21:r.parseDirective("}%%","close_directive","journey");}},table:[{3:1,4:e,7:3,12:4,26:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,26:n},{13:8,27:[1,9]},{27:[2,18]},{6:[1,10],7:21,8:11,9:[1,12],10:13,11:[1,14],12:4,17:i,18:a,20:o,22:s,23:c,24:l,26:n},{1:[2,2]},{14:22,15:[1,23],29:u},t([15,29],[2,19]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:21,10:25,12:4,17:i,18:a,20:o,22:s,23:c,24:l,26:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),{19:[1,26]},{21:[1,27]},t(r,[2,14]),t(r,[2,15]),{25:[1,28]},t(r,[2,17]),{11:[1,29]},{16:30,28:[1,31]},{11:[2,21]},t(r,[2,5]),t(r,[2,12]),t(r,[2,13]),t(r,[2,16]),t(h,[2,9]),{14:32,29:u},{29:[2,20]},{11:[1,33]},t(h,[2,10])],defaultActions:{5:[2,18],7:[2,2],24:[2,21],31:[2,20]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t);},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,l=0,u=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),g={yy:{}};for(var y in this.yy)Object.prototype.hasOwnProperty.call(this.yy,y)&&(g.yy[y]=this.yy[y]);p.setInput(t,g.yy),g.yy.lexer=p,g.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var b=p.options&&p.options.ranges;function v(){var t;return "number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof g.yy.parseError?this.parseError=g.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,k,w,T,E,C,S,A,M={};;){if(k=n[n.length-1],this.defaultActions[k]?w=this.defaultActions[k]:(null==_&&(_=v()),w=o[k]&&o[k][_]),void 0===w||!w.length||!w[0]){var N="";for(E in A=[],o[k])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A});}if(w[0]instanceof Array&&w.length>1)throw new Error("Parse Error: multiple actions possible at state: "+k+", token: "+_);switch(w[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(w[1]),_=null,x?(_=x,x=null):(l=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,u>0&&u--);break;case 2:if(C=this.productions_[w[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},b&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,l,c,g.yy,w[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[w[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return !0}}return !0}},d={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e);},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t));},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return (t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return !1}return !1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return !1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t);},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return (t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t);},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),26;case 1:return this.begin("type_directive"),27;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),29;case 4:return 28;case 5:case 6:case 8:case 9:break;case 7:return 11;case 10:return 4;case 11:return 17;case 12:return this.begin("acc_title"),18;case 13:return this.popState(),"acc_title_value";case 14:return this.begin("acc_descr"),20;case 15:return this.popState(),"acc_descr_value";case 16:this.begin("acc_descr_multiline");break;case 17:this.popState();break;case 18:return "acc_descr_multiline_value";case 19:return 23;case 20:return 24;case 21:return 25;case 22:return 15;case 23:return 6;case 24:return "INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},acc_descr_multiline:{rules:[17,18],inclusive:!1},acc_descr:{rules:[15],inclusive:!1},acc_title:{rules:[13],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,14,16,19,20,21,22,23,24],inclusive:!0}}};function p(){this.yy={};}return f.lexer=d,p.prototype=f,f.Parser=p,new p}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(9143).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1));},7967:(t,e)=>{e.N=void 0;var n=/^([^\w]*)(javascript|data|vbscript)/im,r=/(\w+)(^\w|;)?/g,i=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,a=/^([^:]+):/gm,o=[".","/"];e.N=function(t){var e,s=(e=t||"",e.replace(r,(function(t,e){return String.fromCharCode(e)}))).replace(i,"").trim();if(!s)return "about:blank";if(function(t){return o.indexOf(t[0])>-1}(s))return s;var c=s.match(a);if(!c)return s;var l=c[0];return n.test(l)?"about:blank":s};},3841:t=>{t.exports=function(t,e){return t.intersect(e)};},6187:(t,e,n)=>{n.d(e,{Z:()=>fu});var r=n(1941),i=n.n(r),a={debug:1,info:2,warn:3,error:4,fatal:5},o={debug:function(){},info:function(){},warn:function(){},error:function(){},fatal:function(){}},s=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"fatal";isNaN(t)&&(t=t.toLowerCase(),void 0!==a[t]&&(t=a[t])),o.trace=function(){},o.debug=function(){},o.info=function(){},o.warn=function(){},o.error=function(){},o.fatal=function(){},t<=a.fatal&&(o.fatal=console.error?console.error.bind(console,c("FATAL"),"color: orange"):console.log.bind(console,"[35m",c("FATAL"))),t<=a.error&&(o.error=console.error?console.error.bind(console,c("ERROR"),"color: orange"):console.log.bind(console,"[31m",c("ERROR"))),t<=a.warn&&(o.warn=console.warn?console.warn.bind(console,c("WARN"),"color: orange"):console.log.bind(console,"[33m",c("WARN"))),t<=a.info&&(o.info=console.info?console.info.bind(console,c("INFO"),"color: lightblue"):console.log.bind(console,"[34m",c("INFO"))),t<=a.debug&&(o.debug=console.debug?console.debug.bind(console,c("DEBUG"),"color: lightgreen"):console.log.bind(console,"[32m",c("DEBUG")));},c=function(t){var e=i()().format("ss.SSS");return "%c".concat(e," : ").concat(t," : ")},l=n(7543),u="comm",h="rule",f="decl",d=Math.abs,p=String.fromCharCode;function g(t){return t.trim()}function y(t,e,n){return t.replace(e,n)}function m(t,e){return t.indexOf(e)}function b(t,e){return 0|t.charCodeAt(e)}function v(t,e,n){return t.slice(e,n)}function _(t){return t.length}function x(t){return t.length}function k(t,e){return e.push(t),t}function w(t,e){for(var n="",r=x(t),i=0;i0?b(N,--A):0,C--,10===M&&(C=1,E--),M}function B(){return M=A2||R(M)>3?"":" "}function z(t,e){for(;--e&&B()&&!(M<48||M>102||M>57&&M<65||M>70&&M<97););return F(t,I()+(e<6&&32==L()&&32==B()))}function Y(t){for(;B();)switch(M){case t:return A;case 34:case 39:34!==t&&39!==t&&Y(M);break;case 40:41===t&&Y(t);break;case 92:B();}return A}function U(t,e){for(;B()&&t+M!==57&&(t+M!==84||47!==L()););return "/*"+F(e,A-1)+"*"+p(47===t?t:B())}function $(t){for(;!R(L());)B();return F(t,A)}function W(t){return function(t){return N="",t}(q("",null,null,null,[""],t=function(t){return E=C=1,S=_(N=t),A=0,[]}(t),0,[0],t))}function q(t,e,n,r,i,a,o,s,c){for(var l=0,u=0,h=o,f=0,d=0,g=0,b=1,v=1,x=1,w=0,T="",E=i,C=a,S=r,A=T;v;)switch(g=w,w=B()){case 40:if(108!=g&&58==A.charCodeAt(h-1)){-1!=m(A+=y(P(w),"&","&\f"),"&\f")&&(x=-1);break}case 34:case 39:case 91:A+=P(w);break;case 9:case 10:case 13:case 32:A+=j(g);break;case 92:A+=z(I()-1,7);continue;case 47:switch(L()){case 42:case 47:k(V(U(B(),I()),e,n),c);break;default:A+="/";}break;case 123*b:s[l++]=_(A)*x;case 125*b:case 59:case 0:switch(w){case 0:case 125:v=0;case 59+u:d>0&&_(A)-h&&k(d>32?G(A+";",r,n,h-1):G(y(A," ","")+";",r,n,h-2),c);break;case 59:A+=";";default:if(k(S=H(A,e,n,l,u,i,s,T,E=[],C=[],h),a),123===w)if(0===u)q(A,e,S,S,E,a,h,s,C);else switch(f){case 100:case 109:case 115:q(t,S,S,r&&k(H(t,S,S,0,0,i,s,T,i,E=[],h),C),i,C,h,s,r?E:C);break;default:q(A,S,S,S,[""],C,0,s,C);}}l=u=d=0,b=x=1,T=A="",h=o;break;case 58:h=1+_(A),d=g;default:if(b<1)if(123==w)--b;else if(125==w&&0==b++&&125==D())continue;switch(A+=p(w),w*b){case 38:x=u>0?1:(A+="\f",-1);break;case 44:s[l++]=(_(A)-1)*x,x=1;break;case 64:45===L()&&(A+=P(B())),f=L(),u=h=_(T=A+=$(I())),w++;break;case 45:45===g&&2==_(A)&&(b=0);}}return a}function H(t,e,n,r,i,a,o,s,c,l,u){for(var f=i-1,p=0===i?a:[""],m=x(p),b=0,_=0,k=0;b0?p[w]+" "+T:y(T,/&\f/g,p[w])))&&(c[k++]=E);return O(t,e,n,0===i?h:s,c,l,u)}function V(t,e,n){return O(t,e,n,u,p(M),v(t,2,-2),0)}function G(t,e,n,r){return O(t,e,n,f,v(t,0,r),v(t,r+1,-1),r)}const X="9.1.7";function Z(t){return Z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Z(t)}const Q=function t(e,n,r){var i=Object.assign({depth:2,clobber:!1},r),a=i.depth,o=i.clobber;return Array.isArray(n)&&!Array.isArray(e)?(n.forEach((function(n){return t(e,n,r)})),e):Array.isArray(n)&&Array.isArray(e)?(n.forEach((function(t){-1===e.indexOf(t)&&e.push(t);})),e):void 0===e||a<=0?null!=e&&"object"===Z(e)&&"object"===Z(n)?Object.assign(e,n):n:(void 0!==n&&"object"===Z(e)&&"object"===Z(n)&&Object.keys(n).forEach((function(r){"object"!==Z(n[r])||void 0!==e[r]&&"object"!==Z(e[r])?(o||"object"!==Z(e[r])&&"object"!==Z(n[r]))&&(e[r]=n[r]):(void 0===e[r]&&(e[r]=Array.isArray(n[r])?[]:{}),e[r]=t(e[r],n[r],{depth:a-1,clobber:o}));})),e)},K={min:{r:0,g:0,b:0,s:0,l:0,a:0},max:{r:255,g:255,b:255,h:360,s:100,l:100,a:1},clamp:{r:t=>t>=255?255:t<0?0:t,g:t=>t>=255?255:t<0?0:t,b:t=>t>=255?255:t<0?0:t,h:t=>t%360,s:t=>t>=100?100:t<0?0:t,l:t=>t>=100?100:t<0?0:t,a:t=>t>=1?1:t<0?0:t},toLinear:t=>{const e=t/255;return t>.03928?Math.pow((e+.055)/1.055,2.4):e/12.92},hue2rgb:(t,e,n)=>(n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+(e-t)*(2/3-n)*6:t),hsl2rgb:({h:t,s:e,l:n},r)=>{if(!e)return 2.55*n;t/=360,e/=100;const i=(n/=100)<.5?n*(1+e):n+e-n*e,a=2*n-i;switch(r){case"r":return 255*K.hue2rgb(a,i,t+1/3);case"g":return 255*K.hue2rgb(a,i,t);case"b":return 255*K.hue2rgb(a,i,t-1/3)}},rgb2hsl:({r:t,g:e,b:n},r)=>{t/=255,e/=255,n/=255;const i=Math.max(t,e,n),a=Math.min(t,e,n),o=(i+a)/2;if("l"===r)return 100*o;if(i===a)return 0;const s=i-a;if("s"===r)return 100*(o>.5?s/(2-i-a):s/(i+a));switch(i){case t:return 60*((e-n)/s+(ee>n?Math.min(e,Math.max(n,t)):Math.min(n,Math.max(e,t)),round:t=>Math.round(1e10*t)/1e10},unit:{dec2hex:t=>{const e=Math.round(t).toString(16);return e.length>1?e:`0${e}`}}},tt={};for(let t=0;t<=255;t++)tt[t]=J.unit.dec2hex(t);const et=new class{constructor(t,e){this.color=e,this.changed=!1,this.data=t,this.type=new class{constructor(){this.type=0;}get(){return this.type}set(t){if(this.type&&this.type!==t)throw new Error("Cannot change both RGB and HSL channels at the same time");this.type=t;}reset(){this.type=0;}is(t){return this.type===t}};}set(t,e){return this.color=e,this.changed=!1,this.data=t,this.type.type=0,this}_ensureHSL(){const t=this.data,{h:e,s:n,l:r}=t;void 0===e&&(t.h=J.channel.rgb2hsl(t,"h")),void 0===n&&(t.s=J.channel.rgb2hsl(t,"s")),void 0===r&&(t.l=J.channel.rgb2hsl(t,"l"));}_ensureRGB(){const t=this.data,{r:e,g:n,b:r}=t;void 0===e&&(t.r=J.channel.hsl2rgb(t,"r")),void 0===n&&(t.g=J.channel.hsl2rgb(t,"g")),void 0===r&&(t.b=J.channel.hsl2rgb(t,"b"));}get r(){const t=this.data,e=t.r;return this.type.is(2)||void 0===e?(this._ensureHSL(),J.channel.hsl2rgb(t,"r")):e}get g(){const t=this.data,e=t.g;return this.type.is(2)||void 0===e?(this._ensureHSL(),J.channel.hsl2rgb(t,"g")):e}get b(){const t=this.data,e=t.b;return this.type.is(2)||void 0===e?(this._ensureHSL(),J.channel.hsl2rgb(t,"b")):e}get h(){const t=this.data,e=t.h;return this.type.is(1)||void 0===e?(this._ensureRGB(),J.channel.rgb2hsl(t,"h")):e}get s(){const t=this.data,e=t.s;return this.type.is(1)||void 0===e?(this._ensureRGB(),J.channel.rgb2hsl(t,"s")):e}get l(){const t=this.data,e=t.l;return this.type.is(1)||void 0===e?(this._ensureRGB(),J.channel.rgb2hsl(t,"l")):e}get a(){return this.data.a}set r(t){this.type.set(1),this.changed=!0,this.data.r=t;}set g(t){this.type.set(1),this.changed=!0,this.data.g=t;}set b(t){this.type.set(1),this.changed=!0,this.data.b=t;}set h(t){this.type.set(2),this.changed=!0,this.data.h=t;}set s(t){this.type.set(2),this.changed=!0,this.data.s=t;}set l(t){this.type.set(2),this.changed=!0,this.data.l=t;}set a(t){this.changed=!0,this.data.a=t;}}({r:0,g:0,b:0,a:0},"transparent"),nt={re:/^#((?:[a-f0-9]{2}){2,4}|[a-f0-9]{3})$/i,parse:t=>{if(35!==t.charCodeAt(0))return;const e=t.match(nt.re);if(!e)return;const n=e[1],r=parseInt(n,16),i=n.length,a=i%4==0,o=i>4,s=o?1:17,c=o?8:4,l=a?0:-1,u=o?255:15;return et.set({r:(r>>c*(l+3)&u)*s,g:(r>>c*(l+2)&u)*s,b:(r>>c*(l+1)&u)*s,a:a?(r&u)*s/255:1},t)},stringify:t=>{const{r:e,g:n,b:r,a:i}=t;return i<1?`#${tt[Math.round(e)]}${tt[Math.round(n)]}${tt[Math.round(r)]}${tt[Math.round(255*i)]}`:`#${tt[Math.round(e)]}${tt[Math.round(n)]}${tt[Math.round(r)]}`}},rt=nt,it={re:/^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,hueRe:/^(.+?)(deg|grad|rad|turn)$/i,_hue2deg:t=>{const e=t.match(it.hueRe);if(e){const[,t,n]=e;switch(n){case"grad":return J.channel.clamp.h(.9*parseFloat(t));case"rad":return J.channel.clamp.h(180*parseFloat(t)/Math.PI);case"turn":return J.channel.clamp.h(360*parseFloat(t))}}return J.channel.clamp.h(parseFloat(t))},parse:t=>{const e=t.charCodeAt(0);if(104!==e&&72!==e)return;const n=t.match(it.re);if(!n)return;const[,r,i,a,o,s]=n;return et.set({h:it._hue2deg(r),s:J.channel.clamp.s(parseFloat(i)),l:J.channel.clamp.l(parseFloat(a)),a:o?J.channel.clamp.a(s?parseFloat(o)/100:parseFloat(o)):1},t)},stringify:t=>{const{h:e,s:n,l:r,a:i}=t;return i<1?`hsla(${J.lang.round(e)}, ${J.lang.round(n)}%, ${J.lang.round(r)}%, ${i})`:`hsl(${J.lang.round(e)}, ${J.lang.round(n)}%, ${J.lang.round(r)}%)`}},at=it,ot={colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyanaqua:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",transparent:"#00000000",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},parse:t=>{t=t.toLowerCase();const e=ot.colors[t];if(e)return rt.parse(e)},stringify:t=>{const e=rt.stringify(t);for(const t in ot.colors)if(ot.colors[t]===e)return t}},st=ot,ct={re:/^rgba?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?))(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e\d+)?(%?)))?\s*?\)$/i,parse:t=>{const e=t.charCodeAt(0);if(114!==e&&82!==e)return;const n=t.match(ct.re);if(!n)return;const[,r,i,a,o,s,c,l,u]=n;return et.set({r:J.channel.clamp.r(i?2.55*parseFloat(r):parseFloat(r)),g:J.channel.clamp.g(o?2.55*parseFloat(a):parseFloat(a)),b:J.channel.clamp.b(c?2.55*parseFloat(s):parseFloat(s)),a:l?J.channel.clamp.a(u?parseFloat(l)/100:parseFloat(l)):1},t)},stringify:t=>{const{r:e,g:n,b:r,a:i}=t;return i<1?`rgba(${J.lang.round(e)}, ${J.lang.round(n)}, ${J.lang.round(r)}, ${J.lang.round(i)})`:`rgb(${J.lang.round(e)}, ${J.lang.round(n)}, ${J.lang.round(r)})`}},lt=ct,ut={format:{keyword:st,hex:rt,rgb:lt,rgba:lt,hsl:at,hsla:at},parse:t=>{if("string"!=typeof t)return t;const e=rt.parse(t)||lt.parse(t)||at.parse(t)||st.parse(t);if(e)return e;throw new Error(`Unsupported color format: "${t}"`)},stringify:t=>!t.changed&&t.color?t.color:t.type.is(2)||void 0===t.data.r?at.stringify(t):t.a<1||!Number.isInteger(t.r)||!Number.isInteger(t.g)||!Number.isInteger(t.b)?lt.stringify(t):rt.stringify(t)},ht=(t,e)=>{const n=ut.parse(t);for(const t in e)n[t]=J.channel.clamp[t](e[t]);return ut.stringify(n)},ft=(t,e)=>{const n=ut.parse(t),r={};for(const t in e)e[t]&&(r[t]=n[t]+e[t]);return ht(t,r)},dt=(t,e,n=0,r=1)=>{if("number"!=typeof t)return ht(t,{a:e});const i=et.set({r:J.channel.clamp.r(t),g:J.channel.clamp.g(e),b:J.channel.clamp.b(n),a:J.channel.clamp.a(r)});return ut.stringify(i)},pt=(t,e=100)=>{const n=ut.parse(t);return n.r=255-n.r,n.g=255-n.g,n.b=255-n.b,((t,e,n=50)=>{const{r,g:i,b:a,a:o}=ut.parse(t),{r:s,g:c,b:l,a:u}=ut.parse(e),h=n/100,f=2*h-1,d=o-u,p=((f*d==-1?f:(f+d)/(1+f*d))+1)/2,g=1-p;return dt(r*p+s*g,i*p+c*g,a*p+l*g,o*h+u*(1-h))})(n,t,e)},gt=(t,e,n)=>{const r=ut.parse(t),i=r[e],a=J.channel.clamp[e](i+n);return i!==a&&(r[e]=a),ut.stringify(r)},yt=(t,e)=>gt(t,"l",-e),mt=(t,e)=>gt(t,"l",e);var bt=function(t,e){return ft(t,e?{s:-40,l:10}:{s:-40,l:-10})};function vt(t){return vt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},vt(t)}function _t(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n1&&void 0!==arguments[1]?arguments[1]:"";return Object.keys(e).reduce((function(r,i){return Array.isArray(e[i])?r:"object"===Rt(e[i])&&null!==e[i]?[].concat(It(r),[n+i],It(t(e[i],""))):[].concat(It(r),[n+i])}),[])}(Pt,"");const zt=Pt;function Yt(t){return Yt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Yt(t)}var Ut,$t=Object.freeze(zt),Wt=Q({},$t),qt=[],Ht=Q({},$t),Vt=function(t,e){for(var n=Q({},t),r={},i=0;i-1||e[n].indexOf(">")>-1||e[n].indexOf("url(data:")>-1)&&delete e[n],"object"===Yt(e[n])&&t(e[n]);}));},Qt=function(t){t.fontFamily&&(t.themeVariables&&t.themeVariables.fontFamily||(t.themeVariables={fontFamily:t.fontFamily})),qt.push(t),Vt(Wt,qt);},Kt=function(){Vt(Wt,qt=[]);},Jt=n(7856),te=n.n(Jt),ee=function(t){var e=t.replace(/\\u[\dA-F]{4}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\u/g,""),16))}));return e=(e=(e=e.replace(/\\x([0-9a-f]{2})/gi,(function(t,e){return String.fromCharCode(parseInt(e,16))}))).replace(/\\[\d\d\d]{3}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\/g,""),8))}))).replace(/\\[\d\d\d]{2}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\/g,""),8))}))},ne=function(t){for(var e="",n=0;n>=0;){if(!((n=t.indexOf("
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/cherry/drawio_demo/Actions.js b/static/cherry/drawio_demo/Actions.js
new file mode 100644
index 000000000..198ee9bf2
--- /dev/null
+++ b/static/cherry/drawio_demo/Actions.js
@@ -0,0 +1,1961 @@
+/**
+ * Copyright (c) 2006-2020, JGraph Ltd
+ * Copyright (c) 2006-2020, draw.io AG
+ *
+ * Constructs the actions object for the given UI.
+ */
+function Actions(editorUi)
+{
+ this.editorUi = editorUi;
+ this.actions = new Object();
+ this.init();
+};
+
+/**
+ * Adds the default actions.
+ */
+Actions.prototype.init = function()
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var isGraphEnabled = function()
+ {
+ return Action.prototype.isEnabled.apply(this, arguments) && graph.isEnabled();
+ };
+
+ // File actions
+ this.addAction('new...', function() { graph.openLink(ui.getUrl()); });
+ this.addAction('open...', function()
+ {
+ window.openNew = true;
+ window.openKey = 'open';
+
+ ui.openFile();
+ });
+ this.put('smartFit', new Action(mxResources.get('fitWindow') + ' / ' + mxResources.get('resetView'), function()
+ {
+ graph.popupMenuHandler.hideMenu();
+
+ var scale = graph.view.scale;
+ var sx = graph.container.scrollLeft;
+ var sy = graph.container.scrollTop;
+ var tx = graph.view.translate.x;
+ var ty = graph.view.translate.y;
+ var thresh = 5;
+
+ ui.actions.get('resetView').funct();
+
+ // Toggle scale if nothing has changed
+ if (Math.abs(scale - graph.view.scale) < 0.00001 &&
+ Math.abs(sx - graph.container.scrollLeft) < thresh &&
+ Math.abs(sy - graph.container.scrollTop) < thresh &&
+ tx == graph.view.translate.x &&
+ ty == graph.view.translate.y)
+ {
+ ui.actions.get('fitWindow').funct();
+ }
+ }, null, null, 'Enter'));
+ this.addAction('keyPressEnter', function()
+ {
+ if (graph.isEnabled())
+ {
+ if (graph.isSelectionEmpty())
+ {
+ ui.actions.get('smartFit').funct();
+ }
+ else
+ {
+ graph.startEditingAtCell();
+ }
+ }
+ });
+ this.addAction('import...', function()
+ {
+ window.openNew = false;
+ window.openKey = 'import';
+
+ // Closes dialog after open
+ window.openFile = new OpenFile(mxUtils.bind(this, function()
+ {
+ ui.hideDialog();
+ }));
+
+ window.openFile.setConsumer(mxUtils.bind(this, function(xml, filename)
+ {
+ try
+ {
+ var doc = mxUtils.parseXml(xml);
+ editor.graph.setSelectionCells(editor.graph.importGraphModel(doc.documentElement));
+ }
+ catch (e)
+ {
+ mxUtils.alert(mxResources.get('invalidOrMissingFile') + ': ' + e.message);
+ }
+ }));
+
+ // Removes openFile if dialog is closed
+ ui.showDialog(new OpenDialog(this).container, 320, 220, true, true, function()
+ {
+ window.openFile = null;
+ });
+ }).isEnabled = isGraphEnabled;
+ this.addAction('save', function() { ui.saveFile(false); }, null, null, Editor.ctrlKey + '+S').isEnabled = isGraphEnabled;
+ this.addAction('saveAs...', function() { ui.saveFile(true); }, null, null, Editor.ctrlKey + '+Shift+S').isEnabled = isGraphEnabled;
+ this.addAction('export...', function() { ui.showDialog(new ExportDialog(ui).container, 300, 340, true, true); });
+ this.addAction('editDiagram...', function()
+ {
+ var dlg = new EditDiagramDialog(ui);
+ ui.showDialog(dlg.container, 620, 420, true, false);
+ dlg.init();
+ });
+ this.addAction('pageSetup...', function() { ui.showDialog(new PageSetupDialog(ui).container, 320, 240, true, true); }).isEnabled = isGraphEnabled;
+ this.addAction('print...', function() { ui.showDialog(new PrintDialog(ui).container, 300, 180, true, true); }, null, 'sprite-print', Editor.ctrlKey + '+P');
+ this.addAction('preview', function() { mxUtils.show(graph, null, 10, 10); });
+
+ // Edit actions
+ this.addAction('undo', function() { ui.undo(); }, null, 'sprite-undo', Editor.ctrlKey + '+Z');
+ this.addAction('redo', function() { ui.redo(); }, null, 'sprite-redo', (!mxClient.IS_WIN) ? Editor.ctrlKey + '+Shift+Z' : Editor.ctrlKey + '+Y');
+ this.addAction('cut', function()
+ {
+ var cells = null;
+
+ try
+ {
+ cells = ui.copyXml();
+
+ if (cells != null)
+ {
+ graph.removeCells(cells, false);
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ if (cells == null)
+ {
+ mxClipboard.cut(graph);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }, null, 'sprite-cut', Editor.ctrlKey + '+X');
+ this.addAction('copy', function()
+ {
+ try
+ {
+ ui.copyXml();
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ mxClipboard.copy(graph);
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }, null, 'sprite-copy', Editor.ctrlKey + '+C');
+ this.addAction('paste', function()
+ {
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
+ {
+ var done = false;
+
+ try
+ {
+ if (Editor.enableNativeCipboard)
+ {
+ ui.readGraphModelFromClipboard(function(xml)
+ {
+ if (xml != null)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ ui.pasteXml(xml, true);
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ else
+ {
+ mxClipboard.paste(graph);
+ }
+ })
+
+ done = true;
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ if (!done)
+ {
+ mxClipboard.paste(graph);
+ }
+ }
+ }, false, 'sprite-paste', Editor.ctrlKey + '+V');
+ this.addAction('pasteHere', function(evt)
+ {
+ function pasteCellsHere(cells)
+ {
+ if (cells != null)
+ {
+ var includeEdges = true;
+
+ for (var i = 0; i < cells.length && includeEdges; i++)
+ {
+ includeEdges = includeEdges && graph.model.isEdge(cells[i]);
+ }
+
+ var t = graph.view.translate;
+ var s = graph.view.scale;
+ var dx = t.x;
+ var dy = t.y;
+ var bb = null;
+
+ if (cells.length == 1 && includeEdges)
+ {
+ var geo = graph.getCellGeometry(cells[0]);
+
+ if (geo != null)
+ {
+ bb = geo.getTerminalPoint(true);
+ }
+ }
+
+ bb = (bb != null) ? bb : graph.getBoundingBoxFromGeometry(cells, includeEdges);
+
+ if (bb != null)
+ {
+ var x = Math.round(graph.snap(graph.popupMenuHandler.triggerX / s - dx));
+ var y = Math.round(graph.snap(graph.popupMenuHandler.triggerY / s - dy));
+
+ graph.cellsMoved(cells, x - bb.x, y - bb.y);
+ }
+ }
+ };
+
+ function fallback()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ pasteCellsHere(mxClipboard.paste(graph));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ };
+
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
+ {
+ var done = false;
+
+ try
+ {
+ if (Editor.enableNativeCipboard)
+ {
+ ui.readGraphModelFromClipboard(function(xml)
+ {
+ if (xml != null)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ pasteCellsHere(ui.pasteXml(xml, true));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ else
+ {
+ fallback();
+ }
+ })
+
+ done = true;
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ if (!done)
+ {
+ fallback();
+ }
+ }
+ });
+
+ this.addAction('copySize', function()
+ {
+ var cell = graph.getSelectionCell();
+
+ if (graph.isEnabled() && cell != null && graph.getModel().isVertex(cell))
+ {
+ var geo = graph.getCellGeometry(cell);
+
+ if (geo != null)
+ {
+ ui.copiedSize = new mxRectangle(geo.x, geo.y, geo.width, geo.height);
+ }
+ }
+ }, null, null, 'Alt+Shift+F');
+
+ this.addAction('pasteSize', function()
+ {
+ if (graph.isEnabled() && !graph.isSelectionEmpty() && ui.copiedSize != null)
+ {
+ graph.getModel().beginUpdate();
+
+ try
+ {
+ var cells = graph.getResizableCells(graph.getSelectionCells());
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (graph.getModel().isVertex(cells[i]))
+ {
+ var geo = graph.getCellGeometry(cells[i]);
+
+ if (geo != null)
+ {
+ geo = geo.clone();
+ geo.width = ui.copiedSize.width;
+ geo.height = ui.copiedSize.height;
+
+ graph.getModel().setGeometry(cells[i], geo);
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }, null, null, 'Alt+Shift+V');
+
+ this.addAction('copyData', function()
+ {
+ var cell = graph.getSelectionCell() || graph.getModel().getRoot();
+
+ if (graph.isEnabled() && cell != null)
+ {
+ var value = cell.cloneValue();
+
+ if (value != null && !isNaN(value.nodeType))
+ {
+ ui.copiedValue = value;
+ }
+ }
+ }, null, null, 'Alt+Shift+B');
+
+ this.addAction('pasteData', function(evt, trigger)
+ {
+ // Context menu click uses trigger, toolbar menu click uses evt
+ var evt = (trigger != null) ? trigger : evt;
+ var model = graph.getModel();
+
+ function applyValue(cell, value)
+ {
+ var old = model.getValue(cell);
+ value = cell.cloneValue(value);
+ value.removeAttribute('placeholders');
+
+ // Carries over placeholders and label properties
+ if (old != null && !isNaN(old.nodeType))
+ {
+ value.setAttribute('placeholders', old.getAttribute('placeholders'));
+ }
+
+ if (evt == null || !mxEvent.isShiftDown(evt))
+ {
+ value.setAttribute('label', graph.convertValueToString(cell));
+ }
+
+ model.setValue(cell, value);
+ };
+
+ if (graph.isEnabled() && !graph.isSelectionEmpty() && ui.copiedValue != null)
+ {
+ model.beginUpdate();
+
+ try
+ {
+ var cells = graph.getEditableCells(graph.getSelectionCells());
+
+ if (cells.length == 0)
+ {
+ applyValue(model.getRoot(), ui.copiedValue);
+ }
+ else
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ applyValue(cells[i], ui.copiedValue);
+ }
+ }
+ }
+ finally
+ {
+ model.endUpdate();
+ }
+ }
+ }, null, null, 'Alt+Shift+E');
+
+ function deleteCells(includeEdges)
+ {
+ // Cancels interactive operations
+ graph.escape();
+ var select = graph.deleteCells(graph.getDeletableCells(graph.getSelectionCells()), includeEdges);
+
+ if (select != null)
+ {
+ graph.setSelectionCells(select);
+ }
+ };
+
+ function deleteLabels()
+ {
+ if (!graph.isSelectionEmpty())
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = graph.getSelectionCells();
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ graph.cellLabelChanged(cells[i], '');
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ };
+
+ this.addAction('delete', function(evt, trigger)
+ {
+ // Context menu click uses trigger, toolbar menu click uses evt
+ var evt = (trigger != null) ? trigger : evt;
+
+ if (evt != null && mxEvent.isShiftDown(evt))
+ {
+ deleteLabels();
+ }
+ else
+ {
+ deleteCells(evt != null && (mxEvent.isControlDown(evt) ||
+ mxEvent.isMetaDown(evt) || mxEvent.isAltDown(evt)));
+ }
+ }, null, null, 'Delete');
+ this.addAction('deleteAll', function()
+ {
+ deleteCells(true);
+ });
+ this.addAction('deleteLabels', function()
+ {
+ deleteLabels();
+ }, null, null, Editor.ctrlKey + '+Delete');
+ this.addAction('duplicate', function()
+ {
+ try
+ {
+ graph.setSelectionCells(graph.duplicateCells());
+ graph.scrollCellToVisible(graph.getSelectionCell());
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }, null, null, Editor.ctrlKey + '+D');
+ this.put('mergeCells', new Action(mxResources.get('merge'), function()
+ {
+ var ss = ui.getSelectionState();
+
+ if (ss.mergeCell != null)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles('rowspan', ss.rowspan, [ss.mergeCell]);
+ graph.setCellStyles('colspan', ss.colspan, [ss.mergeCell]);
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }));
+ this.put('unmergeCells', new Action(mxResources.get('unmerge'), function()
+ {
+ var ss = ui.getSelectionState();
+
+ if (ss.cells.length > 0)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles('rowspan', null, ss.cells);
+ graph.setCellStyles('colspan', null, ss.cells);
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }));
+ this.put('turn', new Action(mxResources.get('turn') + ' / ' + mxResources.get('reverse'), function(evt, trigger)
+ {
+ // Context menu click uses trigger, toolbar menu click uses evt
+ var evt = (trigger != null) ? trigger : evt;
+
+ graph.turnShapes(graph.getResizableCells(graph.getSelectionCells()),
+ (evt != null) ? mxEvent.isShiftDown(evt) : false);
+ }, null, null, (mxClient.IS_SF) ? null : Editor.ctrlKey + '+R'));
+ this.put('selectConnections', new Action(mxResources.get('selectEdges'), function(evt)
+ {
+ var cell = graph.getSelectionCell();
+
+ if (graph.isEnabled() && cell != null)
+ {
+ graph.addSelectionCells(graph.getEdges(cell));
+ }
+ }));
+ this.addAction('selectVertices', function() { graph.selectVertices(null, true); }, null, null, Editor.ctrlKey + '+Shift+I');
+ this.addAction('selectEdges', function() { graph.selectEdges(); }, null, null, Editor.ctrlKey + '+Shift+E');
+ this.addAction('selectAll', function() { graph.selectAll(null, true); }, null, null, Editor.ctrlKey + '+A');
+ this.addAction('selectNone', function() { graph.clearSelection(); }, null, null, Editor.ctrlKey + '+Shift+A');
+ this.addAction('lockUnlock', function()
+ {
+ if (!graph.isSelectionEmpty())
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = graph.getSelectionCells();
+ var style = graph.getCurrentCellStyle(graph.getSelectionCell());
+ var value = (mxUtils.getValue(style, mxConstants.STYLE_EDITABLE, 1)) == 1 ? 0 : 1;
+ graph.setCellStyles(mxConstants.STYLE_MOVABLE, value, cells);
+ graph.setCellStyles(mxConstants.STYLE_RESIZABLE, value, cells);
+ graph.setCellStyles(mxConstants.STYLE_ROTATABLE, value, cells);
+ graph.setCellStyles(mxConstants.STYLE_DELETABLE, value, cells);
+ graph.setCellStyles(mxConstants.STYLE_EDITABLE, value, cells);
+ graph.setCellStyles('locked', (value == 1) ? 0 : 1, cells);
+ graph.setCellStyles('connectable', value, cells);
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }, null, null, Editor.ctrlKey + '+L');
+
+ // Navigation actions
+ this.addAction('home', function() { graph.home(); }, null, null, 'Shift+Home');
+ this.addAction('exitGroup', function() { graph.exitGroup(); }, null, null, Editor.ctrlKey + '+Shift+Home');
+ this.addAction('enterGroup', function() { graph.enterGroup(); }, null, null, Editor.ctrlKey + '+Shift+End');
+ this.addAction('collapse', function() { graph.foldCells(true); }, null, null, Editor.ctrlKey + '+Home');
+ this.addAction('expand', function() { graph.foldCells(false); }, null, null, Editor.ctrlKey + '+End');
+
+ // Arrange actions
+ this.addAction('toFront', function()
+ {
+ graph.orderCells(false);
+ }, null, null, Editor.ctrlKey + '+Shift+F');
+ this.addAction('toBack', function()
+ {
+ graph.orderCells(true);
+ }, null, null, Editor.ctrlKey + '+Shift+B');
+ this.addAction('bringForward', function(evt)
+ {
+ graph.orderCells(false, null, true);
+ });
+ this.addAction('sendBackward', function(evt)
+ {
+ graph.orderCells(true, null, true);
+ });
+ this.addAction('group', function()
+ {
+ if (graph.isEnabled())
+ {
+ var cells = mxUtils.sortCells(graph.getSelectionCells(), true);
+
+ if (cells.length == 1 && !graph.isTable(cells[0]) && !graph.isTableRow(cells[0]))
+ {
+ graph.setCellStyles('container', '1');
+ }
+ else
+ {
+ cells = graph.getCellsForGroup(cells);
+
+ if (cells.length > 1)
+ {
+ graph.setSelectionCell(graph.groupCells(null, 0, cells));
+ }
+ }
+ }
+ }, null, null, Editor.ctrlKey + '+G');
+ this.addAction('ungroup', function()
+ {
+ if (graph.isEnabled())
+ {
+ var cells = graph.getEditableCells(graph.getSelectionCells());
+
+ graph.model.beginUpdate();
+ try
+ {
+ var temp = graph.ungroupCells();
+
+ // Clears container flag for remaining cells
+ if (cells != null)
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (graph.model.contains(cells[i]))
+ {
+ if (graph.model.getChildCount(cells[i]) == 0 &&
+ graph.model.isVertex(cells[i]))
+ {
+ graph.setCellStyles('container', '0', [cells[i]]);
+ }
+
+ temp.push(cells[i]);
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.model.endUpdate();
+ }
+
+ if (temp.length > 0)
+ {
+ graph.setSelectionCells(temp);
+ }
+ }
+ }, null, null, Editor.ctrlKey + '+Shift+U');
+ this.addAction('removeFromGroup', function()
+ {
+ if (graph.isEnabled())
+ {
+ var cells = graph.getSelectionCells();
+
+ // Removes table rows and cells
+ if (cells != null)
+ {
+ var temp = [];
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (!graph.isTableRow(cells[i]) &&
+ !graph.isTableCell(cells[i]))
+ {
+ temp.push(cells[i]);
+ }
+ }
+
+ graph.removeCellsFromParent(temp);
+ }
+ }
+ });
+ // Adds action
+ this.addAction('edit', function()
+ {
+ if (graph.isEnabled())
+ {
+ graph.startEditingAtCell();
+ }
+ }, null, null, 'F2/Enter');
+ this.addAction('editData...', function()
+ {
+ var cell = graph.getSelectionCell() || graph.getModel().getRoot();
+ ui.showDataDialog(cell);
+ }, null, null, Editor.ctrlKey + '+M');
+ this.addAction('editTooltip...', function()
+ {
+ var cell = graph.getSelectionCell();
+
+ if (graph.isEnabled() && cell != null && graph.isCellEditable(cell))
+ {
+ var tooltip = '';
+
+ if (mxUtils.isNode(cell.value))
+ {
+ var tmp = null;
+
+ if (Graph.translateDiagram && Graph.diagramLanguage != null &&
+ cell.value.hasAttribute('tooltip_' + Graph.diagramLanguage))
+ {
+ tmp = cell.value.getAttribute('tooltip_' + Graph.diagramLanguage);
+ }
+
+ if (tmp == null)
+ {
+ tmp = cell.value.getAttribute('tooltip');
+ }
+
+ if (tmp != null)
+ {
+ tooltip = tmp;
+ }
+ }
+
+ var dlg = new TextareaDialog(ui, mxResources.get('editTooltip') + ':', tooltip, function(newValue)
+ {
+ graph.setTooltipForCell(cell, newValue);
+ });
+ ui.showDialog(dlg.container, 320, 200, true, true);
+ dlg.init();
+ }
+ }, null, null, 'Alt+Shift+T');
+ this.addAction('openLink', function()
+ {
+ var link = graph.getLinkForCell(graph.getSelectionCell());
+
+ if (link != null)
+ {
+ graph.openLink(link);
+ }
+ });
+ this.addAction('editLink...', function()
+ {
+ var cell = graph.getSelectionCell();
+
+ if (graph.isEnabled() && cell != null && graph.isCellEditable(cell))
+ {
+ var value = graph.getLinkForCell(cell) || '';
+
+ ui.showLinkDialog(value, mxResources.get('apply'), function(link, docs, linkTarget)
+ {
+ link = mxUtils.trim(link);
+ graph.setLinkForCell(cell, (link.length > 0) ? link : null);
+ graph.setAttributeForCell(cell, 'linkTarget', linkTarget);
+ }, true, graph.getLinkTargetForCell(cell));
+ }
+ }, null, null, 'Alt+Shift+L');
+ this.put('insertImage', new Action(mxResources.get('image') + '...', function()
+ {
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
+ {
+ graph.clearSelection();
+ ui.actions.get('image').funct();
+ }
+ })).isEnabled = isGraphEnabled;
+ this.addAction('editImage...', function()
+ {
+ ui.actions.get('image').funct();
+ });
+ this.put('insertLink', new Action(mxResources.get('link') + '...', function()
+ {
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
+ {
+ ui.showLinkDialog('', mxResources.get('insert'), function(link, docs, linkTarget)
+ {
+ link = mxUtils.trim(link);
+
+ if (link.length > 0)
+ {
+ var icon = null;
+ var title = graph.getLinkTitle(link);
+
+ if (docs != null && docs.length > 0)
+ {
+ icon = docs[0].iconUrl;
+ title = docs[0].name || docs[0].type;
+ title = title.charAt(0).toUpperCase() + title.substring(1);
+
+ if (title.length > 30)
+ {
+ title = title.substring(0, 30) + '...';
+ }
+ }
+
+ var linkCell = new mxCell(title, new mxGeometry(0, 0, 100, 40),
+ 'fontColor=#0000EE;fontStyle=4;rounded=1;overflow=hidden;' + ((icon != null) ?
+ 'shape=label;imageWidth=16;imageHeight=16;spacingLeft=26;align=left;image=' + icon :
+ 'spacing=10;'));
+ linkCell.vertex = true;
+
+ var pt = graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry([linkCell], true));
+ linkCell.geometry.x = pt.x;
+ linkCell.geometry.y = pt.y;
+
+ graph.setAttributeForCell(linkCell, 'linkTarget', linkTarget);
+ graph.setLinkForCell(linkCell, link);
+ graph.cellSizeUpdated(linkCell, true);
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ linkCell = graph.addCell(linkCell);
+ graph.fireEvent(new mxEventObject('cellsInserted', 'cells', [linkCell]));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ graph.setSelectionCell(linkCell);
+ graph.scrollCellToVisible(graph.getSelectionCell());
+ }
+ }, true);
+ }
+ }, null, null, 'L')).isEnabled = isGraphEnabled;
+ this.addAction('link...', mxUtils.bind(this, function()
+ {
+ if (graph.isEnabled())
+ {
+ if (graph.cellEditor.isContentEditing())
+ {
+ var elt = graph.getSelectedElement();
+ var link = graph.getParentByName(elt, 'A', graph.cellEditor.textarea);
+ var oldValue = '';
+
+ // Workaround for FF returning the outermost selected element after double
+ // click on a DOM hierarchy with a link inside (but not as topmost element)
+ if (link == null && elt != null && elt.getElementsByTagName != null)
+ {
+ // Finds all links in the selected DOM and uses the link
+ // where the selection text matches its text content
+ var links = elt.getElementsByTagName('a');
+
+ for (var i = 0; i < links.length && link == null; i++)
+ {
+ if (links[i].textContent == elt.textContent)
+ {
+ link = links[i];
+ }
+ }
+ }
+
+ if (link != null && link.nodeName == 'A')
+ {
+ oldValue = link.getAttribute('href') || '';
+ graph.selectNode(link);
+ }
+
+ var selState = graph.cellEditor.saveSelection();
+
+ ui.showLinkDialog(oldValue, mxResources.get('apply'), mxUtils.bind(this, function(value)
+ {
+ graph.cellEditor.restoreSelection(selState);
+
+ if (value != null)
+ {
+ graph.insertLink(value);
+ }
+ }));
+ }
+ else if (graph.isSelectionEmpty())
+ {
+ this.get('insertLink').funct();
+ }
+ else
+ {
+ this.get('editLink').funct();
+ }
+ }
+ })).isEnabled = isGraphEnabled;
+ this.addAction('autosize', function()
+ {
+ var cells = graph.getSelectionCells();
+
+ if (cells != null)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ var cell = cells[i];
+
+ if (graph.getModel().isVertex(cell))
+ {
+ if (graph.getModel().getChildCount(cell) > 0)
+ {
+ graph.updateGroupBounds([cell], 0, true);
+ }
+ else
+ {
+ graph.updateCellSize(cell);
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }, null, null, Editor.ctrlKey + '+Shift+Y');
+ this.addAction('snapToGrid', function()
+ {
+ graph.snapCellsToGrid(graph.getSelectionCells(), graph.gridSize);
+ });
+ this.addAction('formattedText', function()
+ {
+ graph.stopEditing();
+
+ var style = graph.getCommonStyle(graph.getSelectionCells());
+ var value = (mxUtils.getValue(style, 'html', '0') == '1') ? null : '1';
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = graph.getEditableCells(graph.getSelectionCells());
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ state = graph.getView().getState(cells[i]);
+
+ if (state != null)
+ {
+ var html = mxUtils.getValue(state.style, 'html', '0');
+
+ if (html == '1' && value == null)
+ {
+ graph.removeTextStyleForCell(state.cell);
+ graph.setCellStyles('html', value, [cells[i]]);
+ }
+ else if (html == '0' && value == '1')
+ {
+ // Converts HTML tags to text
+ var label = mxUtils.htmlEntities(graph.convertValueToString(state.cell), false);
+
+ if (mxUtils.getValue(state.style, 'nl2Br', '1') != '0')
+ {
+ // Converts newlines in plain text to breaks in HTML
+ // to match the plain text output
+ label = label.replace(/\n/g, '
');
+ }
+
+ graph.cellLabelChanged(state.cell, Graph.sanitizeHtml(label));
+ graph.setCellStyles('html', value, [cells[i]]);
+ }
+ }
+ }
+
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['html'],
+ 'values', [(value != null) ? value : '0'], 'cells', cells));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('wordWrap', function()
+ {
+ var state = graph.getView().getState(graph.getSelectionCell());
+ var value = 'wrap';
+
+ graph.stopEditing();
+
+ if (state != null && state.style[mxConstants.STYLE_WHITE_SPACE] == 'wrap')
+ {
+ value = null;
+ }
+
+ graph.setCellStyles(mxConstants.STYLE_WHITE_SPACE, value);
+ });
+ this.addAction('rotation', function()
+ {
+ var value = '0';
+ var state = graph.getView().getState(graph.getSelectionCell());
+
+ if (state != null)
+ {
+ value = state.style[mxConstants.STYLE_ROTATION] || value;
+ }
+
+ var dlg = new FilenameDialog(ui, value, mxResources.get('apply'), function(newValue)
+ {
+ if (newValue != null && newValue.length > 0)
+ {
+ graph.setCellStyles(mxConstants.STYLE_ROTATION, newValue);
+ }
+ }, mxResources.get('enterValue') + ' (' + mxResources.get('rotation') + ' 0-360)');
+
+ ui.showDialog(dlg.container, 375, 80, true, true);
+ dlg.init();
+ });
+ // View actions
+ this.addAction('resetView', function()
+ {
+ graph.zoomTo(1);
+ ui.resetScrollbars();
+ }, null, null, 'Enter/Home');
+ this.addAction('zoomIn', function(evt)
+ {
+ if (graph.isFastZoomEnabled())
+ {
+ graph.lazyZoom(true, true, ui.buttonZoomDelay);
+ }
+ else
+ {
+ graph.zoomIn();
+ }
+ }, null, null, Editor.ctrlKey + ' + (Numpad) / Alt+Mousewheel');
+ this.addAction('zoomOut', function(evt)
+ {
+ if (graph.isFastZoomEnabled())
+ {
+ graph.lazyZoom(false, true, ui.buttonZoomDelay);
+ }
+ else
+ {
+ graph.zoomOut();
+ }
+ }, null, null, Editor.ctrlKey + ' - (Numpad) / Alt+Mousewheel');
+ this.addAction('fitWindow', function()
+ {
+ if (graph.pageVisible && graph.isSelectionEmpty())
+ {
+ graph.fitPages();
+ }
+ else
+ {
+ ui.fitDiagramToWindow();
+ }
+ }, null, null, Editor.ctrlKey + '+Shift+H');
+ this.addAction('fitPage', mxUtils.bind(this, function()
+ {
+ if (graph.pageVisible)
+ {
+ graph.fitPages(1);
+ }
+ else
+ {
+ this.get('pageView').funct();
+ }
+ }), null, null, Editor.ctrlKey + '+J');
+ this.addAction('fitTwoPages', mxUtils.bind(this, function()
+ {
+ if (graph.pageVisible)
+ {
+ graph.fitPages(2);
+ }
+ else
+ {
+ this.get('pageView').funct();
+ }
+ }), null, null, Editor.ctrlKey + '+Shift+J');
+ this.addAction('fitPageWidth', mxUtils.bind(this, function()
+ {
+ if (graph.pageVisible)
+ {
+ graph.fitPages(1, true);
+ }
+ else
+ {
+ this.get('pageView').funct();
+ }
+ }));
+ this.put('customZoom', new Action(mxResources.get('custom') + '...', mxUtils.bind(this, function()
+ {
+ var dlg = new FilenameDialog(this.editorUi, parseInt(graph.getView().getScale() * 100), mxResources.get('apply'), mxUtils.bind(this, function(newValue)
+ {
+ var val = parseInt(newValue);
+
+ if (!isNaN(val) && val > 0)
+ {
+ graph.zoomTo(val / 100);
+ }
+ }), mxResources.get('zoom') + ' (%)');
+ this.editorUi.showDialog(dlg.container, 300, 80, true, true);
+ dlg.init();
+ }), null, null, Editor.ctrlKey + '+0'));
+ this.addAction('pageScale...', mxUtils.bind(this, function()
+ {
+ var dlg = new FilenameDialog(this.editorUi, parseInt(graph.pageScale * 100), mxResources.get('apply'), mxUtils.bind(this, function(newValue)
+ {
+ var val = parseInt(newValue);
+
+ if (!isNaN(val) && val > 0)
+ {
+ var change = new ChangePageSetup(ui, null, null, null, val / 100);
+ change.ignoreColor = true;
+ change.ignoreImage = true;
+
+ graph.model.execute(change);
+ }
+ }), mxResources.get('pageScale') + ' (%)');
+ this.editorUi.showDialog(dlg.container, 300, 80, true, true);
+ dlg.init();
+ }));
+
+ // Option actions
+ var action = null;
+ action = this.addAction('grid', function()
+ {
+ graph.setGridEnabled(!graph.isGridEnabled());
+ graph.defaultGridEnabled = graph.isGridEnabled();
+ ui.fireEvent(new mxEventObject('gridEnabledChanged'));
+ }, null, null, Editor.ctrlKey + '+Shift+G');
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.isGridEnabled(); });
+ action.setEnabled(false);
+
+ action = this.addAction('guides', function()
+ {
+ graph.graphHandler.guidesEnabled = !graph.graphHandler.guidesEnabled;
+ ui.fireEvent(new mxEventObject('guidesEnabledChanged'));
+ });
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.graphHandler.guidesEnabled; });
+ action.setEnabled(false);
+
+ action = this.addAction('tooltips', function()
+ {
+ graph.tooltipHandler.setEnabled(!graph.tooltipHandler.isEnabled());
+ ui.fireEvent(new mxEventObject('tooltipsEnabledChanged'));
+ });
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.tooltipHandler.isEnabled(); });
+
+ action = this.addAction('collapseExpand', function()
+ {
+ var change = new ChangePageSetup(ui);
+ change.ignoreColor = true;
+ change.ignoreImage = true;
+ change.foldingEnabled = !graph.foldingEnabled;
+
+ graph.model.execute(change);
+ });
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.foldingEnabled; });
+ action.isEnabled = isGraphEnabled;
+ action = this.addAction('pageView', mxUtils.bind(this, function()
+ {
+ ui.setPageVisible(!graph.pageVisible);
+ }));
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.pageVisible; });
+ action = this.addAction('connectionArrows', function()
+ {
+ graph.connectionArrowsEnabled = !graph.connectionArrowsEnabled;
+ ui.fireEvent(new mxEventObject('connectionArrowsChanged'));
+ }, null, null, 'Alt+Shift+A');
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.connectionArrowsEnabled; });
+ action = this.addAction('connectionPoints', function()
+ {
+ graph.setConnectable(!graph.connectionHandler.isEnabled());
+ ui.fireEvent(new mxEventObject('connectionPointsChanged'));
+ }, null, null, 'Alt+Shift+O');
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.connectionHandler.isEnabled(); });
+ action = this.addAction('copyConnect', function()
+ {
+ graph.connectionHandler.setCreateTarget(!graph.connectionHandler.isCreateTarget());
+ ui.fireEvent(new mxEventObject('copyConnectChanged'));
+ });
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return graph.connectionHandler.isCreateTarget(); });
+ action.isEnabled = isGraphEnabled;
+ action = this.addAction('autosave', function()
+ {
+ ui.editor.setAutosave(!ui.editor.autosave);
+ });
+ action.setToggleAction(true);
+ action.setSelectedCallback(function() { return ui.editor.autosave; });
+ action.isEnabled = isGraphEnabled;
+ action.visible = false;
+
+ // Help actions
+ this.addAction('help', function()
+ {
+ var ext = '';
+
+ if (mxResources.isLanguageSupported(mxClient.language))
+ {
+ ext = '_' + mxClient.language;
+ }
+
+ graph.openLink(RESOURCES_PATH + '/help' + ext + '.html');
+ });
+
+ var showingAbout = false;
+
+ this.put('about', new Action(mxResources.get('about') + ' Graph Editor...', function()
+ {
+ if (!showingAbout)
+ {
+ ui.showDialog(new AboutDialog(ui).container, 320, 280, true, true, function()
+ {
+ showingAbout = false;
+ });
+
+ showingAbout = true;
+ }
+ }));
+
+ // Font style actions
+ var toggleFontStyle = mxUtils.bind(this, function(key, style, fn, shortcut)
+ {
+ return this.addAction(key, function()
+ {
+ if (fn != null && graph.cellEditor.isContentEditing())
+ {
+ fn();
+ }
+ else
+ {
+ graph.stopEditing(false);
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = graph.getEditableCells(graph.getSelectionCells());
+ graph.toggleCellStyleFlags(mxConstants.STYLE_FONTSTYLE, style, cells);
+
+ // Removes bold and italic tags and CSS styles inside labels
+ if ((style & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
+ {
+ graph.updateLabelElements(cells, function(elt)
+ {
+ elt.style.fontWeight = null;
+
+ if (elt.nodeName == 'B')
+ {
+ graph.replaceElement(elt);
+ }
+ });
+ }
+ else if ((style & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
+ {
+ graph.updateLabelElements(cells, function(elt)
+ {
+ elt.style.fontStyle = null;
+
+ if (elt.nodeName == 'I')
+ {
+ graph.replaceElement(elt);
+ }
+ });
+ }
+ else if ((style & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
+ {
+ graph.updateLabelElements(cells, function(elt)
+ {
+ elt.style.textDecoration = null;
+
+ if (elt.nodeName == 'U')
+ {
+ graph.replaceElement(elt);
+ }
+ });
+ }
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (graph.model.getChildCount(cells[i]) == 0)
+ {
+ graph.autoSizeCell(cells[i], false);
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }, null, null, shortcut);
+ });
+
+ toggleFontStyle('bold', mxConstants.FONT_BOLD, function() { document.execCommand('bold', false, null); }, Editor.ctrlKey + '+B');
+ toggleFontStyle('italic', mxConstants.FONT_ITALIC, function() { document.execCommand('italic', false, null); }, Editor.ctrlKey + '+I');
+ toggleFontStyle('underline', mxConstants.FONT_UNDERLINE, function() { document.execCommand('underline', false, null); }, Editor.ctrlKey + '+U');
+
+ // Color actions
+ this.addAction('fontColor...', function() { ui.menus.pickColor(mxConstants.STYLE_FONTCOLOR, 'forecolor', '000000'); });
+ this.addAction('strokeColor...', function() { ui.menus.pickColor(mxConstants.STYLE_STROKECOLOR); });
+ this.addAction('fillColor...', function() { ui.menus.pickColor(mxConstants.STYLE_FILLCOLOR); });
+ this.addAction('gradientColor...', function() { ui.menus.pickColor(mxConstants.STYLE_GRADIENTCOLOR); });
+ this.addAction('backgroundColor...', function() { ui.menus.pickColor(mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, 'backcolor'); });
+ this.addAction('borderColor...', function() { ui.menus.pickColor(mxConstants.STYLE_LABEL_BORDERCOLOR); });
+
+ // Format actions
+ this.addAction('removeFormat', function()
+ {
+ if (graph.isEnabled() && !graph.isSelectionEmpty() && !graph.isEditing())
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = graph.getSelectionCells();
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ graph.removeTextStyleForCell(cells[i], true);
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ });
+ this.addAction('vertical', function() { ui.menus.toggleStyle(mxConstants.STYLE_HORIZONTAL, true); });
+ this.addAction('shadow', function() { ui.menus.toggleStyle(mxConstants.STYLE_SHADOW); });
+ this.addAction('solid', function()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(mxConstants.STYLE_DASHED, null);
+ graph.setCellStyles(mxConstants.STYLE_DASH_PATTERN, null);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
+ 'values', [null, null], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('dashed', function()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(mxConstants.STYLE_DASHED, '1');
+ graph.setCellStyles(mxConstants.STYLE_DASH_PATTERN, null);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
+ 'values', ['1', null], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('dotted', function()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(mxConstants.STYLE_DASHED, '1');
+ graph.setCellStyles(mxConstants.STYLE_DASH_PATTERN, '1 4');
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN],
+ 'values', ['1', '1 4'], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('sharp', function()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(mxConstants.STYLE_ROUNDED, '0');
+ graph.setCellStyles(mxConstants.STYLE_CURVED, '0');
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED],
+ 'values', ['0', '0'], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('rounded', function()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(mxConstants.STYLE_ROUNDED, '1');
+ graph.setCellStyles(mxConstants.STYLE_CURVED, '0');
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED],
+ 'values', ['1', '0'], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('toggleRounded', function()
+ {
+ if (!graph.isSelectionEmpty() && graph.isEnabled())
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = graph.getSelectionCells();
+ var style = graph.getCurrentCellStyle(cells[0]);
+ var value = (mxUtils.getValue(style, mxConstants.STYLE_ROUNDED, '0') == '1') ? '0' : '1';
+
+ graph.setCellStyles(mxConstants.STYLE_ROUNDED, value);
+ graph.setCellStyles(mxConstants.STYLE_CURVED, null);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED],
+ 'values', [value, '0'], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ });
+ this.addAction('curved', function()
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(mxConstants.STYLE_ROUNDED, '0');
+ graph.setCellStyles(mxConstants.STYLE_CURVED, '1');
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED],
+ 'values', ['0', '1'], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+ this.addAction('collapsible', function()
+ {
+ var state = graph.view.getState(graph.getSelectionCell());
+ var value = '1';
+
+ if (state != null && graph.getFoldingImage(state) != null)
+ {
+ value = '0';
+ }
+
+ graph.setCellStyles('collapsible', value);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['collapsible'],
+ 'values', [value], 'cells', graph.getSelectionCells()));
+ });
+ this.addAction('editStyle...', mxUtils.bind(this, function()
+ {
+ var cells = graph.getEditableCells(graph.getSelectionCells());
+
+ if (cells != null && cells.length > 0)
+ {
+ var model = graph.getModel();
+
+ var dlg = new TextareaDialog(this.editorUi, mxResources.get('editStyle') + ':',
+ model.getStyle(cells[0]) || '', function(newValue)
+ {
+ if (newValue != null)
+ {
+ graph.setCellStyle(mxUtils.trim(newValue), cells);
+ }
+ }, null, null, 400, 220);
+ this.editorUi.showDialog(dlg.container, 420, 300, true, true);
+ dlg.init();
+ }
+ }), null, null, Editor.ctrlKey + '+E');
+ this.addAction('setAsDefaultStyle', function()
+ {
+ if (graph.isEnabled() && !graph.isSelectionEmpty())
+ {
+ ui.setDefaultStyle(graph.getSelectionCell());
+ }
+ }, null, null, Editor.ctrlKey + '+Shift+D');
+ this.addAction('clearDefaultStyle', function()
+ {
+ if (graph.isEnabled())
+ {
+ ui.clearDefaultStyle();
+ }
+ }, null, null, Editor.ctrlKey + '+Shift+R');
+ this.addAction('addWaypoint', function()
+ {
+ var cell = graph.getSelectionCell();
+
+ if (cell != null && graph.getModel().isEdge(cell))
+ {
+ var handler = editor.graph.selectionCellsHandler.getHandler(cell);
+
+ if (handler instanceof mxEdgeHandler)
+ {
+ var t = graph.view.translate;
+ var s = graph.view.scale;
+ var dx = t.x;
+ var dy = t.y;
+
+ var parent = graph.getModel().getParent(cell);
+ var pgeo = graph.getCellGeometry(parent);
+
+ while (graph.getModel().isVertex(parent) && pgeo != null)
+ {
+ dx += pgeo.x;
+ dy += pgeo.y;
+
+ parent = graph.getModel().getParent(parent);
+ pgeo = graph.getCellGeometry(parent);
+ }
+
+ var x = Math.round(graph.snap(graph.popupMenuHandler.triggerX / s - dx));
+ var y = Math.round(graph.snap(graph.popupMenuHandler.triggerY / s - dy));
+
+ handler.addPointAt(handler.state, x, y);
+ }
+ }
+ });
+ this.addAction('removeWaypoint', function()
+ {
+ // TODO: Action should run with "this" set to action
+ var rmWaypointAction = ui.actions.get('removeWaypoint');
+
+ if (rmWaypointAction.handler != null)
+ {
+ // NOTE: Popupevent handled and action updated in Menus.createPopupMenu
+ rmWaypointAction.handler.removePoint(rmWaypointAction.handler.state, rmWaypointAction.index);
+ }
+ });
+ this.addAction('clearWaypoints', function(evt, trigger)
+ {
+ // Context menu click uses trigger, toolbar menu click uses evt
+ var evt = (trigger != null) ? trigger : evt;
+ var cells = graph.getSelectionCells();
+
+ if (cells != null)
+ {
+ cells = graph.getEditableCells(graph.addAllEdges(cells));
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ var cell = cells[i];
+
+ if (graph.getModel().isEdge(cell))
+ {
+ var geo = graph.getCellGeometry(cell);
+
+ // Resets fixed connection point
+ if (trigger != null && mxEvent.isShiftDown(evt))
+ {
+ graph.setCellStyles(mxConstants.STYLE_EXIT_X, null, [cell]);
+ graph.setCellStyles(mxConstants.STYLE_EXIT_Y, null, [cell]);
+ graph.setCellStyles(mxConstants.STYLE_ENTRY_X, null, [cell]);
+ graph.setCellStyles(mxConstants.STYLE_ENTRY_Y, null, [cell]);
+ }
+ else if (geo != null)
+ {
+ geo = geo.clone();
+ geo.points = null;
+ geo.x = 0;
+ geo.y = 0;
+ geo.offset = null;
+ graph.getModel().setGeometry(cell, geo);
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ }, null, null, 'Alt+Shift+R');
+ action = this.addAction('subscript', mxUtils.bind(this, function()
+ {
+ if (graph.cellEditor.isContentEditing())
+ {
+ document.execCommand('subscript', false, null);
+ }
+ }), null, null, Editor.ctrlKey + '+,');
+ action = this.addAction('superscript', mxUtils.bind(this, function()
+ {
+ if (graph.cellEditor.isContentEditing())
+ {
+ document.execCommand('superscript', false, null);
+ }
+ }), null, null, Editor.ctrlKey + '+.');
+ action = this.addAction('decreaseFontSize', mxUtils.bind(this, function()
+ {
+ if (!graph.isSelectionEmpty())
+ {
+ var style = graph.getCurrentCellStyle(graph.getSelectionCell());
+ var size = mxUtils.getValue(style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE);
+ graph.setCellStyles(mxConstants.STYLE_FONTSIZE, Math.max(1, size - 1),
+ graph.getSelectionCells());
+ }
+ }), null, null, Editor.ctrlKey + '+Shift + (Numpad)');
+ action = this.addAction('increaseFontSize', mxUtils.bind(this, function()
+ {
+ if (!graph.isSelectionEmpty())
+ {
+ var style = graph.getCurrentCellStyle(graph.getSelectionCell());
+ var size = mxUtils.getValue(style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE);
+ graph.setCellStyles(mxConstants.STYLE_FONTSIZE, Math.min(100, size + 1),
+ graph.getSelectionCells());
+ }
+ }), null, null, Editor.ctrlKey + '+Shift - (Numpad)');
+
+ function applyClipPath(cell, clipPath, width, height, graph)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var geo = graph.getCellGeometry(cell);
+
+ if (geo != null && width && height) //Comparing the ratio mostly will fail since it's float
+ {
+ var scale = width / height;
+ geo = geo.clone();
+
+ if (scale > 1)
+ {
+ geo.height = geo.width / scale;
+ }
+ else
+ {
+ geo.width = geo.height * scale;
+ }
+
+ graph.getModel().setGeometry(cell, geo);
+ }
+
+ graph.setCellStyles(mxConstants.STYLE_CLIP_PATH, clipPath, [cell]); //Set/unset clipPath
+ graph.setCellStyles(mxConstants.STYLE_ASPECT, 'fixed', [cell]);
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ };
+
+ this.addAction('image...', function()
+ {
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()))
+ {
+ var title = mxResources.get('image') + ' (' + mxResources.get('url') + '):';
+ var state = graph.getView().getState(graph.getSelectionCell());
+ var value = '', clipPath = null;
+
+ if (state != null)
+ {
+ value = state.style[mxConstants.STYLE_IMAGE] || value;
+ clipPath = state.style[mxConstants.STYLE_CLIP_PATH] || clipPath;
+ }
+
+ var selectionState = graph.cellEditor.saveSelection();
+
+ ui.showImageDialog(title, value, function(newValue, w, h, clipPath, cW, cH)
+ {
+ // Inserts image into HTML text
+ if (graph.cellEditor.isContentEditing())
+ {
+ graph.cellEditor.restoreSelection(selectionState);
+ graph.insertImage(newValue, w, h);
+ }
+ else
+ {
+ var cells = graph.getSelectionCells();
+
+ if (newValue != null && (newValue.length > 0 || cells.length > 0))
+ {
+ var select = null;
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ // Inserts new cell if no cell is selected
+ if (cells.length == 0)
+ {
+ cells = [graph.insertVertex(graph.getDefaultParent(), null, '', 0, 0, w, h,
+ 'shape=image;imageAspect=0;aspect=fixed;verticalLabelPosition=bottom;verticalAlign=top;')];
+ var pt = graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true));
+ cells[0].geometry.x = pt.x;
+ cells[0].geometry.y = pt.y;
+
+ if (clipPath != null)
+ {
+ applyClipPath(cells[0], clipPath, cW, cH, graph);
+ }
+
+ select = cells;
+ graph.fireEvent(new mxEventObject('cellsInserted', 'cells', select));
+ }
+
+ graph.setCellStyles(mxConstants.STYLE_IMAGE, (newValue.length > 0) ? newValue : null, cells);
+
+ // Sets shape only if not already shape with image (label or image)
+ var style = graph.getCurrentCellStyle(cells[0]);
+
+ if (style[mxConstants.STYLE_SHAPE] != 'image' && style[mxConstants.STYLE_SHAPE] != 'label')
+ {
+ graph.setCellStyles(mxConstants.STYLE_SHAPE, 'image', cells);
+ }
+ else if (newValue.length == 0)
+ {
+ graph.setCellStyles(mxConstants.STYLE_SHAPE, null, cells);
+ }
+
+ if (clipPath == null)
+ {
+ graph.setCellStyles(mxConstants.STYLE_CLIP_PATH, null, cells); //Reset clip path
+ }
+
+ if (w != null && h != null)
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ var cell = cells[i];
+
+ if (graph.getCurrentCellStyle(cell)['expand'] != '0')
+ {
+ var geo = graph.getModel().getGeometry(cell);
+
+ if (geo != null)
+ {
+ geo = geo.clone();
+ geo.width = w;
+ geo.height = h;
+ graph.getModel().setGeometry(cell, geo);
+ }
+ }
+
+ if (clipPath != null)
+ {
+ applyClipPath(cell, clipPath, cW, cH, graph);
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ if (select != null)
+ {
+ graph.setSelectionCells(select);
+ graph.scrollCellToVisible(select[0]);
+ }
+ }
+ }
+ }, graph.cellEditor.isContentEditing(), !graph.cellEditor.isContentEditing(), true, clipPath);
+ }
+ }).isEnabled = isGraphEnabled;
+
+ this.addAction('crop...', function()
+ {
+ var cell = graph.getSelectionCell();
+
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()) && cell != null)
+ {
+ var style = graph.getCurrentCellStyle(cell);
+
+ var value = style[mxConstants.STYLE_IMAGE], shape = style[mxConstants.STYLE_SHAPE];
+
+ if (!value || shape != 'image')
+ {
+ return; //Can only process an existing image
+ }
+
+ var dlg = new CropImageDialog(ui, value, style[mxConstants.STYLE_CLIP_PATH], function(clipPath, width, height)
+ {
+ applyClipPath(cell, clipPath, width, height, graph);
+ });
+
+ ui.showDialog(dlg.container, 300, 390, true, true);
+ }
+ }).isEnabled = isGraphEnabled;
+ action = this.addAction('layers', mxUtils.bind(this, function()
+ {
+ if (this.layersWindow == null)
+ {
+ // LATER: Check outline window for initial placement
+ this.layersWindow = new LayersWindow(ui, document.body.offsetWidth - 280, 120, 212, 200);
+ this.layersWindow.window.addListener('show', mxUtils.bind(this, function()
+ {
+ ui.fireEvent(new mxEventObject('layers'));
+ }));
+ this.layersWindow.window.addListener('hide', function()
+ {
+ ui.fireEvent(new mxEventObject('layers'));
+ });
+ this.layersWindow.window.setVisible(true);
+ ui.fireEvent(new mxEventObject('layers'));
+
+ this.layersWindow.init();
+ }
+ else
+ {
+ this.layersWindow.window.setVisible(!this.layersWindow.window.isVisible());
+ }
+ }), null, null, Editor.ctrlKey + '+Shift+L');
+ action.setToggleAction(true);
+ action.setSelectedCallback(mxUtils.bind(this, function() { return this.layersWindow != null && this.layersWindow.window.isVisible(); }));
+ action = this.addAction('format', mxUtils.bind(this, function()
+ {
+ ui.toggleFormatPanel();
+ }), null, null, Editor.ctrlKey + '+Shift+P');
+ action.setToggleAction(true);
+ action.setSelectedCallback(mxUtils.bind(this, function() { return ui.isFormatPanelVisible(); }));
+ action = this.addAction('outline', mxUtils.bind(this, function()
+ {
+ if (this.outlineWindow == null)
+ {
+ // LATER: Check layers window for initial placement
+ this.outlineWindow = new OutlineWindow(ui, document.body.offsetWidth - 260, 100, 180, 180);
+ this.outlineWindow.window.addListener('show', mxUtils.bind(this, function()
+ {
+ ui.fireEvent(new mxEventObject('outline'));
+ }));
+ this.outlineWindow.window.addListener('hide', function()
+ {
+ ui.fireEvent(new mxEventObject('outline'));
+ });
+ this.outlineWindow.window.setVisible(true);
+ ui.fireEvent(new mxEventObject('outline'));
+ }
+ else
+ {
+ this.outlineWindow.window.setVisible(!this.outlineWindow.window.isVisible());
+ }
+ }), null, null, Editor.ctrlKey + '+Shift+O');
+
+ action.setToggleAction(true);
+ action.setSelectedCallback(mxUtils.bind(this, function() { return this.outlineWindow != null && this.outlineWindow.window.isVisible(); }));
+
+ this.addAction('editConnectionPoints...', function()
+ {
+ var cell = graph.getSelectionCell();
+
+ if (graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent()) && cell != null)
+ {
+ var dlg = new ConnectionPointsDialog(ui, cell);
+ ui.showDialog(dlg.container, 350, 450, true, false, function()
+ {
+ dlg.destroy();
+ });
+ dlg.init();
+ }
+ }, null, null, 'Alt+Shift+Q').isEnabled = isGraphEnabled;
+};
+
+/**
+ * Registers the given action under the given name.
+ */
+Actions.prototype.addAction = function(key, funct, enabled, iconCls, shortcut)
+{
+ var title;
+
+ if (key.substring(key.length - 3) == '...')
+ {
+ key = key.substring(0, key.length - 3);
+ title = mxResources.get(key) + '...';
+ }
+ else
+ {
+ title = mxResources.get(key);
+ }
+
+ return this.put(key, new Action(title, funct, enabled, iconCls, shortcut));
+};
+
+/**
+ * Registers the given action under the given name.
+ */
+Actions.prototype.put = function(name, action)
+{
+ this.actions[name] = action;
+
+ return action;
+};
+
+/**
+ * Returns the action for the given name or null if no such action exists.
+ */
+Actions.prototype.get = function(name)
+{
+ return this.actions[name];
+};
+
+/**
+ * Constructs a new action for the given parameters.
+ */
+function Action(label, funct, enabled, iconCls, shortcut)
+{
+ mxEventSource.call(this);
+ this.label = label;
+ this.funct = this.createFunction(funct);
+ this.enabled = (enabled != null) ? enabled : true;
+ this.iconCls = iconCls;
+ this.shortcut = shortcut;
+ this.visible = true;
+};
+
+// Action inherits from mxEventSource
+mxUtils.extend(Action, mxEventSource);
+
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.createFunction = function(funct)
+{
+ return funct;
+};
+
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.setEnabled = function(value)
+{
+ if (this.enabled != value)
+ {
+ this.enabled = value;
+ this.fireEvent(new mxEventObject('stateChanged'));
+ }
+};
+
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.isEnabled = function()
+{
+ return this.enabled;
+};
+
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.setToggleAction = function(value)
+{
+ this.toggleAction = value;
+};
+
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.setSelectedCallback = function(funct)
+{
+ this.selectedCallback = funct;
+};
+
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.isSelected = function()
+{
+ return this.selectedCallback();
+};
diff --git a/static/cherry/drawio_demo/Dialogs.js b/static/cherry/drawio_demo/Dialogs.js
new file mode 100644
index 000000000..17306dc6f
--- /dev/null
+++ b/static/cherry/drawio_demo/Dialogs.js
@@ -0,0 +1,2755 @@
+/**
+ * Copyright (c) 2006-2012, JGraph Ltd
+ */
+/**
+ * Constructs a new open dialog.
+ */
+var OpenDialog = function()
+{
+ var iframe = document.createElement('iframe');
+ iframe.style.backgroundColor = 'transparent';
+ iframe.allowTransparency = 'true';
+ iframe.style.borderStyle = 'none';
+ iframe.style.borderWidth = '0px';
+ iframe.style.overflow = 'hidden';
+ iframe.style.maxWidth = '100%';
+ iframe.frameBorder = '0';
+
+ var dx = 0;
+ iframe.setAttribute('width', (((Editor.useLocalStorage) ? 640 : 320) + dx) + 'px');
+ iframe.setAttribute('height', (((Editor.useLocalStorage) ? 480 : 220) + dx) + 'px');
+ iframe.setAttribute('src', OPEN_FORM);
+
+ this.container = iframe;
+};
+
+/**
+ * Constructs a new color dialog.
+ */
+var ColorDialog = function(editorUi, color, apply, cancelFn)
+{
+ this.editorUi = editorUi;
+
+ var input = document.createElement('input');
+ input.style.marginBottom = '10px';
+
+ // Required for picker to render in IE
+ if (mxClient.IS_IE)
+ {
+ input.style.marginTop = '10px';
+ document.body.appendChild(input);
+ }
+
+ var applyFunction = (apply != null) ? apply : this.createApplyFunction();
+
+ function doApply()
+ {
+ var color = input.value;
+
+ // Blocks any non-alphabetic chars in colors
+ if (/(^#?[a-zA-Z0-9]*$)/.test(color))
+ {
+ if (color != 'none' && color.charAt(0) != '#')
+ {
+ color = '#' + color;
+ }
+
+ ColorDialog.addRecentColor((color != 'none') ? color.substring(1) : color, 12);
+ applyFunction(color);
+ editorUi.hideDialog();
+ }
+ else
+ {
+ editorUi.handleError({message: mxResources.get('invalidInput')});
+ }
+ };
+
+ this.init = function()
+ {
+ if (!mxClient.IS_TOUCH)
+ {
+ input.focus();
+ }
+ };
+
+ var picker = new mxJSColor.color(input);
+ picker.pickerOnfocus = false;
+ picker.showPicker();
+
+ var div = document.createElement('div');
+ mxJSColor.picker.box.style.position = 'relative';
+ mxJSColor.picker.box.style.width = '230px';
+ mxJSColor.picker.box.style.height = '100px';
+ mxJSColor.picker.box.style.paddingBottom = '10px';
+ div.appendChild(mxJSColor.picker.box);
+
+ var center = document.createElement('center');
+
+ function createRecentColorTable()
+ {
+ var table = addPresets((ColorDialog.recentColors.length == 0) ? ['FFFFFF'] :
+ ColorDialog.recentColors, 11, 'FFFFFF', true);
+ table.style.marginBottom = '8px';
+
+ return table;
+ };
+
+ var addPresets = mxUtils.bind(this, function(presets, rowLength, defaultColor, addResetOption)
+ {
+ rowLength = (rowLength != null) ? rowLength : 12;
+ var table = document.createElement('table');
+ table.style.borderCollapse = 'collapse';
+ table.setAttribute('cellspacing', '0');
+ table.style.marginBottom = '20px';
+ table.style.cellSpacing = '0px';
+ table.style.marginLeft = '1px';
+ var tbody = document.createElement('tbody');
+ table.appendChild(tbody);
+
+ var rows = presets.length / rowLength;
+
+ for (var row = 0; row < rows; row++)
+ {
+ var tr = document.createElement('tr');
+
+ for (var i = 0; i < rowLength; i++)
+ {
+ (mxUtils.bind(this, function(clr)
+ {
+ var td = document.createElement('td');
+ td.style.border = '0px solid black';
+ td.style.padding = '0px';
+ td.style.width = '16px';
+ td.style.height = '16px';
+
+ if (clr == null)
+ {
+ clr = defaultColor;
+ }
+
+ if (clr != null)
+ {
+ td.style.borderWidth = '1px';
+
+ if (clr == 'none')
+ {
+ td.style.background = 'url(\'' + Dialog.prototype.noColorImage + '\')';
+ }
+ else
+ {
+ td.style.backgroundColor = '#' + clr;
+ }
+
+ var name = this.colorNames[clr.toUpperCase()];
+
+ if (name != null)
+ {
+ td.setAttribute('title', name);
+ }
+ }
+
+ tr.appendChild(td);
+
+ if (clr != null)
+ {
+ td.style.cursor = 'pointer';
+
+ mxEvent.addListener(td, 'click', function()
+ {
+ if (clr == 'none')
+ {
+ picker.fromString('ffffff');
+ input.value = 'none';
+ }
+ else
+ {
+ picker.fromString(clr);
+ }
+ });
+
+ mxEvent.addListener(td, 'dblclick', doApply);
+ }
+ }))(presets[row * rowLength + i]);
+ }
+
+ tbody.appendChild(tr);
+ }
+
+ if (addResetOption)
+ {
+ var td = document.createElement('td');
+ td.setAttribute('title', mxResources.get('reset'));
+ td.style.border = '1px solid black';
+ td.style.padding = '0px';
+ td.style.width = '16px';
+ td.style.height = '16px';
+ td.style.backgroundImage = 'url(\'' + Dialog.prototype.closeImage + '\')';
+ td.style.backgroundPosition = 'center center';
+ td.style.backgroundRepeat = 'no-repeat';
+ td.style.cursor = 'pointer';
+
+ tr.appendChild(td);
+
+ mxEvent.addListener(td, 'click', function()
+ {
+ ColorDialog.resetRecentColors();
+ table.parentNode.replaceChild(createRecentColorTable(), table);
+ });
+ }
+
+ center.appendChild(table);
+
+ return table;
+ });
+
+ div.appendChild(input);
+
+ if (!mxClient.IS_IE && !mxClient.IS_IE11)
+ {
+ input.style.width = '182px';
+
+ var clrInput = document.createElement('input');
+ clrInput.setAttribute('type', 'color');
+ clrInput.style.position = 'relative';
+ clrInput.style.visibility = 'hidden';
+ clrInput.style.top = '10px';
+ clrInput.style.width = '0px';
+ clrInput.style.height = '0px';
+ clrInput.style.border = 'none';
+
+ div.style.whiteSpace = 'nowrap';
+ div.appendChild(clrInput);
+
+ var dropperBtn = mxUtils.button('', function()
+ {
+ // LATER: Check if clrInput is expanded
+ if (document.activeElement == clrInput)
+ {
+ input.focus();
+ }
+ else
+ {
+ clrInput.value = '#' + input.value;
+ clrInput.click();
+ }
+ });
+
+ var dropper = document.createElement('img');
+ dropper.src = Editor.colorDropperImage;
+ dropper.className = 'geAdaptiveAsset';
+ dropper.style.position = 'relative';
+ dropper.style.verticalAlign = 'middle';
+ dropper.style.width = 'auto';
+ dropper.style.height = '14px';
+
+ dropperBtn.appendChild(dropper);
+ div.appendChild(dropperBtn);
+
+ mxEvent.addListener(clrInput, 'change', function()
+ {
+ picker.fromString(clrInput.value.substring(1));
+ });
+ }
+ else
+ {
+ input.style.width = '216px';
+ }
+
+ mxUtils.br(div);
+
+ // Adds recent colors
+ createRecentColorTable();
+
+ // Adds presets
+ var table = addPresets(this.presetColors);
+ table.style.marginBottom = '8px';
+ table = addPresets(this.defaultColors);
+ table.style.marginBottom = '16px';
+
+ div.appendChild(center);
+
+ var buttons = document.createElement('div');
+ buttons.style.textAlign = 'right';
+ buttons.style.whiteSpace = 'nowrap';
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+
+ if (cancelFn != null)
+ {
+ cancelFn();
+ }
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ buttons.appendChild(cancelBtn);
+ }
+
+ var applyBtn = mxUtils.button(mxResources.get('apply'), doApply);
+ applyBtn.className = 'geBtn gePrimaryBtn';
+ buttons.appendChild(applyBtn);
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ buttons.appendChild(cancelBtn);
+ }
+
+ if (color != null)
+ {
+ if (color == 'none')
+ {
+ picker.fromString('ffffff');
+ input.value = 'none';
+ }
+ else
+ {
+ picker.fromString(color);
+ }
+ }
+
+ div.appendChild(buttons);
+ this.picker = picker;
+ this.colorInput = input;
+
+ // LATER: Only fires if input if focused, should always
+ // fire if this dialog is showing.
+ mxEvent.addListener(div, 'keydown', function(e)
+ {
+ if (e.keyCode == 27)
+ {
+ editorUi.hideDialog();
+
+ if (cancelFn != null)
+ {
+ cancelFn();
+ }
+
+ mxEvent.consume(e);
+ }
+ });
+
+ this.container = div;
+};
+
+/**
+ * Creates function to apply value
+ */
+ColorDialog.prototype.presetColors = ['E6D0DE', 'CDA2BE', 'B5739D', 'E1D5E7', 'C3ABD0', 'A680B8', 'D4E1F5', 'A9C4EB', '7EA6E0', 'D5E8D4', '9AC7BF', '67AB9F', 'D5E8D4', 'B9E0A5', '97D077', 'FFF2CC', 'FFE599', 'FFD966', 'FFF4C3', 'FFCE9F', 'FFB570', 'F8CECC', 'F19C99', 'EA6B66'];
+
+/**
+ * Creates function to apply value
+ */
+ ColorDialog.prototype.colorNames = {};
+
+/**
+ * Creates function to apply value
+ */
+ColorDialog.prototype.defaultColors = ['none', 'FFFFFF', 'E6E6E6', 'CCCCCC', 'B3B3B3', '999999', '808080', '666666', '4D4D4D', '333333', '1A1A1A', '000000', 'FFCCCC', 'FFE6CC', 'FFFFCC', 'E6FFCC', 'CCFFCC', 'CCFFE6', 'CCFFFF', 'CCE5FF', 'CCCCFF', 'E5CCFF', 'FFCCFF', 'FFCCE6',
+ 'FF9999', 'FFCC99', 'FFFF99', 'CCFF99', '99FF99', '99FFCC', '99FFFF', '99CCFF', '9999FF', 'CC99FF', 'FF99FF', 'FF99CC', 'FF6666', 'FFB366', 'FFFF66', 'B3FF66', '66FF66', '66FFB3', '66FFFF', '66B2FF', '6666FF', 'B266FF', 'FF66FF', 'FF66B3', 'FF3333', 'FF9933', 'FFFF33',
+ '99FF33', '33FF33', '33FF99', '33FFFF', '3399FF', '3333FF', '9933FF', 'FF33FF', 'FF3399', 'FF0000', 'FF8000', 'FFFF00', '80FF00', '00FF00', '00FF80', '00FFFF', '007FFF', '0000FF', '7F00FF', 'FF00FF', 'FF0080', 'CC0000', 'CC6600', 'CCCC00', '66CC00', '00CC00', '00CC66',
+ '00CCCC', '0066CC', '0000CC', '6600CC', 'CC00CC', 'CC0066', '990000', '994C00', '999900', '4D9900', '009900', '00994D', '009999', '004C99', '000099', '4C0099', '990099', '99004D', '660000', '663300', '666600', '336600', '006600', '006633', '006666', '003366', '000066',
+ '330066', '660066', '660033', '330000', '331A00', '333300', '1A3300', '003300', '00331A', '003333', '001933', '000033', '190033', '330033', '33001A'];
+
+/**
+ * Creates function to apply value
+ */
+ColorDialog.prototype.createApplyFunction = function()
+{
+ return mxUtils.bind(this, function(color)
+ {
+ var graph = this.editorUi.editor.graph;
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles(this.currentColorKey, color);
+ this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [this.currentColorKey],
+ 'values', [color], 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ });
+};
+
+/**
+ *
+ */
+ColorDialog.recentColors = [];
+
+/**
+ * Adds recent color for later use.
+ */
+ColorDialog.addRecentColor = function(color, max)
+{
+ if (color != null)
+ {
+ mxUtils.remove(color, ColorDialog.recentColors);
+ ColorDialog.recentColors.splice(0, 0, color);
+
+ if (ColorDialog.recentColors.length >= max)
+ {
+ ColorDialog.recentColors.pop();
+ }
+ }
+};
+
+/**
+ * Adds recent color for later use.
+ */
+ColorDialog.resetRecentColors = function()
+{
+ ColorDialog.recentColors = [];
+};
+
+/**
+ * Constructs a new about dialog.
+ */
+var AboutDialog = function(editorUi)
+{
+ var div = document.createElement('div');
+ div.setAttribute('align', 'center');
+ var h3 = document.createElement('h3');
+ mxUtils.write(h3, mxResources.get('about') + ' GraphEditor');
+ div.appendChild(h3);
+ var img = document.createElement('img');
+ img.style.border = '0px';
+ img.setAttribute('width', '176');
+ img.setAttribute('width', '151');
+ img.setAttribute('src', IMAGE_PATH + '/logo.png');
+ div.appendChild(img);
+ mxUtils.br(div);
+ mxUtils.write(div, 'Powered by mxGraph ' + mxClient.VERSION);
+ mxUtils.br(div);
+ var link = document.createElement('a');
+ link.setAttribute('href', 'http://www.jgraph.com/');
+ link.setAttribute('target', '_blank');
+ mxUtils.write(link, 'www.jgraph.com');
+ div.appendChild(link);
+ mxUtils.br(div);
+ mxUtils.br(div);
+ var closeBtn = mxUtils.button(mxResources.get('close'), function()
+ {
+ editorUi.hideDialog();
+ });
+ closeBtn.className = 'geBtn gePrimaryBtn';
+ div.appendChild(closeBtn);
+
+ this.container = div;
+};
+
+/**
+ * Constructs a new textarea dialog.
+ */
+var TextareaDialog = function(editorUi, title, url, fn, cancelFn, cancelTitle, w, h,
+ addButtons, noHide, noWrap, applyTitle, helpLink, customButtons, header)
+{
+ w = (w != null) ? w : 300;
+ h = (h != null) ? h : 120;
+ noHide = (noHide != null) ? noHide : false;
+
+ var div = document.createElement('div');
+ div.style.position = 'absolute';
+ div.style.top = '20px';
+ div.style.bottom = '20px';
+ div.style.left = '20px';
+ div.style.right = '20px';
+
+ var top = document.createElement('div');
+
+ top.style.position = 'absolute';
+ top.style.left = '0px';
+ top.style.right = '0px';
+
+ var main = top.cloneNode(false);
+ var buttons = top.cloneNode(false);
+
+ top.style.top = '0px';
+ top.style.height = '20px';
+ main.style.top = '20px';
+ main.style.bottom = '64px';
+ buttons.style.bottom = '0px';
+ buttons.style.height = '60px';
+ buttons.style.textAlign = 'center';
+
+ mxUtils.write(top, title);
+
+ div.appendChild(top);
+ div.appendChild(main);
+ div.appendChild(buttons);
+
+ if (header != null)
+ {
+ top.appendChild(header);
+ }
+
+ var nameInput = document.createElement('textarea');
+
+ if (noWrap)
+ {
+ nameInput.setAttribute('wrap', 'off');
+ }
+
+ nameInput.setAttribute('spellcheck', 'false');
+ nameInput.setAttribute('autocorrect', 'off');
+ nameInput.setAttribute('autocomplete', 'off');
+ nameInput.setAttribute('autocapitalize', 'off');
+
+ mxUtils.write(nameInput, url || '');
+ nameInput.style.resize = 'none';
+ nameInput.style.outline = 'none';
+ nameInput.style.position = 'absolute';
+ nameInput.style.boxSizing = 'border-box';
+ nameInput.style.top = '0px';
+ nameInput.style.left = '0px';
+ nameInput.style.height = '100%';
+ nameInput.style.width = '100%';
+
+ this.textarea = nameInput;
+
+ this.init = function()
+ {
+ nameInput.focus();
+ nameInput.scrollTop = 0;
+ };
+
+ main.appendChild(nameInput);
+
+ if (helpLink != null)
+ {
+ var helpBtn = mxUtils.button(mxResources.get('help'), function()
+ {
+ editorUi.editor.graph.openLink(helpLink);
+ });
+ helpBtn.className = 'geBtn';
+
+ buttons.appendChild(helpBtn);
+ }
+
+ if (customButtons != null)
+ {
+ for (var i = 0; i < customButtons.length; i++)
+ {
+ (function(label, fn, title)
+ {
+ var customBtn = mxUtils.button(label, function(e)
+ {
+ fn(e, nameInput);
+ });
+
+ if (title != null)
+ {
+ customBtn.setAttribute('title', title);
+ }
+
+ customBtn.className = 'geBtn';
+
+ buttons.appendChild(customBtn);
+ })(customButtons[i][0], customButtons[i][1], customButtons[i][2]);
+ }
+ }
+
+ var cancelBtn = mxUtils.button(cancelTitle || mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+
+ if (cancelFn != null)
+ {
+ cancelFn();
+ }
+ });
+
+ cancelBtn.setAttribute('title', 'Escape');
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ buttons.appendChild(cancelBtn);
+ }
+
+ if (addButtons != null)
+ {
+ addButtons(buttons, nameInput);
+ }
+
+ if (fn != null)
+ {
+ var genericBtn = mxUtils.button(applyTitle || mxResources.get('apply'), function()
+ {
+ if (!noHide)
+ {
+ editorUi.hideDialog();
+ }
+
+ fn(nameInput.value);
+ });
+
+ genericBtn.setAttribute('title', 'Ctrl+Enter');
+ genericBtn.className = 'geBtn gePrimaryBtn';
+ buttons.appendChild(genericBtn);
+
+ mxEvent.addListener(nameInput, 'keypress', function(e)
+ {
+ if (e.keyCode == 13 && mxEvent.isControlDown(e))
+ {
+ genericBtn.click();
+ }
+ });
+ }
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ buttons.appendChild(cancelBtn);
+ }
+
+ this.container = div;
+};
+
+/**
+ * Constructs a new edit file dialog.
+ */
+var EditDiagramDialog = function(editorUi)
+{
+ var div = document.createElement('div');
+ div.style.textAlign = 'right';
+ var textarea = document.createElement('textarea');
+ textarea.setAttribute('wrap', 'off');
+ textarea.setAttribute('spellcheck', 'false');
+ textarea.setAttribute('autocorrect', 'off');
+ textarea.setAttribute('autocomplete', 'off');
+ textarea.setAttribute('autocapitalize', 'off');
+ textarea.style.overflow = 'auto';
+ textarea.style.resize = 'none';
+ textarea.style.width = '600px';
+ textarea.style.height = '360px';
+ textarea.style.marginBottom = '16px';
+
+ textarea.value = mxUtils.getPrettyXml(editorUi.editor.getGraphXml());
+ div.appendChild(textarea);
+
+ this.init = function()
+ {
+ textarea.focus();
+ };
+
+ // Enables dropping files
+ if (Graph.fileSupport)
+ {
+ function handleDrop(evt)
+ {
+ evt.stopPropagation();
+ evt.preventDefault();
+
+ if (evt.dataTransfer.files.length > 0)
+ {
+ var file = evt.dataTransfer.files[0];
+ var reader = new FileReader();
+
+ reader.onload = function(e)
+ {
+ textarea.value = e.target.result;
+ };
+
+ reader.readAsText(file);
+ }
+ else
+ {
+ textarea.value = editorUi.extractGraphModelFromEvent(evt);
+ }
+ };
+
+ function handleDragOver(evt)
+ {
+ evt.stopPropagation();
+ evt.preventDefault();
+ };
+
+ // Setup the dnd listeners.
+ textarea.addEventListener('dragover', handleDragOver, false);
+ textarea.addEventListener('drop', handleDrop, false);
+ }
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ div.appendChild(cancelBtn);
+ }
+
+ var select = document.createElement('select');
+ select.style.width = '180px';
+ select.className = 'geBtn';
+
+ if (editorUi.editor.graph.isEnabled())
+ {
+ var replaceOption = document.createElement('option');
+ replaceOption.setAttribute('value', 'replace');
+ mxUtils.write(replaceOption, mxResources.get('replaceExistingDrawing'));
+ select.appendChild(replaceOption);
+ }
+
+ var newOption = document.createElement('option');
+ newOption.setAttribute('value', 'new');
+ mxUtils.write(newOption, mxResources.get('openInNewWindow'));
+
+ if (EditDiagramDialog.showNewWindowOption)
+ {
+ select.appendChild(newOption);
+ }
+
+ if (editorUi.editor.graph.isEnabled())
+ {
+ var importOption = document.createElement('option');
+ importOption.setAttribute('value', 'import');
+ mxUtils.write(importOption, mxResources.get('addToExistingDrawing'));
+ select.appendChild(importOption);
+ }
+
+ div.appendChild(select);
+
+ var okBtn = mxUtils.button(mxResources.get('ok'), function()
+ {
+ // Removes all illegal control characters before parsing
+ var data = Graph.zapGremlins(mxUtils.trim(textarea.value));
+ var error = null;
+
+ if (select.value == 'new')
+ {
+ editorUi.hideDialog();
+ editorUi.editor.editAsNew(data);
+ }
+ else if (select.value == 'replace')
+ {
+ editorUi.editor.graph.model.beginUpdate();
+ try
+ {
+ editorUi.editor.setGraphXml(mxUtils.parseXml(data).documentElement);
+ // LATER: Why is hideDialog between begin-/endUpdate faster?
+ editorUi.hideDialog();
+ }
+ catch (e)
+ {
+ error = e;
+ }
+ finally
+ {
+ editorUi.editor.graph.model.endUpdate();
+ }
+ }
+ else if (select.value == 'import')
+ {
+ editorUi.editor.graph.model.beginUpdate();
+ try
+ {
+ var doc = mxUtils.parseXml(data);
+ var model = new mxGraphModel();
+ var codec = new mxCodec(doc);
+ codec.decode(doc.documentElement, model);
+
+ var children = model.getChildren(model.getChildAt(model.getRoot(), 0));
+ editorUi.editor.graph.setSelectionCells(editorUi.editor.graph.importCells(children));
+
+ // LATER: Why is hideDialog between begin-/endUpdate faster?
+ editorUi.hideDialog();
+ }
+ catch (e)
+ {
+ error = e;
+ }
+ finally
+ {
+ editorUi.editor.graph.model.endUpdate();
+ }
+ }
+
+ if (error != null)
+ {
+ mxUtils.alert(error.message);
+ }
+ });
+ okBtn.className = 'geBtn gePrimaryBtn';
+ div.appendChild(okBtn);
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ div.appendChild(cancelBtn);
+ }
+
+ this.container = div;
+};
+
+/**
+ *
+ */
+EditDiagramDialog.showNewWindowOption = true;
+
+/**
+ * Constructs a new export dialog.
+ */
+var ExportDialog = function(editorUi)
+{
+ var graph = editorUi.editor.graph;
+ var bounds = graph.getGraphBounds();
+ var scale = graph.view.scale;
+
+ var width = Math.ceil(bounds.width / scale);
+ var height = Math.ceil(bounds.height / scale);
+
+ var row, td;
+
+ var table = document.createElement('table');
+ var tbody = document.createElement('tbody');
+ table.setAttribute('cellpadding', (mxClient.IS_SF) ? '0' : '2');
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ td.style.width = '100px';
+ mxUtils.write(td, mxResources.get('filename') + ':');
+
+ row.appendChild(td);
+
+ var nameInput = document.createElement('input');
+ nameInput.setAttribute('value', editorUi.editor.getOrCreateFilename());
+ nameInput.style.width = '180px';
+
+ td = document.createElement('td');
+ td.appendChild(nameInput);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('format') + ':');
+
+ row.appendChild(td);
+
+ var imageFormatSelect = document.createElement('select');
+ imageFormatSelect.style.width = '180px';
+
+ var pngOption = document.createElement('option');
+ pngOption.setAttribute('value', 'png');
+ mxUtils.write(pngOption, mxResources.get('formatPng'));
+ imageFormatSelect.appendChild(pngOption);
+
+ var gifOption = document.createElement('option');
+
+ if (ExportDialog.showGifOption)
+ {
+ gifOption.setAttribute('value', 'gif');
+ mxUtils.write(gifOption, mxResources.get('formatGif'));
+ imageFormatSelect.appendChild(gifOption);
+ }
+
+ var jpgOption = document.createElement('option');
+ jpgOption.setAttribute('value', 'jpg');
+ mxUtils.write(jpgOption, mxResources.get('formatJpg'));
+ imageFormatSelect.appendChild(jpgOption);
+
+ if (!editorUi.printPdfExport)
+ {
+ var pdfOption = document.createElement('option');
+ pdfOption.setAttribute('value', 'pdf');
+ mxUtils.write(pdfOption, mxResources.get('formatPdf'));
+ imageFormatSelect.appendChild(pdfOption);
+ }
+
+ var svgOption = document.createElement('option');
+ svgOption.setAttribute('value', 'svg');
+ mxUtils.write(svgOption, mxResources.get('formatSvg'));
+ imageFormatSelect.appendChild(svgOption);
+
+ if (ExportDialog.showXmlOption)
+ {
+ var xmlOption = document.createElement('option');
+ xmlOption.setAttribute('value', 'xml');
+ mxUtils.write(xmlOption, mxResources.get('formatXml'));
+ imageFormatSelect.appendChild(xmlOption);
+ }
+
+ td = document.createElement('td');
+ td.appendChild(imageFormatSelect);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('zoom') + ' (%):');
+
+ row.appendChild(td);
+
+ var zoomInput = document.createElement('input');
+ zoomInput.setAttribute('type', 'number');
+ zoomInput.setAttribute('value', '100');
+ zoomInput.style.width = '180px';
+
+ td = document.createElement('td');
+ td.appendChild(zoomInput);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('width') + ':');
+
+ row.appendChild(td);
+
+ var widthInput = document.createElement('input');
+ widthInput.setAttribute('value', width);
+ widthInput.style.width = '180px';
+
+ td = document.createElement('td');
+ td.appendChild(widthInput);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('height') + ':');
+
+ row.appendChild(td);
+
+ var heightInput = document.createElement('input');
+ heightInput.setAttribute('value', height);
+ heightInput.style.width = '180px';
+
+ td = document.createElement('td');
+ td.appendChild(heightInput);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('dpi') + ':');
+
+ row.appendChild(td);
+
+ var dpiSelect = document.createElement('select');
+ dpiSelect.style.width = '180px';
+
+ var dpi100Option = document.createElement('option');
+ dpi100Option.setAttribute('value', '100');
+ mxUtils.write(dpi100Option, '100dpi');
+ dpiSelect.appendChild(dpi100Option);
+
+ var dpi200Option = document.createElement('option');
+ dpi200Option.setAttribute('value', '200');
+ mxUtils.write(dpi200Option, '200dpi');
+ dpiSelect.appendChild(dpi200Option);
+
+ var dpi300Option = document.createElement('option');
+ dpi300Option.setAttribute('value', '300');
+ mxUtils.write(dpi300Option, '300dpi');
+ dpiSelect.appendChild(dpi300Option);
+
+ var dpi400Option = document.createElement('option');
+ dpi400Option.setAttribute('value', '400');
+ mxUtils.write(dpi400Option, '400dpi');
+ dpiSelect.appendChild(dpi400Option);
+
+ var dpiCustOption = document.createElement('option');
+ dpiCustOption.setAttribute('value', 'custom');
+ mxUtils.write(dpiCustOption, mxResources.get('custom'));
+ dpiSelect.appendChild(dpiCustOption);
+
+ var customDpi = document.createElement('input');
+ customDpi.style.width = '180px';
+ customDpi.style.display = 'none';
+ customDpi.setAttribute('value', '100');
+ customDpi.setAttribute('type', 'number');
+ customDpi.setAttribute('min', '50');
+ customDpi.setAttribute('step', '50');
+
+ var zoomUserChanged = false;
+
+ mxEvent.addListener(dpiSelect, 'change', function()
+ {
+ if (this.value == 'custom')
+ {
+ this.style.display = 'none';
+ customDpi.style.display = '';
+ customDpi.focus();
+ }
+ else
+ {
+ customDpi.value = this.value;
+
+ if (!zoomUserChanged)
+ {
+ zoomInput.value = this.value;
+ }
+ }
+ });
+
+ mxEvent.addListener(customDpi, 'change', function()
+ {
+ var dpi = parseInt(customDpi.value);
+
+ if (isNaN(dpi) || dpi <= 0)
+ {
+ customDpi.style.backgroundColor = 'red';
+ }
+ else
+ {
+ customDpi.style.backgroundColor = '';
+
+ if (!zoomUserChanged)
+ {
+ zoomInput.value = dpi;
+ }
+ }
+ });
+
+ td = document.createElement('td');
+ td.appendChild(dpiSelect);
+ td.appendChild(customDpi);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('background') + ':');
+
+ row.appendChild(td);
+
+ var transparentCheckbox = document.createElement('input');
+ transparentCheckbox.setAttribute('type', 'checkbox');
+ transparentCheckbox.checked = graph.background == null || graph.background == mxConstants.NONE;
+
+ td = document.createElement('td');
+ td.appendChild(transparentCheckbox);
+ mxUtils.write(td, mxResources.get('transparent'));
+
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('grid') + ':');
+
+ row.appendChild(td);
+
+ var gridCheckbox = document.createElement('input');
+ gridCheckbox.setAttribute('type', 'checkbox');
+ gridCheckbox.checked = false;
+
+ td = document.createElement('td');
+ td.appendChild(gridCheckbox);
+
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('borderWidth') + ':');
+
+ row.appendChild(td);
+
+ var borderInput = document.createElement('input');
+ borderInput.setAttribute('type', 'number');
+ borderInput.setAttribute('value', ExportDialog.lastBorderValue);
+ borderInput.style.width = '180px';
+
+ td = document.createElement('td');
+ td.appendChild(borderInput);
+ row.appendChild(td);
+
+ tbody.appendChild(row);
+ table.appendChild(tbody);
+
+ // Handles changes in the export format
+ function formatChanged()
+ {
+ var name = nameInput.value;
+ var dot = name.lastIndexOf('.');
+
+ if (dot > 0)
+ {
+ nameInput.value = name.substring(0, dot + 1) + imageFormatSelect.value;
+ }
+ else
+ {
+ nameInput.value = name + '.' + imageFormatSelect.value;
+ }
+
+ if (imageFormatSelect.value === 'xml')
+ {
+ zoomInput.setAttribute('disabled', 'true');
+ widthInput.setAttribute('disabled', 'true');
+ heightInput.setAttribute('disabled', 'true');
+ borderInput.setAttribute('disabled', 'true');
+ }
+ else
+ {
+ zoomInput.removeAttribute('disabled');
+ widthInput.removeAttribute('disabled');
+ heightInput.removeAttribute('disabled');
+ borderInput.removeAttribute('disabled');
+ }
+
+ if (imageFormatSelect.value === 'png' || imageFormatSelect.value === 'svg' || imageFormatSelect.value === 'pdf')
+ {
+ transparentCheckbox.removeAttribute('disabled');
+ }
+ else
+ {
+ transparentCheckbox.setAttribute('disabled', 'disabled');
+ }
+
+ if (imageFormatSelect.value === 'png' || imageFormatSelect.value === 'jpg' || imageFormatSelect.value === 'pdf')
+ {
+ gridCheckbox.removeAttribute('disabled');
+ }
+ else
+ {
+ gridCheckbox.setAttribute('disabled', 'disabled');
+ }
+
+ if (imageFormatSelect.value === 'png')
+ {
+ dpiSelect.removeAttribute('disabled');
+ customDpi.removeAttribute('disabled');
+ }
+ else
+ {
+ dpiSelect.setAttribute('disabled', 'disabled');
+ customDpi.setAttribute('disabled', 'disabled');
+ }
+ };
+
+ mxEvent.addListener(imageFormatSelect, 'change', formatChanged);
+ formatChanged();
+
+ function checkValues()
+ {
+ if (widthInput.value * heightInput.value > MAX_AREA || widthInput.value <= 0)
+ {
+ widthInput.style.backgroundColor = 'red';
+ }
+ else
+ {
+ widthInput.style.backgroundColor = '';
+ }
+
+ if (widthInput.value * heightInput.value > MAX_AREA || heightInput.value <= 0)
+ {
+ heightInput.style.backgroundColor = 'red';
+ }
+ else
+ {
+ heightInput.style.backgroundColor = '';
+ }
+ };
+
+ mxEvent.addListener(zoomInput, 'change', function()
+ {
+ zoomUserChanged = true;
+ var s = Math.max(0, parseFloat(zoomInput.value) || 100) / 100;
+ zoomInput.value = parseFloat((s * 100).toFixed(2));
+
+ if (width > 0)
+ {
+ widthInput.value = Math.floor(width * s);
+ heightInput.value = Math.floor(height * s);
+ }
+ else
+ {
+ zoomInput.value = '100';
+ widthInput.value = width;
+ heightInput.value = height;
+ }
+
+ checkValues();
+ });
+
+ mxEvent.addListener(widthInput, 'change', function()
+ {
+ var s = parseInt(widthInput.value) / width;
+
+ if (s > 0)
+ {
+ zoomInput.value = parseFloat((s * 100).toFixed(2));
+ heightInput.value = Math.floor(height * s);
+ }
+ else
+ {
+ zoomInput.value = '100';
+ widthInput.value = width;
+ heightInput.value = height;
+ }
+
+ checkValues();
+ });
+
+ mxEvent.addListener(heightInput, 'change', function()
+ {
+ var s = parseInt(heightInput.value) / height;
+
+ if (s > 0)
+ {
+ zoomInput.value = parseFloat((s * 100).toFixed(2));
+ widthInput.value = Math.floor(width * s);
+ }
+ else
+ {
+ zoomInput.value = '100';
+ widthInput.value = width;
+ heightInput.value = height;
+ }
+
+ checkValues();
+ });
+
+ row = document.createElement('tr');
+ td = document.createElement('td');
+ td.setAttribute('align', 'right');
+ td.style.paddingTop = '22px';
+ td.colSpan = 2;
+
+ var saveBtn = mxUtils.button(mxResources.get('export'), mxUtils.bind(this, function()
+ {
+ if (parseInt(zoomInput.value) <= 0)
+ {
+ mxUtils.alert(mxResources.get('drawingEmpty'));
+ }
+ else
+ {
+ var name = nameInput.value;
+ var format = imageFormatSelect.value;
+ var s = Math.max(0, parseFloat(zoomInput.value) || 100) / 100;
+ var b = Math.max(0, parseInt(borderInput.value));
+ var bg = graph.background;
+ var dpi = Math.max(1, parseInt(customDpi.value));
+
+ if ((format == 'svg' || format == 'png' || format == 'pdf') && transparentCheckbox.checked)
+ {
+ bg = null;
+ }
+ else if (bg == null || bg == mxConstants.NONE)
+ {
+ bg = '#ffffff';
+ }
+
+ ExportDialog.lastBorderValue = b;
+ ExportDialog.exportFile(editorUi, name, format, bg, s, b, dpi, gridCheckbox.checked);
+ }
+ }));
+ saveBtn.className = 'geBtn gePrimaryBtn';
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ td.appendChild(saveBtn);
+ }
+ else
+ {
+ td.appendChild(saveBtn);
+ td.appendChild(cancelBtn);
+ }
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+ table.appendChild(tbody);
+ this.container = table;
+};
+
+/**
+ * Remembers last value for border.
+ */
+ExportDialog.lastBorderValue = 0;
+
+/**
+ * Global switches for the export dialog.
+ */
+ExportDialog.showGifOption = true;
+
+/**
+ * Global switches for the export dialog.
+ */
+ExportDialog.showXmlOption = true;
+
+/**
+ * Hook for getting the export format. Returns null for the default
+ * intermediate XML export format or a function that returns the
+ * parameter and value to be used in the request in the form
+ * key=value, where value should be URL encoded.
+ */
+ExportDialog.exportFile = function(editorUi, name, format, bg, s, b, dpi, grid)
+{
+ var graph = editorUi.editor.graph;
+
+ if (format == 'xml')
+ {
+ ExportDialog.saveLocalFile(editorUi, mxUtils.getXml(editorUi.editor.getGraphXml()), name, format);
+ }
+ else if (format == 'svg')
+ {
+ ExportDialog.saveLocalFile(editorUi, mxUtils.getXml(graph.getSvg(bg, s, b)), name, format);
+ }
+ else
+ {
+ var bounds = graph.getGraphBounds();
+
+ // New image export
+ var xmlDoc = mxUtils.createXmlDocument();
+ var root = xmlDoc.createElement('output');
+ xmlDoc.appendChild(root);
+
+ // Renders graph. Offset will be multiplied with state's scale when painting state.
+ var xmlCanvas = new mxXmlCanvas2D(root);
+ xmlCanvas.translate(Math.floor((b / s - bounds.x) / graph.view.scale),
+ Math.floor((b / s - bounds.y) / graph.view.scale));
+ xmlCanvas.scale(s / graph.view.scale);
+
+ var imgExport = new mxImageExport()
+ imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
+
+ // Puts request data together
+ var param = 'xml=' + encodeURIComponent(mxUtils.getXml(root));
+ var w = Math.ceil(bounds.width * s / graph.view.scale + 2 * b);
+ var h = Math.ceil(bounds.height * s / graph.view.scale + 2 * b);
+
+ // Requests image if request is valid
+ if (param.length <= MAX_REQUEST_SIZE && w * h < MAX_AREA)
+ {
+ editorUi.hideDialog();
+ var req = new mxXmlRequest(EXPORT_URL, 'format=' + format +
+ '&filename=' + encodeURIComponent(name) +
+ '&bg=' + ((bg != null) ? bg : 'none') +
+ '&w=' + w + '&h=' + h + '&' + param +
+ '&dpi=' + dpi);
+ req.simulate(document, '_blank');
+ }
+ else
+ {
+ mxUtils.alert(mxResources.get('drawingTooLarge'));
+ }
+ }
+};
+
+/**
+ * Hook for getting the export format. Returns null for the default
+ * intermediate XML export format or a function that returns the
+ * parameter and value to be used in the request in the form
+ * key=value, where value should be URL encoded.
+ */
+ExportDialog.saveLocalFile = function(editorUi, data, filename, format)
+{
+ if (data.length < MAX_REQUEST_SIZE)
+ {
+ editorUi.hideDialog();
+ var req = new mxXmlRequest(SAVE_URL, 'xml=' + encodeURIComponent(data) + '&filename=' +
+ encodeURIComponent(filename) + '&format=' + format);
+ req.simulate(document, '_blank');
+ }
+ else
+ {
+ mxUtils.alert(mxResources.get('drawingTooLarge'));
+ mxUtils.popup(xml);
+ }
+};
+
+/**
+ * Constructs a new metadata dialog.
+ */
+var EditDataDialog = function(ui, cell)
+{
+ var div = document.createElement('div');
+ var graph = ui.editor.graph;
+
+ var value = graph.getModel().getValue(cell);
+
+ // Converts the value to an XML node
+ if (!mxUtils.isNode(value))
+ {
+ var doc = mxUtils.createXmlDocument();
+ var obj = doc.createElement('object');
+ obj.setAttribute('label', value || '');
+ value = obj;
+ }
+
+ var meta = {};
+
+ try
+ {
+ var temp = mxUtils.getValue(ui.editor.graph.getCurrentCellStyle(cell), 'metaData', null);
+
+ if (temp != null)
+ {
+ meta = JSON.parse(temp);
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ // Creates the dialog contents
+ var form = new mxForm('properties');
+ form.table.style.width = '100%';
+
+ var attrs = value.attributes;
+ var names = [];
+ var texts = [];
+ var count = 0;
+
+ var id = (EditDataDialog.getDisplayIdForCell != null) ?
+ EditDataDialog.getDisplayIdForCell(ui, cell) : null;
+
+ var addRemoveButton = function(text, name)
+ {
+ var wrapper = document.createElement('div');
+ wrapper.style.position = 'relative';
+ wrapper.style.paddingRight = '20px';
+ wrapper.style.boxSizing = 'border-box';
+ wrapper.style.width = '100%';
+
+ var removeAttr = document.createElement('a');
+ var img = mxUtils.createImage(Dialog.prototype.closeImage);
+ img.style.height = '9px';
+ img.style.fontSize = '9px';
+ img.style.marginBottom = (mxClient.IS_IE11) ? '-1px' : '5px';
+
+ removeAttr.className = 'geButton';
+ removeAttr.setAttribute('title', mxResources.get('delete'));
+ removeAttr.style.position = 'absolute';
+ removeAttr.style.top = '4px';
+ removeAttr.style.right = '0px';
+ removeAttr.style.margin = '0px';
+ removeAttr.style.width = '9px';
+ removeAttr.style.height = '9px';
+ removeAttr.style.cursor = 'pointer';
+ removeAttr.appendChild(img);
+
+ var removeAttrFn = (function(name)
+ {
+ return function()
+ {
+ var count = 0;
+
+ for (var j = 0; j < names.length; j++)
+ {
+ if (names[j] == name)
+ {
+ texts[j] = null;
+ form.table.deleteRow(count + ((id != null) ? 1 : 0));
+
+ break;
+ }
+
+ if (texts[j] != null)
+ {
+ count++;
+ }
+ }
+ };
+ })(name);
+
+ mxEvent.addListener(removeAttr, 'click', removeAttrFn);
+
+ var parent = text.parentNode;
+ wrapper.appendChild(text);
+ wrapper.appendChild(removeAttr);
+ parent.appendChild(wrapper);
+ };
+
+ var addTextArea = function(index, name, value)
+ {
+ names[index] = name;
+ texts[index] = form.addTextarea(names[count] + ':', value, 2);
+ texts[index].style.width = '100%';
+
+ if (value.indexOf('\n') > 0)
+ {
+ texts[index].setAttribute('rows', '2');
+ }
+
+ addRemoveButton(texts[index], name);
+
+ if (meta[name] != null && meta[name].editable == false)
+ {
+ texts[index].setAttribute('disabled', 'disabled');
+ }
+ };
+
+ var temp = [];
+ var isLayer = graph.getModel().getParent(cell) == graph.getModel().getRoot();
+
+ for (var i = 0; i < attrs.length; i++)
+ {
+ if ((attrs[i].nodeName != 'label' || Graph.translateDiagram ||
+ isLayer) && attrs[i].nodeName != 'placeholders')
+ {
+ temp.push({name: attrs[i].nodeName, value: attrs[i].nodeValue});
+ }
+ }
+
+ // Sorts by name
+ temp.sort(function(a, b)
+ {
+ if (a.name < b.name)
+ {
+ return -1;
+ }
+ else if (a.name > b.name)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ });
+
+ if (id != null)
+ {
+ var text = document.createElement('div');
+ text.style.width = '100%';
+ text.style.fontSize = '11px';
+ text.style.textAlign = 'center';
+ mxUtils.write(text, id);
+
+ var idInput = form.addField(mxResources.get('id') + ':', text);
+
+ mxEvent.addListener(text, 'dblclick', function(evt)
+ {
+ var dlg = new FilenameDialog(ui, id, mxResources.get('apply'), mxUtils.bind(this, function(value)
+ {
+ if (value != null && value.length > 0 && value != id)
+ {
+ if (graph.model.isRoot(cell))
+ {
+ var page = ui.getPageById(id);
+
+ if (page != null)
+ {
+ if (ui.getPageById(value) == null)
+ {
+ var index = ui.getPageIndex(page);
+
+ if (index >= 0)
+ {
+ ui.removePage(page);
+ page.node.setAttribute('id', value);
+ id = value;
+ idInput.innerHTML = mxUtils.htmlEntities(value);
+ ui.insertPage(page, index);
+ }
+ }
+ else
+ {
+ ui.handleError({message: mxResources.get('alreadyExst', [mxResources.get('page')])});
+ }
+ }
+ }
+ else
+ {
+ if (graph.getModel().getCell(value) == null)
+ {
+ graph.getModel().cellRemoved(cell);
+ cell.setId(value);
+ id = value;
+ idInput.innerHTML = mxUtils.htmlEntities(value);
+ graph.getModel().cellAdded(cell);
+ }
+ else
+ {
+ ui.handleError({message: mxResources.get('alreadyExst', [value])});
+ }
+ }
+ }
+ }), mxResources.get('id'), null, null, null, null, null, null, 200);
+ ui.showDialog(dlg.container, 300, 80, true, true);
+ dlg.init();
+ });
+ }
+
+ for (var i = 0; i < temp.length; i++)
+ {
+ addTextArea(count, temp[i].name, temp[i].value);
+ count++;
+ }
+
+ var top = document.createElement('div');
+ top.style.position = 'absolute';
+ top.style.top = '30px';
+ top.style.left = '30px';
+ top.style.right = '30px';
+ top.style.bottom = '80px';
+ top.style.overflowY = 'auto';
+
+ top.appendChild(form.table);
+
+ var newProp = document.createElement('div');
+ newProp.style.display = 'flex';
+ newProp.style.alignItems = 'center';
+ newProp.style.boxSizing = 'border-box';
+ newProp.style.paddingRight = '160px';
+ newProp.style.whiteSpace = 'nowrap';
+ newProp.style.marginTop = '6px';
+ newProp.style.width = '100%';
+
+ var nameInput = document.createElement('input');
+ nameInput.setAttribute('placeholder', mxResources.get('enterPropertyName'));
+ nameInput.setAttribute('type', 'text');
+ nameInput.setAttribute('size', (mxClient.IS_IE || mxClient.IS_IE11) ? '36' : '40');
+ nameInput.style.boxSizing = 'border-box';
+ nameInput.style.borderWidth = '1px';
+ nameInput.style.borderStyle = 'solid';
+ nameInput.style.marginLeft = '2px';
+ nameInput.style.padding = '4px';
+ nameInput.style.width = '100%';
+
+ newProp.appendChild(nameInput);
+ top.appendChild(newProp);
+ div.appendChild(top);
+
+ var addBtn = mxUtils.button(mxResources.get('addProperty'), function()
+ {
+ var name = nameInput.value;
+
+ // Avoid ':' in attribute names which seems to be valid in Chrome
+ if (name.length > 0 && name != 'label' && name != 'id' &&
+ name != 'placeholders' && name.indexOf(':') < 0)
+ {
+ try
+ {
+ var idx = mxUtils.indexOf(names, name);
+
+ if (idx >= 0 && texts[idx] != null)
+ {
+ texts[idx].focus();
+ }
+ else
+ {
+ // Checks if the name is valid
+ var clone = value.cloneNode(false);
+ clone.setAttribute(name, '');
+
+ if (idx >= 0)
+ {
+ names.splice(idx, 1);
+ texts.splice(idx, 1);
+ }
+
+ names.push(name);
+ var text = form.addTextarea(name + ':', '', 2);
+ text.style.width = '100%';
+ texts.push(text);
+ addRemoveButton(text, name);
+
+ text.focus();
+ }
+
+ addBtn.setAttribute('disabled', 'disabled');
+ nameInput.value = '';
+ }
+ catch (e)
+ {
+ mxUtils.alert(e);
+ }
+ }
+ else
+ {
+ mxUtils.alert(mxResources.get('invalidName'));
+ }
+ });
+
+ mxEvent.addListener(nameInput, 'keypress', function(e)
+ {
+ if (e.keyCode == 13 )
+ {
+ addBtn.click();
+ }
+ });
+
+ this.init = function()
+ {
+ if (texts.length > 0)
+ {
+ texts[0].focus();
+ }
+ else
+ {
+ nameInput.focus();
+ }
+ };
+
+ addBtn.setAttribute('title', mxResources.get('addProperty'));
+ addBtn.setAttribute('disabled', 'disabled');
+ addBtn.style.textOverflow = 'ellipsis';
+ addBtn.style.position = 'absolute';
+ addBtn.style.overflow = 'hidden';
+ addBtn.style.width = '144px';
+ addBtn.style.right = '0px';
+ addBtn.className = 'geBtn';
+ newProp.appendChild(addBtn);
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ ui.hideDialog.apply(ui, arguments);
+ });
+
+ cancelBtn.setAttribute('title', 'Escape');
+ cancelBtn.className = 'geBtn';
+
+ var exportBtn = mxUtils.button(mxResources.get('export'), mxUtils.bind(this, function(evt)
+ {
+ var result = graph.getDataForCells([cell]);
+
+ var dlg = new EmbedDialog(ui, JSON.stringify(result, null, 2), null, null, function()
+ {
+ console.log(result);
+ ui.alert('Written to Console (Dev Tools)');
+ }, mxResources.get('export'), null, 'Console', 'data.json');
+ ui.showDialog(dlg.container, 450, 240, true, true);
+ dlg.init();
+ }));
+
+ exportBtn.setAttribute('title', mxResources.get('export'));
+ exportBtn.className = 'geBtn';
+
+ var applyBtn = mxUtils.button(mxResources.get('apply'), function()
+ {
+ try
+ {
+ ui.hideDialog.apply(ui, arguments);
+
+ // Clones and updates the value
+ value = value.cloneNode(true);
+ var removeLabel = false;
+
+ for (var i = 0; i < names.length; i++)
+ {
+ if (texts[i] == null)
+ {
+ value.removeAttribute(names[i]);
+ }
+ else
+ {
+ value.setAttribute(names[i], texts[i].value);
+ removeLabel = removeLabel || (names[i] == 'placeholder' &&
+ value.getAttribute('placeholders') == '1');
+ }
+ }
+
+ // Removes label if placeholder is assigned
+ if (removeLabel)
+ {
+ value.removeAttribute('label');
+ }
+
+ // Updates the value of the cell (undoable)
+ graph.getModel().setValue(cell, value);
+ }
+ catch (e)
+ {
+ mxUtils.alert(e);
+ }
+ });
+
+ applyBtn.setAttribute('title', 'Ctrl+Enter');
+ applyBtn.className = 'geBtn gePrimaryBtn';
+
+ mxEvent.addListener(div, 'keypress', function(e)
+ {
+ if (e.keyCode == 13 && mxEvent.isControlDown(e))
+ {
+ applyBtn.click();
+ }
+ });
+
+ function updateAddBtn()
+ {
+ if (nameInput.value.length > 0)
+ {
+ addBtn.removeAttribute('disabled');
+ }
+ else
+ {
+ addBtn.setAttribute('disabled', 'disabled');
+ }
+ };
+
+ mxEvent.addListener(nameInput, 'keyup', updateAddBtn);
+
+ // Catches all changes that don't fire a keyup (such as paste via mouse)
+ mxEvent.addListener(nameInput, 'change', updateAddBtn);
+
+ var buttons = document.createElement('div');
+ buttons.style.cssText = 'position:absolute;left:30px;right:30px;text-align:right;bottom:30px;height:40px;'
+
+ if (ui.editor.graph.getModel().isVertex(cell) || ui.editor.graph.getModel().isEdge(cell))
+ {
+ var replace = document.createElement('span');
+ replace.style.marginRight = '10px';
+ var input = document.createElement('input');
+ input.setAttribute('type', 'checkbox');
+ input.style.marginRight = '6px';
+
+ if (value.getAttribute('placeholders') == '1')
+ {
+ input.setAttribute('checked', 'checked');
+ input.defaultChecked = true;
+ }
+
+ mxEvent.addListener(input, 'click', function()
+ {
+ if (value.getAttribute('placeholders') == '1')
+ {
+ value.removeAttribute('placeholders');
+ }
+ else
+ {
+ value.setAttribute('placeholders', '1');
+ }
+ });
+
+ replace.appendChild(input);
+ mxUtils.write(replace, mxResources.get('placeholders'));
+
+ if (EditDataDialog.placeholderHelpLink != null)
+ {
+ var link = document.createElement('a');
+ link.setAttribute('href', EditDataDialog.placeholderHelpLink);
+ link.setAttribute('title', mxResources.get('help'));
+ link.setAttribute('target', '_blank');
+ link.style.marginLeft = '8px';
+ link.style.cursor = 'help';
+
+ var icon = document.createElement('img');
+ mxUtils.setOpacity(icon, 50);
+ icon.style.height = '16px';
+ icon.style.width = '16px';
+ icon.setAttribute('border', '0');
+ icon.setAttribute('valign', 'middle');
+ icon.style.marginTop = (mxClient.IS_IE11) ? '0px' : '-4px';
+ icon.setAttribute('src', Editor.helpImage);
+ link.appendChild(icon);
+
+ replace.appendChild(link);
+ }
+
+ buttons.appendChild(replace);
+ }
+
+ if (ui.editor.cancelFirst)
+ {
+ buttons.appendChild(cancelBtn);
+ }
+
+ buttons.appendChild(exportBtn);
+ buttons.appendChild(applyBtn);
+
+ if (!ui.editor.cancelFirst)
+ {
+ buttons.appendChild(cancelBtn);
+ }
+
+ div.appendChild(buttons);
+ this.container = div;
+};
+
+/**
+ * Optional help link.
+ */
+EditDataDialog.getDisplayIdForCell = function(ui, cell)
+{
+ var id = null;
+
+ if (ui.editor.graph.getModel().getParent(cell) != null)
+ {
+ id = cell.getId();
+ }
+
+ return id;
+};
+
+/**
+ * Optional help link.
+ */
+EditDataDialog.placeholderHelpLink = null;
+
+/**
+ * Constructs a new link dialog.
+ */
+var LinkDialog = function(editorUi, initialValue, btnLabel, fn)
+{
+ var div = document.createElement('div');
+ mxUtils.write(div, mxResources.get('editLink') + ':');
+
+ var inner = document.createElement('div');
+ inner.className = 'geTitle';
+ inner.style.backgroundColor = 'transparent';
+ inner.style.borderColor = 'transparent';
+ inner.style.whiteSpace = 'nowrap';
+ inner.style.textOverflow = 'clip';
+ inner.style.cursor = 'default';
+ inner.style.paddingRight = '20px';
+
+ var linkInput = document.createElement('input');
+ linkInput.setAttribute('value', initialValue);
+ linkInput.setAttribute('placeholder', 'http://www.example.com/');
+ linkInput.setAttribute('type', 'text');
+ linkInput.style.marginTop = '6px';
+ linkInput.style.width = '400px';
+ linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')';
+ linkInput.style.backgroundRepeat = 'no-repeat';
+ linkInput.style.backgroundPosition = '100% 50%';
+ linkInput.style.paddingRight = '14px';
+
+ var cross = document.createElement('div');
+ cross.setAttribute('title', mxResources.get('reset'));
+ cross.style.position = 'relative';
+ cross.style.left = '-16px';
+ cross.style.width = '12px';
+ cross.style.height = '14px';
+ cross.style.cursor = 'pointer';
+
+ // Workaround for inline-block not supported in IE
+ cross.style.display = 'inline-block';
+ cross.style.top = '3px';
+
+ // Needed to block event transparency in IE
+ cross.style.background = 'url(' + IMAGE_PATH + '/transparent.gif)';
+
+ mxEvent.addListener(cross, 'click', function()
+ {
+ linkInput.value = '';
+ linkInput.focus();
+ });
+
+ inner.appendChild(linkInput);
+ inner.appendChild(cross);
+ div.appendChild(inner);
+
+ this.init = function()
+ {
+ linkInput.focus();
+
+ if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
+ {
+ linkInput.select();
+ }
+ else
+ {
+ document.execCommand('selectAll', false, null);
+ }
+ };
+
+ var btns = document.createElement('div');
+ btns.style.marginTop = '18px';
+ btns.style.textAlign = 'right';
+
+ mxEvent.addListener(linkInput, 'keypress', function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ editorUi.hideDialog();
+ fn(linkInput.value);
+ }
+ });
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ btns.appendChild(cancelBtn);
+ }
+
+ var mainBtn = mxUtils.button(btnLabel, function()
+ {
+ editorUi.hideDialog();
+ fn(linkInput.value);
+ });
+ mainBtn.className = 'geBtn gePrimaryBtn';
+ btns.appendChild(mainBtn);
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ btns.appendChild(cancelBtn);
+ }
+
+ div.appendChild(btns);
+
+ this.container = div;
+};
+
+/**
+ *
+ */
+var OutlineWindow = function(editorUi, x, y, w, h)
+{
+ var graph = editorUi.editor.graph;
+
+ var div = document.createElement('div');
+ div.style.position = 'absolute';
+ div.style.width = '100%';
+ div.style.height = '100%';
+ div.style.overflow = 'hidden';
+
+ this.window = new mxWindow(mxResources.get('outline'), div, x, y, w, h, true, true);
+ this.window.minimumSize = new mxRectangle(0, 0, 80, 80);
+ this.window.destroyOnClose = false;
+ this.window.setMaximizable(false);
+ this.window.setResizable(true);
+ this.window.setClosable(true);
+ this.window.setVisible(true);
+
+ var outline = editorUi.createOutline(this.window);
+
+ editorUi.installResizeHandler(this, true, function()
+ {
+ outline.destroy();
+ });
+
+ this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
+ {
+ this.window.fit();
+ outline.setSuspended(false);
+ }));
+
+ this.window.addListener(mxEvent.HIDE, mxUtils.bind(this, function()
+ {
+ outline.setSuspended(true);
+ }));
+
+ this.window.addListener(mxEvent.NORMALIZE, mxUtils.bind(this, function()
+ {
+ outline.setSuspended(false);
+ }));
+
+ this.window.addListener(mxEvent.MINIMIZE, mxUtils.bind(this, function()
+ {
+ outline.setSuspended(true);
+ }));
+
+ outline.init(div);
+
+ mxEvent.addMouseWheelListener(function(evt, up)
+ {
+ var outlineWheel = false;
+ var source = mxEvent.getSource(evt);
+
+ while (source != null)
+ {
+ if (source == outline.svg)
+ {
+ outlineWheel = true;
+ break;
+ }
+
+ source = source.parentNode;
+ }
+
+ if (outlineWheel)
+ {
+ var factor = graph.zoomFactor;
+
+ // Slower zoom for pinch gesture on trackpad
+ if (evt.deltaY != null && Math.round(evt.deltaY) != evt.deltaY)
+ {
+ factor = 1 + (Math.abs(evt.deltaY) / 20) * (factor - 1);
+ }
+
+ graph.lazyZoom(up, null, null, factor);
+ mxEvent.consume(evt);
+ }
+ });
+};
+
+/**
+ *
+ */
+var LayersWindow = function(editorUi, x, y, w, h)
+{
+ var graph = editorUi.editor.graph;
+
+ var div = document.createElement('div');
+ div.className = 'geBackground';
+ div.style.userSelect = 'none';
+ div.style.border = '1px solid whiteSmoke';
+ div.style.height = '100%';
+ div.style.marginBottom = '10px';
+ div.style.overflow = 'auto';
+
+ var tbarHeight = (!EditorUi.compactUi) ? '30px' : '26px';
+
+ var listDiv = document.createElement('div')
+ listDiv.className = 'geBackground';
+ listDiv.style.position = 'absolute';
+ listDiv.style.overflow = 'auto';
+ listDiv.style.left = '0px';
+ listDiv.style.right = '0px';
+ listDiv.style.top = '0px';
+ listDiv.style.bottom = (parseInt(tbarHeight) + 7) + 'px';
+ div.appendChild(listDiv);
+
+ var dragSource = null;
+ var dropIndex = null;
+
+ mxEvent.addListener(div, 'dragover', function(evt)
+ {
+ evt.dataTransfer.dropEffect = 'move';
+ dropIndex = 0;
+ evt.stopPropagation();
+ evt.preventDefault();
+ });
+
+ // Workaround for "no element found" error in FF
+ mxEvent.addListener(div, 'drop', function(evt)
+ {
+ evt.stopPropagation();
+ evt.preventDefault();
+ });
+
+ var layerCount = null;
+ var selectionLayer = null;
+ var ldiv = document.createElement('div');
+
+ ldiv.className = 'geToolbarContainer';
+ ldiv.style.position = 'absolute';
+ ldiv.style.bottom = '0px';
+ ldiv.style.left = '0px';
+ ldiv.style.right = '0px';
+ ldiv.style.height = tbarHeight;
+ ldiv.style.overflow = 'hidden';
+ ldiv.style.padding = (!EditorUi.compactUi) ? '1px' : '4px 0px 3px 0px';
+ ldiv.style.borderWidth = '1px 0px 0px 0px';
+ ldiv.style.borderStyle = 'solid';
+ ldiv.style.display = 'block';
+ ldiv.style.whiteSpace = 'nowrap';
+
+ var link = document.createElement('a');
+ link.className = 'geButton';
+
+ var removeLink = link.cloneNode(false);
+ var img = document.createElement('img');
+ img.setAttribute('border', '0');
+ img.setAttribute('width', '22');
+ img.setAttribute('src', Editor.trashImage);
+ img.style.opacity = '0.9';
+
+ if (Editor.isDarkMode())
+ {
+ img.style.filter = 'invert(100%)';
+ }
+
+ removeLink.appendChild(img);
+
+ mxEvent.addListener(removeLink, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ graph.model.beginUpdate();
+ try
+ {
+ var index = graph.model.root.getIndex(selectionLayer);
+ graph.removeCells([selectionLayer], false);
+
+ // Creates default layer if no layer exists
+ if (graph.model.getChildCount(graph.model.root) == 0)
+ {
+ graph.model.add(graph.model.root, new mxCell());
+ graph.setDefaultParent(null);
+ }
+ else if (index > 0 && index <= graph.model.getChildCount(graph.model.root))
+ {
+ graph.setDefaultParent(graph.model.getChildAt(graph.model.root, index - 1));
+ }
+ else
+ {
+ graph.setDefaultParent(null);
+ }
+ }
+ finally
+ {
+ graph.model.endUpdate();
+ }
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ if (!graph.isEnabled())
+ {
+ removeLink.className = 'geButton mxDisabled';
+ }
+
+ ldiv.appendChild(removeLink);
+
+ var insertLink = link.cloneNode();
+ insertLink.setAttribute('title', mxUtils.trim(mxResources.get('moveSelectionTo', ['...'])));
+
+ img = img.cloneNode(false);
+ img.setAttribute('src', Editor.verticalDotsImage);
+ insertLink.appendChild(img);
+
+ mxEvent.addListener(insertLink, 'click', function(evt)
+ {
+ if (graph.isEnabled() && !graph.isSelectionEmpty())
+ {
+ var offset = mxUtils.getOffset(insertLink);
+
+ editorUi.showPopupMenu(mxUtils.bind(this, function(menu, parent)
+ {
+ for (var i = layerCount - 1; i >= 0; i--)
+ {
+ (mxUtils.bind(this, function(child)
+ {
+ var item = menu.addItem(graph.convertValueToString(child) ||
+ mxResources.get('background'), null, mxUtils.bind(this, function()
+ {
+ graph.moveCells(graph.getSelectionCells(), 0, 0, false, child);
+ }), parent);
+
+ if (graph.getSelectionCount() == 1 && graph.model.isAncestor(child, graph.getSelectionCell()))
+ {
+ menu.addCheckmark(item, Editor.checkmarkImage);
+ }
+
+ }))(graph.model.getChildAt(graph.model.root, i));
+ }
+ }), offset.x, offset.y + insertLink.offsetHeight, evt);
+ }
+ });
+
+ ldiv.appendChild(insertLink);
+
+ var dataLink = link.cloneNode(false);
+ dataLink.setAttribute('title', mxResources.get('editData'));
+
+ img = img.cloneNode(false);
+ img.setAttribute('src', Editor.editImage);
+ dataLink.appendChild(img);
+
+ mxEvent.addListener(dataLink, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ editorUi.showDataDialog(selectionLayer);
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ if (!graph.isEnabled())
+ {
+ dataLink.className = 'geButton mxDisabled';
+ }
+
+ ldiv.appendChild(dataLink);
+
+ function renameLayer(layer)
+ {
+ if (graph.isEnabled() && layer != null)
+ {
+ var label = graph.convertValueToString(layer);
+ var dlg = new FilenameDialog(editorUi, label || mxResources.get('background'),
+ mxResources.get('rename'), mxUtils.bind(this, function(newValue)
+ {
+ if (newValue != null)
+ {
+ graph.cellLabelChanged(layer, newValue);
+ }
+ }), mxResources.get('enterName'));
+ editorUi.showDialog(dlg.container, 300, 100, true, true);
+ dlg.init();
+ }
+ };
+
+ var duplicateLink = link.cloneNode(false);
+ duplicateLink.setAttribute('title', mxResources.get('duplicate'));
+
+ img = img.cloneNode(false);
+ img.setAttribute('src', Editor.duplicateImage);
+ duplicateLink.appendChild(img);
+
+ mxEvent.addListener(duplicateLink, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ var newCell = null;
+ graph.model.beginUpdate();
+ try
+ {
+ newCell = graph.cloneCell(selectionLayer);
+ graph.cellLabelChanged(newCell, mxResources.get('untitledLayer'));
+ newCell.setVisible(true);
+ newCell = graph.addCell(newCell, graph.model.root);
+ graph.setDefaultParent(newCell);
+ }
+ finally
+ {
+ graph.model.endUpdate();
+ }
+
+ if (newCell != null && !graph.isCellLocked(newCell))
+ {
+ graph.selectAll(newCell);
+ }
+ }
+ });
+
+ if (!graph.isEnabled())
+ {
+ duplicateLink.className = 'geButton mxDisabled';
+ }
+
+ ldiv.appendChild(duplicateLink);
+
+ var addLink = link.cloneNode(false);
+ addLink.setAttribute('title', mxResources.get('addLayer'));
+
+ img = img.cloneNode(false);
+ img.setAttribute('src', Editor.addImage);
+ addLink.appendChild(img);
+
+ mxEvent.addListener(addLink, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ graph.model.beginUpdate();
+
+ try
+ {
+ var cell = graph.addCell(new mxCell(mxResources.get('untitledLayer')), graph.model.root);
+ graph.setDefaultParent(cell);
+ }
+ finally
+ {
+ graph.model.endUpdate();
+ }
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ if (!graph.isEnabled())
+ {
+ addLink.className = 'geButton mxDisabled';
+ }
+
+ ldiv.appendChild(addLink);
+ div.appendChild(ldiv);
+
+ var layerDivs = new mxDictionary();
+
+ var dot = document.createElement('span');
+ dot.setAttribute('title', mxResources.get('selectionOnly'));
+ dot.innerHTML = '•';
+ dot.style.position = 'absolute';
+ dot.style.fontWeight = 'bold';
+ dot.style.fontSize = '16pt';
+ dot.style.right = '2px';
+ dot.style.top = '2px';
+
+ function updateLayerDot()
+ {
+ var div = layerDivs.get(graph.getLayerForCells(graph.getSelectionCells()));
+
+ if (div != null)
+ {
+ div.appendChild(dot);
+ }
+ else if (dot.parentNode != null)
+ {
+ dot.parentNode.removeChild(dot);
+ }
+ };
+
+ function refresh()
+ {
+ layerCount = graph.model.getChildCount(graph.model.root)
+ listDiv.innerText = '';
+ layerDivs.clear();
+
+ function addLayer(index, label, child, defaultParent)
+ {
+ var ldiv = document.createElement('div');
+ ldiv.className = 'geToolbarContainer';
+ layerDivs.put(child, ldiv);
+
+ ldiv.style.overflow = 'hidden';
+ ldiv.style.position = 'relative';
+ ldiv.style.padding = '4px';
+ ldiv.style.height = '22px';
+ ldiv.style.display = 'block';
+ ldiv.style.backgroundColor = (Editor.isDarkMode()) ?
+ Editor.darkColor : 'whiteSmoke';
+ ldiv.style.borderWidth = '0px 0px 1px 0px';
+ ldiv.style.borderColor = '#c3c3c3';
+ ldiv.style.borderStyle = 'solid';
+ ldiv.style.whiteSpace = 'nowrap';
+ ldiv.setAttribute('title', label);
+
+ var left = document.createElement('div');
+ left.style.display = 'inline-block';
+ left.style.width = '100%';
+ left.style.textOverflow = 'ellipsis';
+ left.style.overflow = 'hidden';
+
+ mxEvent.addListener(ldiv, 'dragover', function(evt)
+ {
+ evt.dataTransfer.dropEffect = 'move';
+ dropIndex = index;
+ evt.stopPropagation();
+ evt.preventDefault();
+ });
+
+ mxEvent.addListener(ldiv, 'dragstart', function(evt)
+ {
+ dragSource = ldiv;
+
+ // Workaround for no DnD on DIV in FF
+ if (mxClient.IS_FF)
+ {
+ // LATER: Check what triggers a parse as XML on this in FF after drop
+ evt.dataTransfer.setData('Text', '');
+ }
+ });
+
+ mxEvent.addListener(ldiv, 'dragend', function(evt)
+ {
+ if (dragSource != null && dropIndex != null)
+ {
+ graph.addCell(child, graph.model.root, dropIndex);
+ }
+
+ dragSource = null;
+ dropIndex = null;
+ evt.stopPropagation();
+ evt.preventDefault();
+ });
+
+ var inp = document.createElement('img');
+ inp.setAttribute('draggable', 'false');
+ inp.setAttribute('align', 'top');
+ inp.setAttribute('border', '0');
+ inp.style.width = '16px';
+ inp.style.padding = '0px 6px 0 4px';
+ inp.style.marginTop = '2px';
+ inp.style.cursor = 'pointer';
+ inp.setAttribute('title', mxResources.get(
+ graph.model.isVisible(child) ?
+ 'hide' : 'show'));
+
+ if (graph.model.isVisible(child))
+ {
+ inp.setAttribute('src', Editor.visibleImage);
+ mxUtils.setOpacity(ldiv, 75);
+ }
+ else
+ {
+ inp.setAttribute('src', Editor.hiddenImage);
+ mxUtils.setOpacity(ldiv, 25);
+ }
+
+ if (Editor.isDarkMode())
+ {
+ inp.style.filter = 'invert(100%)';
+ }
+
+ left.appendChild(inp);
+
+ mxEvent.addListener(inp, 'click', function(evt)
+ {
+ graph.model.setVisible(child, !graph.model.isVisible(child));
+ mxEvent.consume(evt);
+ });
+
+ var btn = document.createElement('img');
+ btn.setAttribute('draggable', 'false');
+ btn.setAttribute('align', 'top');
+ btn.setAttribute('border', '0');
+ btn.style.width = '16px';
+ btn.style.padding = '0px 6px 0 0';
+ btn.style.marginTop = '2px';
+ btn.setAttribute('title', mxResources.get('lockUnlock'));
+
+ var style = graph.getCurrentCellStyle(child);
+
+ if (mxUtils.getValue(style, 'locked', '0') == '1')
+ {
+ btn.setAttribute('src', Editor.lockedImage);
+ mxUtils.setOpacity(btn, 75);
+ }
+ else
+ {
+ btn.setAttribute('src', Editor.unlockedImage);
+ mxUtils.setOpacity(btn, 25);
+ }
+
+ if (Editor.isDarkMode())
+ {
+ btn.style.filter = 'invert(100%)';
+ }
+
+ if (graph.isEnabled())
+ {
+ btn.style.cursor = 'pointer';
+ }
+
+ mxEvent.addListener(btn, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ var value = null;
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ value = (mxUtils.getValue(style, 'locked', '0') == '1') ? null : '1';
+ graph.setCellStyles('locked', value, [child]);
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ if (value == '1')
+ {
+ graph.removeSelectionCells(graph.getModel().getDescendants(child));
+ }
+
+ mxEvent.consume(evt);
+ }
+ });
+
+ left.appendChild(btn);
+
+ var span = document.createElement('span');
+ mxUtils.write(span, label);
+ span.style.display = 'block';
+ span.style.whiteSpace = 'nowrap';
+ span.style.overflow = 'hidden';
+ span.style.textOverflow = 'ellipsis';
+ span.style.position = 'absolute';
+ span.style.left = '52px';
+ span.style.right = '8px';
+ span.style.top = '8px';
+
+ left.appendChild(span);
+ ldiv.appendChild(left);
+
+ if (graph.isEnabled())
+ {
+ // Fallback if no drag and drop is available
+ if (mxClient.IS_TOUCH || mxClient.IS_POINTER ||
+ (mxClient.IS_IE && document.documentMode < 10))
+ {
+ var right = document.createElement('div');
+ right.style.display = 'block';
+ right.style.textAlign = 'right';
+ right.style.whiteSpace = 'nowrap';
+ right.style.position = 'absolute';
+ right.style.right = '16px';
+ right.style.top = '6px';
+
+ // Poor man's change layer order
+ if (index > 0)
+ {
+ var img2 = document.createElement('a');
+
+ img2.setAttribute('title', mxResources.get('toBack'));
+
+ img2.className = 'geButton';
+ img2.style.cssFloat = 'none';
+ img2.innerHTML = '▼';
+ img2.style.width = '14px';
+ img2.style.height = '14px';
+ img2.style.fontSize = '14px';
+ img2.style.margin = '0px';
+ img2.style.marginTop = '-1px';
+ right.appendChild(img2);
+
+ mxEvent.addListener(img2, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ graph.addCell(child, graph.model.root, index - 1);
+ }
+
+ mxEvent.consume(evt);
+ });
+ }
+
+ if (index >= 0 && index < layerCount - 1)
+ {
+ var img1 = document.createElement('a');
+
+ img1.setAttribute('title', mxResources.get('toFront'));
+
+ img1.className = 'geButton';
+ img1.style.cssFloat = 'none';
+ img1.innerHTML = '▲';
+ img1.style.width = '14px';
+ img1.style.height = '14px';
+ img1.style.fontSize = '14px';
+ img1.style.margin = '0px';
+ img1.style.marginTop = '-1px';
+ right.appendChild(img1);
+
+ mxEvent.addListener(img1, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ graph.addCell(child, graph.model.root, index + 1);
+ }
+
+ mxEvent.consume(evt);
+ });
+ }
+
+ ldiv.appendChild(right);
+ }
+
+ if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10))
+ {
+ ldiv.setAttribute('draggable', 'true');
+ ldiv.style.cursor = 'move';
+ }
+ }
+
+ mxEvent.addListener(ldiv, 'dblclick', function(evt)
+ {
+ var nodeName = mxEvent.getSource(evt).nodeName;
+
+ if (nodeName != 'INPUT' && nodeName != 'IMG')
+ {
+ renameLayer(child);
+ mxEvent.consume(evt);
+ }
+ });
+
+ if (graph.getDefaultParent() == child)
+ {
+ ldiv.style.background = (!Editor.isDarkMode()) ? '#e6eff8' : '#505759';
+ ldiv.style.fontWeight = (graph.isEnabled()) ? 'bold' : '';
+ selectionLayer = child;
+ }
+
+ mxEvent.addListener(ldiv, 'click', function(evt)
+ {
+ if (graph.isEnabled())
+ {
+ graph.setDefaultParent(defaultParent);
+ graph.view.setCurrentRoot(null);
+
+ if (mxEvent.isShiftDown(evt))
+ {
+ graph.setSelectionCells(child.children);
+ }
+
+ mxEvent.consume(evt);
+ }
+ });
+
+ listDiv.appendChild(ldiv);
+ };
+
+ // Cannot be moved or deleted
+ for (var i = layerCount - 1; i >= 0; i--)
+ {
+ (mxUtils.bind(this, function(child)
+ {
+ addLayer(i, graph.convertValueToString(child) ||
+ mxResources.get('background'), child, child);
+ }))(graph.model.getChildAt(graph.model.root, i));
+ }
+
+ var label = graph.convertValueToString(selectionLayer) || mxResources.get('background');
+ removeLink.setAttribute('title', mxResources.get('removeIt', [label]));
+ duplicateLink.setAttribute('title', mxResources.get('duplicateIt', [label]));
+
+ if (graph.isSelectionEmpty())
+ {
+ insertLink.className = 'geButton mxDisabled';
+ }
+
+ updateLayerDot();
+ };
+
+ refresh();
+ graph.model.addListener(mxEvent.CHANGE, refresh);
+ graph.addListener('defaultParentChanged', refresh);
+
+ graph.selectionModel.addListener(mxEvent.CHANGE, function()
+ {
+ if (graph.isSelectionEmpty())
+ {
+ insertLink.className = 'geButton mxDisabled';
+ }
+ else
+ {
+ insertLink.className = 'geButton';
+ }
+
+ updateLayerDot();
+ });
+
+ this.window = new mxWindow(mxResources.get('layers'), div, x, y, w, h, true, true);
+ this.window.minimumSize = new mxRectangle(0, 0, 150, 120);
+ this.window.destroyOnClose = false;
+ this.window.setMaximizable(false);
+ this.window.setResizable(true);
+ this.window.setClosable(true);
+ this.window.setVisible(true);
+
+ this.init = function()
+ {
+ listDiv.scrollTop = listDiv.scrollHeight - listDiv.clientHeight;
+ };
+
+ this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
+ {
+ this.window.fit();
+ }));
+
+ // Make refresh available via instance
+ this.refreshLayers = refresh;
+ editorUi.installResizeHandler(this, true);
+};
diff --git a/static/cherry/drawio_demo/Editor.js b/static/cherry/drawio_demo/Editor.js
new file mode 100644
index 000000000..54bfebddc
--- /dev/null
+++ b/static/cherry/drawio_demo/Editor.js
@@ -0,0 +1,3212 @@
+/**
+ * Copyright (c) 2006-2012, JGraph Ltd
+ */
+/**
+ * Editor constructor executed on page load.
+ */
+Editor = function(chromeless, themes, model, graph, editable)
+{
+ mxEventSource.call(this);
+ this.chromeless = (chromeless != null) ? chromeless : this.chromeless;
+ this.initStencilRegistry();
+ this.graph = graph || this.createGraph(themes, model);
+ this.editable = (editable != null) ? editable : !chromeless;
+ this.undoManager = this.createUndoManager();
+ this.status = '';
+
+ this.getOrCreateFilename = function()
+ {
+ return this.filename || mxResources.get('drawing', [Editor.pageCounter]) + '.xml';
+ };
+
+ this.getFilename = function()
+ {
+ return this.filename;
+ };
+
+ // Sets the status and fires a statusChanged event
+ this.setStatus = function(value, fn)
+ {
+ this.status = value;
+ this.statusFunction = fn;
+ this.fireEvent(new mxEventObject('statusChanged'));
+ };
+
+ // Returns the current status
+ this.getStatus = function()
+ {
+ return this.status;
+ };
+
+ // Updates modified state if graph changes
+ this.graphChangeListener = function(sender, eventObject)
+ {
+ var edit = (eventObject != null) ? eventObject.getProperty('edit') : null;
+
+ if (edit == null || !edit.ignoreEdit)
+ {
+ this.setModified(true);
+ }
+ };
+
+ this.graph.getModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function()
+ {
+ this.graphChangeListener.apply(this, arguments);
+ }));
+
+ // Sets persistent graph state defaults
+ this.graph.resetViewOnRootChange = false;
+ this.init();
+};
+
+/**
+ * Counts open editor tabs (must be global for cross-window access)
+ */
+Editor.pageCounter = 0;
+
+// Cross-domain window access is not allowed in FF, so if we
+// were opened from another domain then this will fail.
+(function()
+{
+ try
+ {
+ var op = window;
+
+ while (op.opener != null && typeof op.opener.Editor !== 'undefined' &&
+ !isNaN(op.opener.Editor.pageCounter) &&
+ // Workaround for possible infinite loop in FF https://drawio.atlassian.net/browse/DS-795
+ op.opener != op)
+ {
+ op = op.opener;
+ }
+
+ // Increments the counter in the first opener in the chain
+ if (op != null)
+ {
+ op.Editor.pageCounter++;
+ Editor.pageCounter = op.Editor.pageCounter;
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+})();
+
+/**
+ *
+ */
+Editor.defaultHtmlFont = '-apple-system, BlinkMacSystemFont, "Segoe UI Variable", "Segoe UI", system-ui, ui-sans-serif, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"';
+
+/**
+ * Specifies if local storage should be used (eg. on the iPad which has no filesystem)
+ */
+Editor.useLocalStorage = typeof(Storage) != 'undefined' && mxClient.IS_IOS;
+
+/**
+ * Window width for simple mode to collapse panels.
+ */
+Editor.smallScreenWidth = 800;
+
+/**
+ *
+ */
+Editor.lightCheckmarkImage = 'data:image/gif;base64,R0lGODlhFQAVAMQfAGxsbHx8fIqKioaGhvb29nJycvr6+sDAwJqamltbW5OTk+np6YGBgeTk5Ly8vJiYmP39/fLy8qWlpa6ursjIyOLi4vj4+N/f3+3t7fT09LCwsHZ2dubm5r6+vmZmZv///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OEY4NTZERTQ5QUFBMTFFMUE5MTVDOTM5MUZGMTE3M0QiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OEY4NTZERTU5QUFBMTFFMUE5MTVDOTM5MUZGMTE3M0QiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Rjg1NkRFMjlBQUExMUUxQTkxNUM5MzkxRkYxMTczRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Rjg1NkRFMzlBQUExMUUxQTkxNUM5MzkxRkYxMTczRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAB8ALAAAAAAVABUAAAVI4CeOZGmeaKqubKtylktSgCOLRyLd3+QJEJnh4VHcMoOfYQXQLBcBD4PA6ngGlIInEHEhPOANRkaIFhq8SuHCE1Hb8Lh8LgsBADs=';
+Editor.darkCheckmarkImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAMAAACeyVWkAAAARVBMVEUAAACZmZkICAgEBASNjY2Dg4MYGBiTk5N5eXl1dXVmZmZQUFBCQkI3NzceHh4MDAykpKSJiYl+fn5sbGxaWlo/Pz8SEhK96uPlAAAAAXRSTlMAQObYZgAAAE5JREFUGNPFzTcSgDAQQ1HJGUfy/Y9K7V1qeOUfzQifCQZai1XHaz11LFysbDbzgDSSWMZiETz3+b8yNUc/MMsktxuC8XQBSncdLwz+8gCCggGXzBcozAAAAABJRU5ErkJggg==';
+Editor.darkHelpImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAP1BMVEUAAAD///////////////////////////////////////////////////////////////////////////////9Du/pqAAAAFXRSTlMAT30qCJRBboyDZyCgRzUUdF46MJlgXETgAAAAeklEQVQY022O2w4DIQhEQUURda/9/28tUO2+7CQS5sgQ4F1RapX78YUwRqQjTU8ILqQfKerTKTvACJ4nLX3krt+8aS82oI8aQC4KavRgtvEW/mDvsICgA03PSGRr79MqX1YPNIxzjyqtw8ZnnRo4t5a5undtJYRywau+ds4Cyza3E6YAAAAASUVORK5CYII=';
+Editor.lightHelpImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBkPSJNMCAwaDI0djI0SDB6Ii8+PHBhdGggZD0iTTExIDE4aDJ2LTJoLTJ2MnptMS0xNkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTAtMTRjLTIuMjEgMC00IDEuNzktNCA0aDJjMC0xLjEuOS0yIDItMnMyIC45IDIgMmMwIDItMyAxLjc1LTMgNWgyYzAtMi4yNSAzLTIuNSAzLTUgMC0yLjIxLTEuNzktNC00LTR6Ii8+PC9zdmc+';
+Editor.menuImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTMgMThoMTh2LTJIM3Yyem0wLTVoMTh2LTJIM3Yyem0wLTd2MmgxOFY2SDN6Ii8+PC9zdmc+';
+Editor.moveImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI4cHgiIGhlaWdodD0iMjhweCI+PGc+PC9nPjxnPjxnPjxnPjxwYXRoIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuNCwyLjQpc2NhbGUoMC44KXJvdGF0ZSg0NSwxMiwxMikiIHN0cm9rZT0iIzI5YjZmMiIgZmlsbD0iIzI5YjZmMiIgZD0iTTE1LDNsMi4zLDIuM2wtMi44OSwyLjg3bDEuNDIsMS40MkwxOC43LDYuN0wyMSw5VjNIMTV6IE0zLDlsMi4zLTIuM2wyLjg3LDIuODlsMS40Mi0xLjQyTDYuNyw1LjNMOSwzSDNWOXogTTksMjEgbC0yLjMtMi4zbDIuODktMi44N2wtMS40Mi0xLjQyTDUuMywxNy4zTDMsMTV2Nkg5eiBNMjEsMTVsLTIuMywyLjNsLTIuODctMi44OWwtMS40MiwxLjQybDIuODksMi44N0wxNSwyMWg2VjE1eiIvPjwvZz48L2c+PC9nPjwvc3ZnPgo=';
+Editor.zoomInImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTUuNSAxNGgtLjc5bC0uMjgtLjI3QzE1LjQxIDEyLjU5IDE2IDExLjExIDE2IDkuNSAxNiA1LjkxIDEzLjA5IDMgOS41IDNTMyA1LjkxIDMgOS41IDUuOTEgMTYgOS41IDE2YzEuNjEgMCAzLjA5LS41OSA0LjIzLTEuNTdsLjI3LjI4di43OWw1IDQuOTlMMjAuNDkgMTlsLTQuOTktNXptLTYgMEM3LjAxIDE0IDUgMTEuOTkgNSA5LjVTNy4wMSA1IDkuNSA1IDE0IDcuMDEgMTQgOS41IDExLjk5IDE0IDkuNSAxNHptMi41LTRoLTJ2Mkg5di0ySDdWOWgyVjdoMXYyaDJ2MXoiLz48L3N2Zz4=';
+Editor.zoomOutImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTUuNSAxNGgtLjc5bC0uMjgtLjI3QzE1LjQxIDEyLjU5IDE2IDExLjExIDE2IDkuNSAxNiA1LjkxIDEzLjA5IDMgOS41IDNTMyA1LjkxIDMgOS41IDUuOTEgMTYgOS41IDE2YzEuNjEgMCAzLjA5LS41OSA0LjIzLTEuNTdsLjI3LjI4di43OWw1IDQuOTlMMjAuNDkgMTlsLTQuOTktNXptLTYgMEM3LjAxIDE0IDUgMTEuOTkgNSA5LjVTNy4wMSA1IDkuNSA1IDE0IDcuMDEgMTQgOS41IDExLjk5IDE0IDkuNSAxNHpNNyA5aDV2MUg3eiIvPjwvc3ZnPg==';
+Editor.fullscreenImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMyA1djRoMlY1aDRWM0g1Yy0xLjEgMC0yIC45LTIgMnptMiAxMEgzdjRjMCAxLjEuOSAyIDIgMmg0di0ySDV2LTR6bTE0IDRoLTR2Mmg0YzEuMSAwIDItLjkgMi0ydi00aC0ydjR6bTAtMTZoLTR2Mmg0djRoMlY1YzAtMS4xLS45LTItMi0yeiIvPjwvc3ZnPg==';
+Editor.fullscreenExitImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTUgMTZoM3YzaDJ2LTVINXYyem0zLThINXYyaDVWNUg4djN6bTYgMTFoMnYtM2gzdi0yaC01djV6bTItMTFWNWgtMnY1aDVWOGgtM3oiLz48L3N2Zz4=';
+Editor.zoomFitImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTUgMTVIM3Y0YzAgMS4xLjkgMiAyIDJoNHYtMkg1di00ek01IDVoNFYzSDVjLTEuMSAwLTIgLjktMiAydjRoMlY1em03IDNjLTIuMjEgMC00IDEuNzktNCA0czEuNzkgNCA0IDQgNC0xLjc5IDQtNC0xLjc5LTQtNC00em0wIDZjLTEuMSAwLTItLjktMi0ycy45LTIgMi0yIDIgLjkgMiAyLS45IDItMiAyem03LTExaC00djJoNHY0aDJWNWMwLTEuMS0uOS0yLTItMnptMCAxNmgtNHYyaDRjMS4xIDAgMi0uOSAyLTJ2LTRoLTJ2NHoiLz48L3N2Zz4=';
+Editor.layersImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTExLjk5IDE4LjU0bC03LjM3LTUuNzNMMyAxNC4wN2w5IDcgOS03LTEuNjMtMS4yN3pNMTIgMTZsNy4zNi01LjczTDIxIDlsLTktNy05IDcgMS42MyAxLjI3TDEyIDE2em0wLTExLjQ3TDE3Ljc0IDkgMTIgMTMuNDcgNi4yNiA5IDEyIDQuNTN6Ii8+PC9zdmc+';
+Editor.previousImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE1LjQxIDcuNDFMMTQgNmwtNiA2IDYgNiAxLjQxLTEuNDFMMTAuODMgMTJsNC41OC00LjU5eiIvPjwvc3ZnPg==';
+Editor.nextImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEwIDZMOC41OSA3LjQxIDEzLjE3IDEybC00LjU4IDQuNTlMMTAgMThsNi02LTYtNnoiLz48L3N2Zz4=';
+Editor.editImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE0LjA2IDkuMDJsLjkyLjkyTDUuOTIgMTlINXYtLjkybDkuMDYtOS4wNk0xNy42NiAzYy0uMjUgMC0uNTEuMS0uNy4yOWwtMS44MyAxLjgzIDMuNzUgMy43NSAxLjgzLTEuODNjLjM5LS4zOS4zOS0xLjAyIDAtMS40MWwtMi4zNC0yLjM0Yy0uMi0uMi0uNDUtLjI5LS43MS0uMjl6bS0zLjYgMy4xOUwzIDE3LjI1VjIxaDMuNzVMMTcuODEgOS45NGwtMy43NS0zLjc1eiIvPjwvc3ZnPg==';
+Editor.duplicateImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE2IDFINGMtMS4xIDAtMiAuOS0yIDJ2MTRoMlYzaDEyVjF6bTMgNEg4Yy0xLjEgMC0yIC45LTIgMnYxNGMwIDEuMS45IDIgMiAyaDExYzEuMSAwIDItLjkgMi0yVjdjMC0xLjEtLjktMi0yLTJ6bTAgMTZIOFY3aDExdjE0eiIvPjwvc3ZnPg==';
+Editor.addImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5IDEzaC02djZoLTJ2LTZINXYtMmg2VjVoMnY2aDZ2MnoiLz48L3N2Zz4=';
+Editor.crossImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5IDYuNDFMMTcuNTkgNSAxMiAxMC41OSA2LjQxIDUgNSA2LjQxIDEwLjU5IDEyIDUgMTcuNTkgNi40MSAxOSAxMiAxMy40MSAxNy41OSAxOSAxOSAxNy41OSAxMy40MSAxMiAxOSA2LjQxeiIvPjwvc3ZnPg==';
+Editor.verticalDotsImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDhjMS4xIDAgMi0uOSAyLTJzLS45LTItMi0yLTIgLjktMiAyIC45IDIgMiAyem0wIDJjLTEuMSAwLTIgLjktMiAycy45IDIgMiAyIDItLjkgMi0yLS45LTItMi0yem0wIDZjLTEuMSAwLTIgLjktMiAycy45IDIgMiAyIDItLjkgMi0yLS45LTItMi0yeiIvPjwvc3ZnPg==';
+Editor.trashImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE2IDl2MTBIOFY5aDhtLTEuNS02aC01bC0xIDFINXYyaDE0VjRoLTMuNWwtMS0xek0xOCA3SDZ2MTJjMCAxLjEuOSAyIDIgMmg4YzEuMSAwIDItLjkgMi0yVjd6Ii8+PC9zdmc+';
+Editor.hiddenImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6bTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDZjMy43OSAwIDcuMTcgMi4xMyA4LjgyIDUuNS0uNTkgMS4yMi0xLjQyIDIuMjctMi40MSAzLjEybDEuNDEgMS40MWMxLjM5LTEuMjMgMi40OS0yLjc3IDMuMTgtNC41M0MyMS4yNyA3LjExIDE3IDQgMTIgNGMtMS4yNyAwLTIuNDkuMi0zLjY0LjU3bDEuNjUgMS42NUMxMC42NiA2LjA5IDExLjMyIDYgMTIgNnptLTEuMDcgMS4xNEwxMyA5LjIxYy41Ny4yNSAxLjAzLjcxIDEuMjggMS4yOGwyLjA3IDIuMDdjLjA4LS4zNC4xNC0uNy4xNC0xLjA3QzE2LjUgOS4wMSAxNC40OCA3IDEyIDdjLS4zNyAwLS43Mi4wNS0xLjA3LjE0ek0yLjAxIDMuODdsMi42OCAyLjY4QzMuMDYgNy44MyAxLjc3IDkuNTMgMSAxMS41IDIuNzMgMTUuODkgNyAxOSAxMiAxOWMxLjUyIDAgMi45OC0uMjkgNC4zMi0uODJsMy40MiAzLjQyIDEuNDEtMS40MUwzLjQyIDIuNDUgMi4wMSAzLjg3em03LjUgNy41bDIuNjEgMi42MWMtLjA0LjAxLS4wOC4wMi0uMTIuMDItMS4zOCAwLTIuNS0xLjEyLTIuNS0yLjUgMC0uMDUuMDEtLjA4LjAxLS4xM3ptLTMuNC0zLjRsMS43NSAxLjc1Yy0uMjMuNTUtLjM2IDEuMTUtLjM2IDEuNzggMCAyLjQ4IDIuMDIgNC41IDQuNSA0LjUuNjMgMCAxLjIzLS4xMyAxLjc3LS4zNmwuOTguOThjLS44OC4yNC0xLjguMzgtMi43NS4zOC0zLjc5IDAtNy4xNy0yLjEzLTguODItNS41LjctMS40MyAxLjcyLTIuNjEgMi45My0zLjUzeiIvPjwvc3ZnPg==';
+Editor.visibleImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDZjMy43OSAwIDcuMTcgMi4xMyA4LjgyIDUuNUMxOS4xNyAxNC44NyAxNS43OSAxNyAxMiAxN3MtNy4xNy0yLjEzLTguODItNS41QzQuODMgOC4xMyA4LjIxIDYgMTIgNm0wLTJDNyA0IDIuNzMgNy4xMSAxIDExLjUgMi43MyAxNS44OSA3IDE5IDEyIDE5czkuMjctMy4xMSAxMS03LjVDMjEuMjcgNy4xMSAxNyA0IDEyIDR6bTAgNWMxLjM4IDAgMi41IDEuMTIgMi41IDIuNVMxMy4zOCAxNCAxMiAxNHMtMi41LTEuMTItMi41LTIuNVMxMC42MiA5IDEyIDltMC0yYy0yLjQ4IDAtNC41IDIuMDItNC41IDQuNVM5LjUyIDE2IDEyIDE2czQuNS0yLjAyIDQuNS00LjVTMTQuNDggNyAxMiA3eiIvPjwvc3ZnPg==';
+Editor.lockedImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PGcgZmlsbD0ibm9uZSI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6Ii8+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBvcGFjaXR5PSIuODciLz48L2c+PHBhdGggZD0iTTE4IDhoLTFWNmMwLTIuNzYtMi4yNC01LTUtNVM3IDMuMjQgNyA2djJINmMtMS4xIDAtMiAuOS0yIDJ2MTBjMCAxLjEuOSAyIDIgMmgxMmMxLjEgMCAyLS45IDItMlYxMGMwLTEuMS0uOS0yLTItMnpNOSA2YzAtMS42NiAxLjM0LTMgMy0zczMgMS4zNCAzIDN2Mkg5VjZ6bTkgMTRINlYxMGgxMnYxMHptLTYtM2MxLjEgMCAyLS45IDItMnMtLjktMi0yLTItMiAuOS0yIDIgLjkgMiAyIDJ6Ii8+PC9zdmc+';
+Editor.unlockedImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE4IDhoLTFWNmMwLTIuNzYtMi4yNC01LTUtNVM3IDMuMjQgNyA2aDJjMC0xLjY2IDEuMzQtMyAzLTNzMyAxLjM0IDMgM3YySDZjLTEuMSAwLTIgLjktMiAydjEwYzAgMS4xLjkgMiAyIDJoMTJjMS4xIDAgMi0uOSAyLTJWMTBjMC0xLjEtLjktMi0yLTJ6bTAgMTJINlYxMGgxMnYxMHptLTYtM2MxLjEgMCAyLS45IDItMnMtLjktMi0yLTItMiAuOS0yIDIgLjkgMiAyIDJ6Ii8+PC9zdmc+';
+Editor.printImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5IDhoLTFWM0g2djVINWMtMS42NiAwLTMgMS4zNC0zIDN2Nmg0djRoMTJ2LTRoNHYtNmMwLTEuNjYtMS4zNC0zLTMtM3pNOCA1aDh2M0g4VjV6bTggMTJ2Mkg4di00aDh2MnptMi0ydi0ySDZ2Mkg0di00YzAtLjU1LjQ1LTEgMS0xaDE0Yy41NSAwIDEgLjQ1IDEgMXY0aC0yeiIvPjxjaXJjbGUgY3g9IjE4IiBjeT0iMTEuNSIgcj0iMSIvPjwvc3ZnPg==';
+Editor.refreshImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE3LjY1IDYuMzVDMTYuMiA0LjkgMTQuMjEgNCAxMiA0Yy00LjQyIDAtNy45OSAzLjU4LTcuOTkgOHMzLjU3IDggNy45OSA4YzMuNzMgMCA2Ljg0LTIuNTUgNy43My02aC0yLjA4Yy0uODIgMi4zMy0zLjA0IDQtNS42NSA0LTMuMzEgMC02LTIuNjktNi02czIuNjktNiA2LTZjMS42NiAwIDMuMTQuNjkgNC4yMiAxLjc4TDEzIDExaDdWNGwtMi4zNSAyLjM1eiIvPjwvc3ZnPg==';
+Editor.backImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIiBvcGFjaXR5PSIuODciLz48cGF0aCBkPSJNMTcuNTEgMy44N0wxNS43MyAyLjEgNS44NCAxMmw5LjkgOS45IDEuNzctMS43N0w5LjM4IDEybDguMTMtOC4xM3oiLz48L3N2Zz4=';
+Editor.closeImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIiBvcGFjaXR5PSIuODciLz48cGF0aCBkPSJNMTIgMkM2LjQ3IDIgMiA2LjQ3IDIgMTJzNC40NyAxMCAxMCAxMCAxMC00LjQ3IDEwLTEwUzE3LjUzIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTMuNTktMTNMMTIgMTAuNTkgOC40MSA3IDcgOC40MSAxMC41OSAxMiA3IDE1LjU5IDguNDEgMTcgMTIgMTMuNDEgMTUuNTkgMTcgMTcgMTUuNTkgMTMuNDEgMTIgMTcgOC40MXoiLz48L3N2Zz4='
+Editor.closeBlackImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjZweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjZweCI+PGVsbGlwc2UgY3g9IjEyIiBjeT0iMTIiIHJ4PSI5IiByeT0iOSIgc3Ryb2tlPSJub25lIiBmaWxsPSIjMDAwIi8+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE0LjU5IDhMMTIgMTAuNTkgOS40MSA4IDggOS40MSAxMC41OSAxMiA4IDE0LjU5IDkuNDEgMTYgMTIgMTMuNDEgMTQuNTkgMTYgMTYgMTQuNTkgMTMuNDEgMTIgMTYgOS40MSAxNC41OSA4ek0xMiAyQzYuNDcgMiAyIDYuNDcgMiAxMnM0LjQ3IDEwIDEwIDEwIDEwLTQuNDcgMTAtMTBTMTcuNTMgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHoiLz48L3N2Zz4=';
+Editor.minusImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHdpZHRoPSI0OCI+PHBhdGggZD0iTTEwIDI1LjV2LTNoMjh2M1oiLz48L3N2Zz4=';
+Editor.plusImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgMTNoLTZ2NmgtMnYtNkg1di0yaDZWNWgydjZoNnYyeiIvPjwvc3ZnPg==';
+Editor.addBoxImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTExIDE3aDJ2LTRoNHYtMmgtNFY3aC0ydjRIN3YyaDRabS02IDRxLS44MjUgMC0xLjQxMy0uNTg3UTMgMTkuODI1IDMgMTlWNXEwLS44MjUuNTg3LTEuNDEzUTQuMTc1IDMgNSAzaDE0cS44MjUgMCAxLjQxMy41ODdRMjEgNC4xNzUgMjEgNXYxNHEwIC44MjUtLjU4NyAxLjQxM1ExOS44MjUgMjEgMTkgMjFabTAtMmgxNFY1SDV2MTRaTTUgNXYxNFY1WiIvPjwvc3ZnPg==';
+Editor.shapesImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTE1IDE1Wm0tNyAyLjk1cS4yNS4wMjUuNDg4LjAzOFE4LjcyNSAxOCA5IDE4dC41MTItLjAxMnEuMjM4LS4wMTMuNDg4LS4wMzhWMjBoMTBWMTBoLTIuMDVxLjAyNS0uMjUuMDM4LS40ODhRMTggOS4yNzUgMTggOXQtLjAxMi0uNTEyUTE3Ljk3NSA4LjI1IDE3Ljk1IDhIMjBxLjgyNSAwIDEuNDEzLjU4N1EyMiA5LjE3NSAyMiAxMHYxMHEwIC44MjUtLjU4NyAxLjQxM1EyMC44MjUgMjIgMjAgMjJIMTBxLS44MjUgMC0xLjQxMi0uNTg3UTggMjAuODI1IDggMjBaTTkgMTZxLTIuOTI1IDAtNC45NjMtMi4wMzhRMiAxMS45MjUgMiA5dDIuMDM3LTQuOTYzUTYuMDc1IDIgOSAycTIuOTI1IDAgNC45NjMgMi4wMzdRMTYgNi4wNzUgMTYgOXEwIDIuOTI1LTIuMDM3IDQuOTYyUTExLjkyNSAxNiA5IDE2Wm0wLTJxMi4wNzUgMCAzLjUzOC0xLjQ2M1ExNCAxMS4wNzUgMTQgOXQtMS40NjItMy41MzdRMTEuMDc1IDQgOSA0IDYuOTI1IDQgNS40NjMgNS40NjMgNCA2LjkyNSA0IDl0MS40NjMgMy41MzdRNi45MjUgMTQgOSAxNFptMC01WiIvPjwvc3ZnPg==';
+Editor.formatImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTExIDIycS0uODI1IDAtMS40MTItLjU4N1E5IDIwLjgyNSA5IDIwdi00SDZxLS44MjUgMC0xLjQxMi0uNTg4UTQgMTQuODI1IDQgMTRWN3EwLTEuNjUgMS4xNzUtMi44MjVRNi4zNSAzIDggM2gxMnYxMXEwIC44MjUtLjU4NyAxLjQxMlExOC44MjUgMTYgMTggMTZoLTN2NHEwIC44MjUtLjU4NyAxLjQxM1ExMy44MjUgMjIgMTMgMjJaTTYgMTBoMTJWNWgtMXY0aC0yVjVoLTF2MmgtMlY1SDhxLS44MjUgMC0xLjQxMi41ODhRNiA2LjE3NSA2IDdabTAgNGgxMnYtMkg2djJabTAtMnYyWiIvPjwvc3ZnPg==';
+Editor.freehandImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMjRweCIgZmlsbD0iIzAwMDAwMCI+PHJlY3QgZmlsbD0ibm9uZSIgaGVpZ2h0PSIyNCIgd2lkdGg9IjI0Ii8+PHBhdGggZD0iTTQuNSw4YzEuMDQsMCwyLjM0LTEuNSw0LjI1LTEuNWMxLjUyLDAsMi43NSwxLjIzLDIuNzUsMi43NWMwLDIuMDQtMS45OSwzLjE1LTMuOTEsNC4yMkM1LjQyLDE0LjY3LDQsMTUuNTcsNCwxNyBjMCwxLjEsMC45LDIsMiwydjJjLTIuMjEsMC00LTEuNzktNC00YzAtMi43MSwyLjU2LTQuMTQsNC42Mi01LjI4YzEuNDItMC43OSwyLjg4LTEuNiwyLjg4LTIuNDdjMC0wLjQxLTAuMzQtMC43NS0wLjc1LTAuNzUgQzcuNSw4LjUsNi4yNSwxMCw0LjUsMTBDMy4xMiwxMCwyLDguODgsMiw3LjVDMiw1LjQ1LDQuMTcsMi44Myw1LDJsMS40MSwxLjQxQzUuNDEsNC40Miw0LDYuNDMsNCw3LjVDNCw3Ljc4LDQuMjIsOCw0LjUsOHogTTgsMjEgbDMuNzUsMGw4LjA2LTguMDZsLTMuNzUtMy43NUw4LDE3LjI1TDgsMjF6IE0xMCwxOC4wOGw2LjA2LTYuMDZsMC45MiwwLjkyTDEwLjkyLDE5TDEwLDE5TDEwLDE4LjA4eiBNMjAuMzcsNi4yOSBjLTAuMzktMC4zOS0xLjAyLTAuMzktMS40MSwwbC0xLjgzLDEuODNsMy43NSwzLjc1bDEuODMtMS44M2MwLjM5LTAuMzksMC4zOS0xLjAyLDAtMS40MUwyMC4zNyw2LjI5eiIvPjwvc3ZnPg==';
+Editor.undoImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIuNSA4Yy0yLjY1IDAtNS4wNS45OS02LjkgMi42TDIgN3Y5aDlsLTMuNjItMy42MmMxLjM5LTEuMTYgMy4xNi0xLjg4IDUuMTItMS44OCAzLjU0IDAgNi41NSAyLjMxIDcuNiA1LjVsMi4zNy0uNzhDMjEuMDggMTEuMDMgMTcuMTUgOCAxMi41IDh6Ii8+PC9zdmc+';
+Editor.redoImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTguNCAxMC42QzE2LjU1IDguOTkgMTQuMTUgOCAxMS41IDhjLTQuNjUgMC04LjU4IDMuMDMtOS45NiA3LjIyTDMuOSAxNmMxLjA1LTMuMTkgNC4wNS01LjUgNy42LTUuNSAxLjk1IDAgMy43My43MiA1LjEyIDEuODhMMTMgMTZoOVY3bC0zLjYgMy42eiIvPjwvc3ZnPg==';
+Editor.outlineImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTE1IDIxLTYtMi4xLTQuNjUgMS44cS0uNS4yLS45MjUtLjExM1EzIDIwLjI3NSAzIDE5Ljc1di0xNHEwLS4zMjUuMTg4LS41NzUuMTg3LS4yNS41MTItLjM3NUw5IDNsNiAyLjEgNC42NS0xLjhxLjUtLjIuOTI1LjExMi40MjUuMzEzLjQyNS44Mzh2MTRxMCAuMzI1LS4xODguNTc1LS4xODcuMjUtLjUxMi4zNzVabS0xLTIuNDVWNi44NWwtNC0xLjR2MTEuN1ptMiAwIDMtMVY1LjdsLTMgMS4xNVpNNSAxOC4zbDMtMS4xNVY1LjQ1bC0zIDFaTTE2IDYuODV2MTEuN1ptLTgtMS40djExLjdaIi8+PC9zdmc+';
+Editor.saveImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMThweCIgdmlld0JveD0iMCAwIDI0IDI0IiB3aWR0aD0iMThweCIgZmlsbD0iIzAwMDAwMCI+PHBhdGggZD0iTTAgMGgyNHYyNEgwVjB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTE5IDEydjdINXYtN0gzdjdjMCAxLjEuOSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMnYtN2gtMnptLTYgLjY3bDIuNTktMi41OEwxNyAxMS41bC01IDUtNS01IDEuNDEtMS40MUwxMSAxMi42N1YzaDJ2OS42N3oiLz48L3N2Zz4=';
+Editor.compareImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHdpZHRoPSI0OCI+PHBhdGggZD0ibTE1Ljg1IDQwLTIuMS0yLjEgNi4wNS02LjA1SDR2LTNoMTUuOGwtNi4wNS02LjA1IDIuMS0yLjEgOS42NSA5LjY1Wm0xNi4zLTEyLjctOS42NS05LjY1TDMyLjE1IDhsMi4xIDIuMS02LjA1IDYuMDVINDR2M0gyOC4ybDYuMDUgNi4wNVoiLz48L3N2Zz4=';
+Editor.expandMoreImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTEyIDE1LjM3NS02LTYgMS40LTEuNCA0LjYgNC42IDQuNi00LjYgMS40IDEuNFoiLz48L3N2Zz4=';
+Editor.expandLessImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTcuNCAxNS4zNzUtMS40LTEuNCA2LTYgNiA2LTEuNCAxLjQtNC42LTQuNloiLz48L3N2Zz4=';
+Editor.gearImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0ibTkuMjUgMjItLjQtMy4ycS0uMzI1LS4xMjUtLjYxMi0uMy0uMjg4LS4xNzUtLjU2My0uMzc1TDQuNyAxOS4zNzVsLTIuNzUtNC43NSAyLjU3NS0xLjk1UTQuNSAxMi41IDQuNSAxMi4zMzd2LS42NzVxMC0uMTYyLjAyNS0uMzM3TDEuOTUgOS4zNzVsMi43NS00Ljc1IDIuOTc1IDEuMjVxLjI3NS0uMi41NzUtLjM3NS4zLS4xNzUuNi0uM2wuNC0zLjJoNS41bC40IDMuMnEuMzI1LjEyNS42MTMuMy4yODcuMTc1LjU2Mi4zNzVsMi45NzUtMS4yNSAyLjc1IDQuNzUtMi41NzUgMS45NXEuMDI1LjE3NS4wMjUuMzM3di42NzVxMCAuMTYzLS4wNS4zMzhsMi41NzUgMS45NS0yLjc1IDQuNzUtMi45NS0xLjI1cS0uMjc1LjItLjU3NS4zNzUtLjMuMTc1LS42LjNsLS40IDMuMlptMi44LTYuNXExLjQ1IDAgMi40NzUtMS4wMjVRMTUuNTUgMTMuNDUgMTUuNTUgMTJxMC0xLjQ1LTEuMDI1LTIuNDc1UTEzLjUgOC41IDEyLjA1IDguNXEtMS40NzUgMC0yLjQ4OCAxLjAyNVE4LjU1IDEwLjU1IDguNTUgMTJxMCAxLjQ1IDEuMDEyIDIuNDc1UTEwLjU3NSAxNS41IDEyLjA1IDE1LjVabTAtMnEtLjYyNSAwLTEuMDYyLS40MzgtLjQzOC0uNDM3LS40MzgtMS4wNjJ0LjQzOC0xLjA2MnEuNDM3LS40MzggMS4wNjItLjQzOHQxLjA2My40MzhxLjQzNy40MzcuNDM3IDEuMDYydC0uNDM3IDEuMDYycS0uNDM4LjQzOC0xLjA2My40MzhaTTEyIDEyWm0tMSA4aDEuOTc1bC4zNS0yLjY1cS43NzUtLjIgMS40MzgtLjU4OC42NjItLjM4NyAxLjIxMi0uOTM3bDIuNDc1IDEuMDI1Ljk3NS0xLjctMi4xNS0xLjYyNXEuMTI1LS4zNS4xNzUtLjczOC4wNS0uMzg3LjA1LS43ODd0LS4wNS0uNzg4cS0uMDUtLjM4Ny0uMTc1LS43MzdsMi4xNS0xLjYyNS0uOTc1LTEuNy0yLjQ3NSAxLjA1cS0uNTUtLjU3NS0xLjIxMi0uOTYzLS42NjMtLjM4Ny0xLjQzOC0uNTg3TDEzIDRoLTEuOTc1bC0uMzUgMi42NXEtLjc3NS4yLTEuNDM3LjU4Ny0uNjYzLjM4OC0xLjIxMy45MzhMNS41NSA3LjE1bC0uOTc1IDEuNyAyLjE1IDEuNnEtLjEyNS4zNzUtLjE3NS43NS0uMDUuMzc1LS4wNS44IDAgLjQuMDUuNzc1dC4xNzUuNzVsLTIuMTUgMS42MjUuOTc1IDEuNyAyLjQ3NS0xLjA1cS41NS41NzUgMS4yMTMuOTYyLjY2Mi4zODggMS40MzcuNTg4WiIvPjwvc3ZnPg==';
+Editor.extensionImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTguOCAyMUg1cS0uODI1IDAtMS40MTMtLjU4N1EzIDE5LjgyNSAzIDE5di0zLjhxMS4yIDAgMi4xLS43NjIuOS0uNzYzLjktMS45MzggMC0xLjE3NS0uOS0xLjkzOFE0LjIgOS44IDMgOS44VjZxMC0uODI1LjU4Ny0xLjQxMlE0LjE3NSA0IDUgNGg0cTAtMS4wNS43MjUtMS43NzVRMTAuNDUgMS41IDExLjUgMS41cTEuMDUgMCAxLjc3NS43MjVRMTQgMi45NSAxNCA0aDRxLjgyNSAwIDEuNDEzLjU4OFEyMCA1LjE3NSAyMCA2djRxMS4wNSAwIDEuNzc1LjcyNS43MjUuNzI1LjcyNSAxLjc3NSAwIDEuMDUtLjcyNSAxLjc3NVEyMS4wNSAxNSAyMCAxNXY0cTAgLjgyNS0uNTg3IDEuNDEzUTE4LjgyNSAyMSAxOCAyMWgtMy44cTAtMS4yNS0uNzg3LTIuMTI1UTEyLjYyNSAxOCAxMS41IDE4dC0xLjkxMi44NzVROC44IDE5Ljc1IDguOCAyMVpNNSAxOWgyLjEyNXEuNi0xLjY1IDEuOTI1LTIuMzI1UTEwLjM3NSAxNiAxMS41IDE2cTEuMTI1IDAgMi40NS42NzUgMS4zMjUuNjc1IDEuOTI1IDIuMzI1SDE4di02aDJxLjIgMCAuMzUtLjE1LjE1LS4xNS4xNS0uMzUgMC0uMi0uMTUtLjM1UTIwLjIgMTIgMjAgMTJoLTJWNmgtNlY0cTAtLjItLjE1LS4zNS0uMTUtLjE1LS4zNS0uMTUtLjIgMC0uMzUuMTVRMTEgMy44IDExIDR2Mkg1djIuMnExLjM1LjUgMi4xNzUgMS42NzVROCAxMS4wNSA4IDEyLjVxMCAxLjQyNS0uODI1IDIuNlQ1IDE2LjhabTcuNzUtNy43NVoiLz48L3N2Zz4=';
+Editor.colorDropperImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDgiIHdpZHRoPSI0OCI+PHBhdGggZD0iTTYgNDJ2LTguNGwxOC44NS0xOC44NS0zLjYtMy42TDIzLjMgOS4xbDQuNiA0LjZMMzUgNi42cS41NS0uNTUgMS4xNzUtLjU1dDEuMTc1LjU1bDQuMDUgNC4wNXEuNTUuNTUuNTUgMS4xNzVUNDEuNCAxM2wtNy4xIDcuMSA0LjYgNC42LTIuMDUgMi4wNS0zLjYtMy42TDE0LjQgNDJabTMtM2g0LjM1TDMxLjEgMjEuMjVsLTQuMzUtNC4zNUw5IDM0LjY1Wm0yMy4xNS0yMSA2LjItNi4yLTIuMTUtMi4xNS02LjIgNi4yWm0wIDBMMzAgMTUuODUgMzIuMTUgMThaIi8+PC9zdmc+';
+Editor.helpImage = Editor.lightHelpImage;
+Editor.checkmarkImage = Editor.lightCheckmarkImage;
+
+/**
+ * All fill styles supported by rough.js.
+ */
+Editor.roughFillStyles = [{val: 'auto', dispName: 'Auto'}, {val: 'hachure', dispName: 'Hachure'},
+ {val: 'solid', dispName: 'Solid'}, {val: 'zigzag', dispName: 'ZigZag'},
+ {val: 'cross-hatch', dispName: 'Cross Hatch'}, {val: 'dashed', dispName: 'Dashed'},
+ {val: 'zigzag-line', dispName: 'ZigZag Line'}];
+
+/**
+ * Fill styles for normal mode.
+ */
+Editor.fillStyles = [{val: 'auto', dispName: 'Auto'}, {val: 'hatch', dispName: 'Hatch'},
+ {val: 'solid', dispName: 'Solid'}, {val: 'dots', dispName: 'Dots'},
+ {val: 'cross-hatch', dispName: 'Cross Hatch'}, {val: 'dashed', dispName: 'Dashed'},
+ {val: 'zigzag-line', dispName: 'ZigZag Line'}];
+
+/**
+ * Graph themes for the format panel.
+ */
+Editor.themes = null;
+
+/**
+ * Specifies the image URL to be used for the transparent background.
+ */
+Editor.ctrlKey = (mxClient.IS_MAC) ? 'Cmd' : 'Ctrl';
+
+/**
+ * Specifies the image URL to be used for the transparent background.
+ */
+Editor.hintOffset = 20;
+
+/**
+ * Delay in ms to show shape picker on hover over blue arrows.
+ */
+Editor.shapePickerHoverDelay = 300;
+
+/**
+ * Specifies the image URL to be used for the transparent background.
+ */
+Editor.fitWindowBorders = null;
+
+/**
+ * Specifies if the diagram should be saved automatically if possible. Default
+ * is true.
+ */
+Editor.popupsAllowed = window.urlParams != null? urlParams['noDevice'] != '1' : true;
+
+/**
+ * Specifies if the html and whiteSpace styles should be removed on inserted cells.
+ */
+Editor.simpleLabels = false;
+
+/**
+ * Specifies if the native clipboard is enabled. Blocked in iframes for possible sandbox attribute.
+ * LATER: Check if actually blocked.
+ */
+Editor.enableNativeCipboard = window == window.top && !mxClient.IS_FF && navigator.clipboard != null;
+
+/**
+ * Dynamic change of dark mode for minimal and sketch theme.
+ */
+Editor.sketchMode = false;
+
+/**
+ * Dynamic change of dark mode for minimal and sketch theme.
+ */
+Editor.darkMode = false;
+
+/**
+ * Dynamic change of dark mode for minimal and sketch theme.
+ */
+//Editor.currentTheme = uiTheme;
+
+/**
+ * Dynamic change of dark mode for minimal and sketch theme.
+ */
+Editor.darkColor = '#18141D';
+
+/**
+ * Dynamic change of dark mode for minimal and sketch theme.
+ */
+Editor.lightColor = '#f0f0f0';
+
+/**
+ * Returns the current state of the dark mode.
+ */
+Editor.isDarkMode = function(value)
+{
+ return Editor.darkMode;
+};
+
+/**
+ * Returns true if the given URL is a PNG data URL.
+ */
+Editor.isPngDataUrl = function(url)
+{
+ return url != null && url.substring(0, 15) == 'data:image/png;'
+};
+
+/**
+ * Returns true if the given binary data is a PNG file.
+ */
+Editor.isPngData = function(data)
+{
+ return data.length > 8 && data.charCodeAt(0) == 137 && data.charCodeAt(1) == 80 &&
+ data.charCodeAt(2) == 78 && data.charCodeAt(3) == 71 && data.charCodeAt(4) == 13 &&
+ data.charCodeAt(5) == 10 && data.charCodeAt(6) == 26 && data.charCodeAt(7) == 10;
+};
+
+/**
+ * Converts HTML to plain text.
+ */
+Editor.convertHtmlToText = function(label)
+{
+ if (label != null)
+ {
+ var temp = document.createElement('div');
+ temp.innerHTML = Graph.sanitizeHtml(label);
+
+ return mxUtils.extractTextWithWhitespace(temp.childNodes)
+ }
+ else
+ {
+ return null;
+ }
+};
+
+/**
+ * Extracts the XML from the compressed or non-compressed text chunk.
+ */
+Editor.extractGraphModelFromPng = function(data)
+{
+ var result = null;
+
+ try
+ {
+ var base64 = data.substring(data.indexOf(',') + 1);
+
+ // Workaround for invalid character error in Safari
+ var binary = (window.atob && !mxClient.IS_SF) ? atob(base64) : Base64.decode(base64, true);
+
+ EditorUi.parsePng(binary, mxUtils.bind(this, function(pos, type, length)
+ {
+ var value = binary.substring(pos + 8, pos + 8 + length);
+
+ if (type == 'zTXt')
+ {
+ var idx = value.indexOf(String.fromCharCode(0));
+
+ if (value.substring(0, idx) == 'mxGraphModel')
+ {
+ // Workaround for Java URL Encoder using + for spaces, which isn't compatible with JS
+ var xmlData = pako.inflateRaw(Graph.stringToArrayBuffer(
+ value.substring(idx + 2)), {to: 'string'}).replace(/\+/g,' ');
+
+ if (xmlData != null && xmlData.length > 0)
+ {
+ result = xmlData;
+ }
+ }
+ }
+ // Uncompressed section is normally not used
+ else if (type == 'tEXt')
+ {
+ var vals = value.split(String.fromCharCode(0));
+
+ if (vals.length > 1 && (vals[0] == 'mxGraphModel' ||
+ vals[0] == 'mxfile'))
+ {
+ result = vals[1];
+ }
+ }
+
+ if (result != null || type == 'IDAT')
+ {
+ // Stops processing the file as our text chunks
+ // are always placed before the data section
+ return true;
+ }
+ }));
+ }
+ catch (e)
+ {
+ // ignores decoding errors
+ }
+
+ if (result != null && result.charAt(0) == '%')
+ {
+ result = decodeURIComponent(result);
+ }
+
+ // Workaround for double encoded content
+ if (result != null && result.charAt(0) == '%')
+ {
+ result = decodeURIComponent(result);
+ }
+
+ return result;
+};
+
+/**
+ * Soundex algorithm for strings.
+ * See https://www.codedrome.com/the-soundex-algorithm-in-javascript/
+ */
+Editor.soundex = function(name)
+{
+ if (name == null || name.length == 0)
+ {
+ return '';
+ }
+ else
+ {
+ var s = [];
+ var si = 1;
+ var c;
+
+ // Changed: s maps to 0 not 2 to ignore plurals
+ // ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ var mappings = '01230120022455012603010202';
+
+ s[0] = name[0].toUpperCase();
+
+ for(var i = 1, l = name.length; i < l; i++)
+ {
+ c = (name[i].toUpperCase()).charCodeAt(0) - 65;
+
+ if(c >= 0 && c <= 25)
+ {
+ if(mappings[c] != '0')
+ {
+ if(mappings[c] != s[si-1])
+ {
+ s[si] = mappings[c];
+ si++;
+ }
+
+ if(si > 3)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ if(si <= 3)
+ {
+ while(si <= 3)
+ {
+ s[si] = '0';
+ si++;
+ }
+ }
+
+ return s.join('');
+ }
+};
+
+/**
+ * Selects the given part of the input element.
+ */
+Editor.selectFilename = function(input)
+{
+ var end = input.value.lastIndexOf('.');
+
+ if (end > 0)
+ {
+ var ext = input.value.substring(end + 1);
+
+ if (ext != 'drawio')
+ {
+ if (mxUtils.indexOf(['png', 'svg', 'html', 'xml', 'pdf'], ext) >= 0)
+ {
+ var temp = input.value.lastIndexOf('.drawio.', end);
+
+ if (temp > 0)
+ {
+ end = temp;
+ }
+ }
+ }
+ }
+
+ end = (end > 0) ? end : input.value.length;
+ Editor.selectSubstring(input, 0, end);
+};
+
+/**
+ * Selects the given part of the input element.
+ */
+Editor.selectSubstring = function(input, startPos, endPos)
+{
+ input.focus();
+
+ if (typeof input.selectionStart != 'undefined')
+ {
+ input.selectionStart = startPos;
+ input.selectionEnd = endPos;
+ }
+ else if (document.selection && document.selection.createRange)
+ {
+ // IE branch
+ input.select();
+ var range = document.selection.createRange();
+ range.collapse(true);
+ range.moveEnd('character', endPos);
+ range.moveStart('character', startPos);
+ range.select();
+ }
+};
+
+/**
+ * Editor inherits from mxEventSource
+ */
+mxUtils.extend(Editor, mxEventSource);
+
+/**
+ * Stores initial state of mxClient.NO_FO.
+ */
+Editor.prototype.originalNoForeignObject = mxClient.NO_FO;
+
+/**
+ * Specifies the image URL to be used for the transparent background.
+ */
+Editor.prototype.transparentImage = (mxClient.IS_SVG) ? 'data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7' :
+ IMAGE_PATH + '/transparent.gif';
+
+/**
+ * Specifies if the canvas should be extended in all directions. Default is true.
+ */
+Editor.prototype.extendCanvas = true;
+
+/**
+ * Specifies if the app should run in chromeless mode. Default is false.
+ * This default is only used if the contructor argument is null.
+ */
+Editor.prototype.chromeless = false;
+
+/**
+ * Specifies the order of OK/Cancel buttons in dialogs. Default is true.
+ * Cancel first is used on Macs, Windows/Confluence uses cancel last.
+ */
+Editor.prototype.cancelFirst = true;
+
+/**
+ * Specifies if the editor is enabled. Default is true.
+ */
+Editor.prototype.enabled = true;
+
+/**
+ * Contains the name which was used for the last save. Default value is null.
+ */
+Editor.prototype.filename = null;
+
+/**
+ * Contains the current modified state of the diagram. This is false for
+ * new diagrams and after the diagram was saved.
+ */
+Editor.prototype.modified = false;
+
+/**
+ * Specifies if the diagram should be saved automatically if possible. Default
+ * is true.
+ */
+Editor.prototype.autosave = true;
+
+/**
+ * Specifies the top spacing for the initial page view. Default is 0.
+ */
+Editor.prototype.initialTopSpacing = 0;
+
+/**
+ * Specifies the app name. Default is document.title.
+ */
+Editor.prototype.appName = document.title;
+
+/**
+ *
+ */
+Editor.prototype.editBlankUrl = window.location.protocol + '//' + window.location.host + '/';
+
+/**
+ * Default value for the graph container overflow style.
+ */
+Editor.prototype.defaultGraphOverflow = 'hidden';
+
+/**
+ * Initializes the environment.
+ */
+Editor.prototype.init = function() { };
+
+/**
+ * Sets the XML node for the current diagram.
+ */
+Editor.prototype.isChromelessView = function()
+{
+ return this.chromeless;
+};
+
+/**
+ * Sets the XML node for the current diagram.
+ */
+Editor.prototype.setAutosave = function(value)
+{
+ this.autosave = value;
+ this.fireEvent(new mxEventObject('autosaveChanged'));
+};
+
+/**
+ *
+ */
+Editor.prototype.getEditBlankUrl = function(params)
+{
+ return this.editBlankUrl + params;
+}
+
+/**
+ *
+ */
+Editor.prototype.editAsNew = function(xml, title)
+{
+ var p = (title != null) ? '?title=' + encodeURIComponent(title) : '';
+
+ if (urlParams['ui'] != null)
+ {
+ p += ((p.length > 0) ? '&' : '?') + 'ui=' + urlParams['ui'];
+ }
+
+ if (typeof window.postMessage !== 'undefined' &&
+ (document.documentMode == null ||
+ document.documentMode >= 10))
+ {
+ var wnd = null;
+
+ var l = mxUtils.bind(this, function(evt)
+ {
+ if (evt.data == 'ready' && evt.source == wnd)
+ {
+ mxEvent.removeListener(window, 'message', l);
+ wnd.postMessage(xml, '*');
+ }
+ });
+
+ mxEvent.addListener(window, 'message', l);
+ wnd = this.graph.openLink(this.getEditBlankUrl(
+ p + ((p.length > 0) ? '&' : '?') +
+ 'client=1'), null, true);
+ }
+ else
+ {
+ this.graph.openLink(this.getEditBlankUrl(p) +
+ '#R' + encodeURIComponent(xml));
+ }
+};
+
+/**
+ * Sets the XML node for the current diagram.
+ */
+Editor.prototype.createGraph = function(themes, model)
+{
+ var graph = new Graph(null, model, null, null, themes);
+ graph.transparentBackground = false;
+
+ // Disables CSS transforms in Safari in chromeless mode
+ var graphIsCssTransformsSupported = graph.isCssTransformsSupported;
+ var self = this;
+
+ graph.isCssTransformsSupported = function()
+ {
+ return graphIsCssTransformsSupported.apply(this, arguments) &&
+ (!self.chromeless || !mxClient.IS_SF);
+ };
+
+ // Opens all links in a new window while editing
+ if (!this.chromeless)
+ {
+ graph.isBlankLink = function(href)
+ {
+ return !this.isExternalProtocol(href);
+ };
+ }
+
+ return graph;
+};
+
+/**
+ * Sets the XML node for the current diagram.
+ */
+Editor.prototype.resetGraph = function()
+{
+ this.graph.gridEnabled = this.graph.defaultGridEnabled && (!this.isChromelessView() || urlParams['grid'] == '1');
+ this.graph.graphHandler.guidesEnabled = true;
+ this.graph.setTooltips(true);
+ this.graph.setConnectable(true);
+ this.graph.foldingEnabled = true;
+ this.graph.scrollbars = this.graph.defaultScrollbars;
+ this.graph.pageVisible = this.graph.defaultPageVisible;
+ this.graph.pageBreaksVisible = this.graph.pageVisible;
+ this.graph.preferPageSize = this.graph.pageBreaksVisible;
+ this.graph.background = null;
+ this.graph.pageScale = mxGraph.prototype.pageScale;
+ this.graph.pageFormat = mxGraph.prototype.pageFormat;
+ this.graph.currentScale = 1;
+ this.graph.currentTranslate.x = 0;
+ this.graph.currentTranslate.y = 0;
+ this.updateGraphComponents();
+ this.graph.view.setScale(1);
+};
+
+/**
+ * Sets the XML node for the current diagram.
+ */
+Editor.prototype.readGraphState = function(node)
+{
+ var grid = node.getAttribute('grid');
+
+ if (grid == null || grid == '')
+ {
+ grid = this.graph.defaultGridEnabled ? '1' : '0';
+ }
+
+ this.graph.gridEnabled = grid != '0' && (!this.isChromelessView() || urlParams['grid'] == '1');
+ this.graph.gridSize = parseFloat(node.getAttribute('gridSize')) || mxGraph.prototype.gridSize;
+ this.graph.graphHandler.guidesEnabled = node.getAttribute('guides') != '0';
+ this.graph.setTooltips(node.getAttribute('tooltips') != '0');
+ this.graph.setConnectable(node.getAttribute('connect') != '0');
+ this.graph.connectionArrowsEnabled = node.getAttribute('arrows') != '0';
+ this.graph.foldingEnabled = node.getAttribute('fold') != '0';
+
+ if (this.isChromelessView() && this.graph.foldingEnabled)
+ {
+ this.graph.foldingEnabled = urlParams['nav'] == '1';
+ this.graph.cellRenderer.forceControlClickHandler = this.graph.foldingEnabled;
+ }
+
+ var ps = parseFloat(node.getAttribute('pageScale'));
+
+ if (!isNaN(ps) && ps > 0)
+ {
+ this.graph.pageScale = ps;
+ }
+ else
+ {
+ this.graph.pageScale = mxGraph.prototype.pageScale;
+ }
+
+ if (!this.graph.isLightboxView() && !this.graph.isViewer())
+ {
+ var pv = node.getAttribute('page');
+
+ if (pv != null)
+ {
+ this.graph.pageVisible = (pv != '0');
+ }
+ else
+ {
+ this.graph.pageVisible = this.graph.defaultPageVisible;
+ }
+ }
+ else
+ {
+ this.graph.pageVisible = false;
+ }
+
+ this.graph.pageBreaksVisible = this.graph.pageVisible;
+ this.graph.preferPageSize = this.graph.pageBreaksVisible;
+
+ var pw = parseFloat(node.getAttribute('pageWidth'));
+ var ph = parseFloat(node.getAttribute('pageHeight'));
+
+ if (!isNaN(pw) && !isNaN(ph))
+ {
+ this.graph.pageFormat = new mxRectangle(0, 0, pw, ph);
+ }
+
+ // Loads the persistent state settings
+ var bg = node.getAttribute('background');
+
+ if (bg != null && bg.length > 0)
+ {
+ this.graph.background = bg;
+ }
+ else
+ {
+ this.graph.background = null;
+ }
+};
+
+/**
+ * Sets the XML node for the current diagram.
+ */
+Editor.prototype.setGraphXml = function(node)
+{
+ if (node != null)
+ {
+ var dec = new mxCodec(node.ownerDocument);
+
+ if (node.nodeName == 'mxGraphModel')
+ {
+ this.graph.model.beginUpdate();
+
+ try
+ {
+ this.graph.model.clear();
+ this.graph.view.scale = 1;
+ this.readGraphState(node);
+ this.updateGraphComponents();
+ dec.decode(node, this.graph.getModel());
+ }
+ finally
+ {
+ this.graph.model.endUpdate();
+ }
+
+ this.fireEvent(new mxEventObject('resetGraphView'));
+ }
+ else if (node.nodeName == 'root')
+ {
+ this.resetGraph();
+
+ // Workaround for invalid XML output in Firefox 20 due to bug in mxUtils.getXml
+ var wrapper = dec.document.createElement('mxGraphModel');
+ wrapper.appendChild(node);
+
+ dec.decode(wrapper, this.graph.getModel());
+ this.updateGraphComponents();
+ this.fireEvent(new mxEventObject('resetGraphView'));
+ }
+ else
+ {
+ throw {
+ message: mxResources.get('cannotOpenFile'),
+ node: node,
+ toString: function() { return this.message; }
+ };
+ }
+ }
+ else
+ {
+ this.resetGraph();
+ this.graph.model.clear();
+ this.fireEvent(new mxEventObject('resetGraphView'));
+ }
+};
+
+/**
+ * Returns the XML node that represents the current diagram.
+ */
+Editor.prototype.getGraphXml = function(ignoreSelection)
+{
+ ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
+ var node = null;
+
+ if (ignoreSelection)
+ {
+ var enc = new mxCodec(mxUtils.createXmlDocument());
+ node = enc.encode(this.graph.getModel());
+ }
+ else
+ {
+ node = this.graph.encodeCells(mxUtils.sortCells(this.graph.model.getTopmostCells(
+ this.graph.getSelectionCells())));
+ }
+
+ if (this.graph.view.translate.x != 0 || this.graph.view.translate.y != 0)
+ {
+ node.setAttribute('dx', Math.round(this.graph.view.translate.x * 100) / 100);
+ node.setAttribute('dy', Math.round(this.graph.view.translate.y * 100) / 100);
+ }
+
+ node.setAttribute('grid', (this.graph.isGridEnabled()) ? '1' : '0');
+ node.setAttribute('gridSize', this.graph.gridSize);
+ node.setAttribute('guides', (this.graph.graphHandler.guidesEnabled) ? '1' : '0');
+ node.setAttribute('tooltips', (this.graph.tooltipHandler.isEnabled()) ? '1' : '0');
+ node.setAttribute('connect', (this.graph.connectionHandler.isEnabled()) ? '1' : '0');
+ node.setAttribute('arrows', (this.graph.connectionArrowsEnabled) ? '1' : '0');
+ node.setAttribute('fold', (this.graph.foldingEnabled) ? '1' : '0');
+ node.setAttribute('page', (this.graph.pageVisible) ? '1' : '0');
+ node.setAttribute('pageScale', this.graph.pageScale);
+ node.setAttribute('pageWidth', this.graph.pageFormat.width);
+ node.setAttribute('pageHeight', this.graph.pageFormat.height);
+
+ if (this.graph.background != null)
+ {
+ node.setAttribute('background', this.graph.background);
+ }
+
+ return node;
+};
+
+/**
+ * Keeps the graph container in sync with the persistent graph state
+ */
+Editor.prototype.updateGraphComponents = function()
+{
+ var graph = this.graph;
+
+ if (graph.container != null)
+ {
+ graph.view.validateBackground();
+ graph.container.style.overflow = (graph.scrollbars) ? 'auto' : this.defaultGraphOverflow;
+
+ this.fireEvent(new mxEventObject('updateGraphComponents'));
+ }
+};
+
+/**
+ * Sets the modified flag.
+ */
+Editor.prototype.setModified = function(value)
+{
+ this.modified = value;
+};
+
+/**
+ * Sets the filename.
+ */
+Editor.prototype.setFilename = function(value)
+{
+ this.filename = value;
+};
+
+/**
+ * Creates and returns a new undo manager.
+ */
+Editor.prototype.createUndoManager = function()
+{
+ var graph = this.graph;
+ var undoMgr = new mxUndoManager();
+
+ this.undoListener = function(sender, evt)
+ {
+ undoMgr.undoableEditHappened(evt.getProperty('edit'));
+ };
+
+ // Installs the command history
+ var listener = mxUtils.bind(this, function(sender, evt)
+ {
+ this.undoListener.apply(this, arguments);
+ });
+
+ graph.getModel().addListener(mxEvent.UNDO, listener);
+ graph.getView().addListener(mxEvent.UNDO, listener);
+
+ // Keeps the selection in sync with the history
+ var undoHandler = function(sender, evt)
+ {
+ var cand = graph.getSelectionCellsForChanges(evt.getProperty('edit').changes, function(change)
+ {
+ // Only selects changes to the cell hierarchy
+ return !(change instanceof mxChildChange);
+ });
+
+ if (cand.length > 0)
+ {
+ var model = graph.getModel();
+ var cells = [];
+
+ for (var i = 0; i < cand.length; i++)
+ {
+ if (graph.view.getState(cand[i]) != null)
+ {
+ cells.push(cand[i]);
+ }
+ }
+
+ graph.setSelectionCells(cells);
+ }
+ };
+
+ undoMgr.addListener(mxEvent.UNDO, undoHandler);
+ undoMgr.addListener(mxEvent.REDO, undoHandler);
+
+ return undoMgr;
+};
+
+/**
+ * Adds basic stencil set (no namespace).
+ */
+Editor.prototype.initStencilRegistry = function() { };
+
+/**
+ * Creates and returns a new undo manager.
+ */
+Editor.prototype.destroy = function()
+{
+ if (this.graph != null)
+ {
+ this.graph.destroy();
+ this.graph = null;
+ }
+};
+
+/**
+ * Class for asynchronously opening a new window and loading a file at the same
+ * time. This acts as a bridge between the open dialog and the new editor.
+ */
+OpenFile = function(done)
+{
+ this.producer = null;
+ this.consumer = null;
+ this.done = done;
+ this.args = null;
+};
+
+/**
+ * Registers the editor from the new window.
+ */
+OpenFile.prototype.setConsumer = function(value)
+{
+ this.consumer = value;
+ this.execute();
+};
+
+/**
+ * Sets the data from the loaded file.
+ */
+OpenFile.prototype.setData = function()
+{
+ this.args = arguments;
+ this.execute();
+};
+
+/**
+ * Displays an error message.
+ */
+OpenFile.prototype.error = function(msg)
+{
+ this.cancel(true);
+ mxUtils.alert(msg);
+};
+
+/**
+ * Consumes the data.
+ */
+OpenFile.prototype.execute = function()
+{
+ if (this.consumer != null && this.args != null)
+ {
+ this.cancel(false);
+ this.consumer.apply(this, this.args);
+ }
+};
+
+/**
+ * Cancels the operation.
+ */
+OpenFile.prototype.cancel = function(cancel)
+{
+ if (this.done != null)
+ {
+ this.done((cancel != null) ? cancel : true);
+ }
+};
+
+/**
+ * Basic dialogs that are available in the viewer (print dialog).
+ */
+function Dialog(editorUi, elt, w, h, modal, closable, onClose, noScroll, transparent, onResize, ignoreBgClick)
+{
+ this.editorUi = editorUi;
+ var dx = transparent? 57 : 0;
+ var w0 = w;
+ var h0 = h;
+ var padding = transparent? 0 : 64; //No padding needed for transparent dialogs
+
+ var ds = (!Editor.inlineFullscreen && editorUi.embedViewport != null) ?
+ mxUtils.clone(editorUi.embedViewport) : this.getDocumentSize();
+
+ // Workaround for print dialog offset in viewer lightbox
+ if (editorUi.embedViewport == null && window.innerHeight != null)
+ {
+ ds.height = window.innerHeight;
+ }
+
+ var dh = ds.height;
+ var left = Math.max(1, Math.round((ds.width - w - padding) / 2));
+ var top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));
+
+ // Keeps window size inside available space
+ elt.style.maxHeight = '100%';
+
+ w = (document.body != null) ? Math.min(w, document.body.scrollWidth - padding) : w;
+ h = Math.min(h, dh - padding);
+
+ // Increments zIndex to put subdialogs and background over existing dialogs and background
+ if (editorUi.dialogs.length > 0)
+ {
+ this.zIndex += editorUi.dialogs.length * 2;
+ }
+
+ if (this.bg == null)
+ {
+ this.bg = editorUi.createDiv('geBackground');
+ this.bg.style.position = 'absolute';
+ this.bg.style.height = dh + 'px';
+ this.bg.style.right = '0px';
+ this.bg.style.zIndex = this.zIndex - 2;
+
+ mxUtils.setOpacity(this.bg, this.bgOpacity);
+ }
+
+ var origin = mxUtils.getDocumentScrollOrigin(document);
+ this.bg.style.left = origin.x + 'px';
+ this.bg.style.top = origin.y + 'px';
+ left += origin.x;
+ top += origin.y;
+
+ if (!Editor.inlineFullscreen && editorUi.embedViewport != null)
+ {
+ this.bg.style.height = this.getDocumentSize().height + 'px';
+ top += editorUi.embedViewport.y;
+ left += editorUi.embedViewport.x;
+ }
+
+ if (modal)
+ {
+ document.body.appendChild(this.bg);
+ }
+
+ var div = editorUi.createDiv(transparent? 'geTransDialog' : 'geDialog');
+ var pos = this.getPosition(left, top, w, h);
+ left = pos.x;
+ top = pos.y;
+
+ div.style.width = w + 'px';
+ div.style.height = h + 'px';
+ div.style.left = left + 'px';
+ div.style.top = top + 'px';
+ div.style.zIndex = this.zIndex;
+
+ div.appendChild(elt);
+ document.body.appendChild(div);
+
+ // Adds vertical scrollbars if needed
+ if (!noScroll && elt.clientHeight > div.clientHeight - padding)
+ {
+ elt.style.overflowY = 'auto';
+ }
+
+ //Prevent horizontal scrollbar
+ elt.style.overflowX = 'hidden';
+
+ if (closable)
+ {
+ var img = document.createElement('img');
+
+ img.setAttribute('src', Dialog.prototype.closeImage);
+ img.setAttribute('title', mxResources.get('close'));
+ img.className = 'geDialogClose';
+ img.style.top = (top + 14) + 'px';
+ img.style.left = (left + w + 38 - dx) + 'px';
+ img.style.zIndex = this.zIndex;
+
+ mxEvent.addListener(img, 'click', mxUtils.bind(this, function()
+ {
+ editorUi.hideDialog(true);
+ }));
+
+ document.body.appendChild(img);
+ this.dialogImg = img;
+
+ if (!ignoreBgClick)
+ {
+ var mouseDownSeen = false;
+
+ mxEvent.addGestureListeners(this.bg, mxUtils.bind(this, function(evt)
+ {
+ mouseDownSeen = true;
+ }), null, mxUtils.bind(this, function(evt)
+ {
+ if (mouseDownSeen)
+ {
+ editorUi.hideDialog(true);
+ mouseDownSeen = false;
+ }
+ }));
+ }
+ }
+
+ this.resizeListener = mxUtils.bind(this, function()
+ {
+ if (onResize != null)
+ {
+ var newWH = onResize();
+
+ if (newWH != null)
+ {
+ w0 = w = newWH.w;
+ h0 = h = newWH.h;
+ }
+ }
+
+ var ds = (!Editor.inlineFullscreen && editorUi.embedViewport != null) ?
+ mxUtils.clone(editorUi.embedViewport) : this.getDocumentSize();
+ dh = ds.height;
+ this.bg.style.height = dh + 'px';
+
+ if (!Editor.inlineFullscreen && editorUi.embedViewport != null)
+ {
+ this.bg.style.height = this.getDocumentSize().height + 'px';
+ }
+
+ left = Math.max(1, Math.round((ds.width - w - padding) / 2));
+ top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));
+ w = (document.body != null) ? Math.min(w0, document.body.scrollWidth - padding) : w0;
+ h = Math.min(h0, dh - padding);
+
+ // var dh = ds.height;
+ var left = Math.max(1, Math.round((ds.width - w - padding) / 2));
+ var top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));
+
+ var pos = this.getPosition(left, top, w, h);
+ left = pos.x;
+ top = pos.y;
+
+ var origin = mxUtils.getDocumentScrollOrigin(document);
+ left += origin.x;
+ top += origin.y;
+
+ if (!Editor.inlineFullscreen && editorUi.embedViewport != null)
+ {
+ top += editorUi.embedViewport.y;
+ left += editorUi.embedViewport.x;
+ }
+
+ div.style.left = left + 'px';
+ div.style.top = top + 'px';
+ div.style.width = w + 'px';
+ div.style.height = h + 'px';
+
+ // Adds vertical scrollbars if needed
+ if (!noScroll && elt.clientHeight > div.clientHeight - padding)
+ {
+ elt.style.overflowY = 'auto';
+ }
+
+ if (this.dialogImg != null)
+ {
+ this.dialogImg.style.top = (top + 14) + 'px';
+ this.dialogImg.style.left = (left + w + 38 - dx) + 'px';
+ }
+ });
+
+ if (editorUi.embedViewport != null)
+ {
+ editorUi.addListener('embedViewportChanged', this.resizeListener);
+ }
+ else
+ {
+ mxEvent.addListener(window, 'resize', this.resizeListener);
+ }
+
+ this.onDialogClose = onClose;
+ this.container = div;
+
+ editorUi.editor.fireEvent(new mxEventObject('showDialog'));
+};
+
+/**
+ *
+ */
+Dialog.prototype.zIndex = mxPopupMenu.prototype.zIndex - 2;
+
+/**
+ *
+ */
+Dialog.prototype.noColorImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/nocolor.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkEzRDlBMUUwODYxMTExRTFCMzA4RDdDMjJBMEMxRDM3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkEzRDlBMUUxODYxMTExRTFCMzA4RDdDMjJBMEMxRDM3Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTNEOUExREU4NjExMTFFMUIzMDhEN0MyMkEwQzFEMzciIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTNEOUExREY4NjExMTFFMUIzMDhEN0MyMkEwQzFEMzciLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5xh3fmAAAABlBMVEX////MzMw46qqDAAAAGElEQVR42mJggAJGKGAYIIGBth8KAAIMAEUQAIElnLuQAAAAAElFTkSuQmCC';
+
+/**
+ *
+ */
+Dialog.prototype.closeImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/close.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAQMAAADaX5RTAAAABlBMVEV7mr3///+wksspAAAAAnRSTlP/AOW3MEoAAAAdSURBVAgdY9jXwCDDwNDRwHCwgeExmASygSL7GgB12QiqNHZZIwAAAABJRU5ErkJggg==';
+
+/**
+ *
+ */
+Dialog.prototype.clearImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/clear.gif' : 'data:image/gif;base64,R0lGODlhDQAKAIABAMDAwP///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUIzOEM1NzI4NjEyMTFFMUEzMkNDMUE3NjZERDE2QjIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUIzOEM1NzM4NjEyMTFFMUEzMkNDMUE3NjZERDE2QjIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QjM4QzU3MDg2MTIxMUUxQTMyQ0MxQTc2NkREMTZCMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QjM4QzU3MTg2MTIxMUUxQTMyQ0MxQTc2NkREMTZCMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAAEALAAAAAANAAoAAAIXTGCJebD9jEOTqRlttXdrB32PJ2ncyRQAOw==';
+
+/**
+ * Removes the dialog from the DOM.
+ */
+Dialog.prototype.bgOpacity = 80;
+
+/**
+ * Removes the dialog from the DOM.
+ */
+Dialog.prototype.getDocumentSize = function()
+{
+ return mxUtils.getDocumentSize();
+};
+
+/**
+ * Removes the dialog from the DOM.
+ */
+Dialog.prototype.getPosition = function(left, top)
+{
+ return new mxPoint(left, top);
+};
+
+/**
+ * Removes the dialog from the DOM.
+ */
+Dialog.prototype.close = function(cancel, isEsc)
+{
+ if (this.onDialogClose != null)
+ {
+ if (this.onDialogClose(cancel, isEsc) == false)
+ {
+ return false;
+ }
+
+ this.onDialogClose = null;
+ }
+
+ if (this.dialogImg != null && this.dialogImg.parentNode != null)
+ {
+ this.dialogImg.parentNode.removeChild(this.dialogImg);
+ this.dialogImg = null;
+ }
+
+ if (this.bg != null && this.bg.parentNode != null)
+ {
+ this.bg.parentNode.removeChild(this.bg);
+ }
+
+ if (this.editorUi.embedViewport != null)
+ {
+ this.editorUi.removeListener(this.resizeListener);
+ }
+ else
+ {
+ mxEvent.removeListener(window, 'resize', this.resizeListener);
+ }
+
+ if (this.container.parentNode != null)
+ {
+ this.container.parentNode.removeChild(this.container);
+ }
+};
+
+/**
+ *
+ */
+var ErrorDialog = function(editorUi, title, message, buttonText, fn, retry, buttonText2, fn2, hide, buttonText3, fn3)
+{
+ hide = (hide != null) ? hide : true;
+
+ var div = document.createElement('div');
+ div.style.textAlign = 'center';
+
+ if (title != null)
+ {
+ var hd = document.createElement('div');
+ hd.style.padding = '0px';
+ hd.style.margin = '0px';
+ hd.style.fontSize = '18px';
+ hd.style.paddingBottom = '16px';
+ hd.style.marginBottom = '10px';
+ hd.style.borderBottom = '1px solid #c0c0c0';
+ hd.style.color = 'gray';
+ hd.style.whiteSpace = 'nowrap';
+ hd.style.textOverflow = 'ellipsis';
+ hd.style.overflow = 'hidden';
+ mxUtils.write(hd, title);
+ hd.setAttribute('title', title);
+ div.appendChild(hd);
+ }
+
+ var p2 = document.createElement('div');
+ p2.style.lineHeight = '1.2em';
+ p2.style.padding = '6px';
+
+ if (typeof message === 'string')
+ {
+ message = message.replace(/\n/g, '
');
+ }
+
+ p2.innerHTML = message;
+ div.appendChild(p2);
+
+ var btns = document.createElement('div');
+ btns.style.marginTop = '12px';
+ btns.style.textAlign = 'center';
+
+ if (retry != null)
+ {
+ var retryBtn = mxUtils.button(mxResources.get('tryAgain'), function()
+ {
+ editorUi.hideDialog();
+ retry();
+ });
+ retryBtn.className = 'geBtn';
+ btns.appendChild(retryBtn);
+
+ btns.style.textAlign = 'center';
+ }
+
+ if (buttonText3 != null)
+ {
+ var btn3 = mxUtils.button(buttonText3, function()
+ {
+ if (fn3 != null)
+ {
+ fn3();
+ }
+ });
+
+ btn3.className = 'geBtn';
+ btns.appendChild(btn3);
+ }
+
+ var btn = mxUtils.button(buttonText, function()
+ {
+ if (hide)
+ {
+ editorUi.hideDialog();
+ }
+
+ if (fn != null)
+ {
+ fn();
+ }
+ });
+
+ btn.className = 'geBtn';
+ btns.appendChild(btn);
+
+ if (buttonText2 != null)
+ {
+ var mainBtn = mxUtils.button(buttonText2, function()
+ {
+ if (hide)
+ {
+ editorUi.hideDialog();
+ }
+
+ if (fn2 != null)
+ {
+ fn2();
+ }
+ });
+
+ mainBtn.className = 'geBtn gePrimaryBtn';
+ btns.appendChild(mainBtn);
+ }
+
+ this.init = function()
+ {
+ btn.focus();
+ };
+
+ div.appendChild(btns);
+
+ this.container = div;
+};
+
+/**
+ * Constructs a new print dialog.
+ */
+var PrintDialog = function(editorUi, title)
+{
+ this.create(editorUi, title);
+};
+
+/**
+ * Constructs a new print dialog.
+ */
+PrintDialog.prototype.create = function(editorUi)
+{
+ var graph = editorUi.editor.graph;
+ var row, td;
+
+ var table = document.createElement('table');
+ table.style.width = '100%';
+ table.style.height = '100%';
+ var tbody = document.createElement('tbody');
+
+ row = document.createElement('tr');
+
+ var onePageCheckBox = document.createElement('input');
+ onePageCheckBox.setAttribute('type', 'checkbox');
+ td = document.createElement('td');
+ td.setAttribute('colspan', '2');
+ td.style.fontSize = '10pt';
+ td.appendChild(onePageCheckBox);
+
+ var span = document.createElement('span');
+ mxUtils.write(span, ' ' + mxResources.get('fitPage'));
+ td.appendChild(span);
+
+ mxEvent.addListener(span, 'click', function(evt)
+ {
+ onePageCheckBox.checked = !onePageCheckBox.checked;
+ pageCountCheckBox.checked = !onePageCheckBox.checked;
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(onePageCheckBox, 'change', function()
+ {
+ pageCountCheckBox.checked = !onePageCheckBox.checked;
+ });
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ row = row.cloneNode(false);
+
+ var pageCountCheckBox = document.createElement('input');
+ pageCountCheckBox.setAttribute('type', 'checkbox');
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ td.appendChild(pageCountCheckBox);
+
+ var span = document.createElement('span');
+ mxUtils.write(span, ' ' + mxResources.get('posterPrint') + ':');
+ td.appendChild(span);
+
+ mxEvent.addListener(span, 'click', function(evt)
+ {
+ pageCountCheckBox.checked = !pageCountCheckBox.checked;
+ onePageCheckBox.checked = !pageCountCheckBox.checked;
+ mxEvent.consume(evt);
+ });
+
+ row.appendChild(td);
+
+ var pageCountInput = document.createElement('input');
+ pageCountInput.setAttribute('value', '1');
+ pageCountInput.setAttribute('type', 'number');
+ pageCountInput.setAttribute('min', '1');
+ pageCountInput.setAttribute('size', '4');
+ pageCountInput.setAttribute('disabled', 'disabled');
+ pageCountInput.style.width = '50px';
+
+ td = document.createElement('td');
+ td.style.fontSize = '10pt';
+ td.appendChild(pageCountInput);
+ mxUtils.write(td, ' ' + mxResources.get('pages') + ' (max)');
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ mxEvent.addListener(pageCountCheckBox, 'change', function()
+ {
+ if (pageCountCheckBox.checked)
+ {
+ pageCountInput.removeAttribute('disabled');
+ }
+ else
+ {
+ pageCountInput.setAttribute('disabled', 'disabled');
+ }
+
+ onePageCheckBox.checked = !pageCountCheckBox.checked;
+ });
+
+ row = row.cloneNode(false);
+
+ td = document.createElement('td');
+ mxUtils.write(td, mxResources.get('pageScale') + ':');
+ row.appendChild(td);
+
+ td = document.createElement('td');
+ var pageScaleInput = document.createElement('input');
+ pageScaleInput.setAttribute('value', '100 %');
+ pageScaleInput.setAttribute('size', '5');
+ pageScaleInput.style.width = '50px';
+
+ td.appendChild(pageScaleInput);
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+ td = document.createElement('td');
+ td.colSpan = 2;
+ td.style.paddingTop = '20px';
+ td.setAttribute('align', 'right');
+
+ // Overall scale for print-out to account for print borders in dialogs etc
+ function preview(print)
+ {
+ var autoOrigin = onePageCheckBox.checked || pageCountCheckBox.checked;
+ var printScale = parseInt(pageScaleInput.value) / 100;
+
+ if (isNaN(printScale))
+ {
+ printScale = 1;
+ pageScaleInput.value = '100%';
+ }
+
+ // Workaround to match available paper size in actual print output
+ if (mxClient.IS_SF)
+ {
+ printScale *= 0.75;
+ }
+
+ var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;
+ var scale = 1 / graph.pageScale;
+
+ if (autoOrigin)
+ {
+ var pageCount = (onePageCheckBox.checked) ? 1 : parseInt(pageCountInput.value);
+
+ if (!isNaN(pageCount))
+ {
+ scale = mxUtils.getScaleForPageCount(pageCount, graph, pf);
+ }
+ }
+
+ // Negative coordinates are cropped or shifted if page visible
+ var border = 0;
+ var x0 = 0;
+ var y0 = 0;
+
+ // Applies print scale
+ pf = mxRectangle.fromRectangle(pf);
+ pf.width = Math.ceil(pf.width * printScale);
+ pf.height = Math.ceil(pf.height * printScale);
+ scale *= printScale;
+
+ // Starts at first visible page
+ if (!autoOrigin && graph.pageVisible)
+ {
+ var layout = graph.getPageLayout();
+ x0 -= layout.x * pf.width;
+ y0 -= layout.y * pf.height;
+ }
+ else
+ {
+ autoOrigin = true;
+ }
+
+ var preview = PrintDialog.createPrintPreview(graph, scale, pf, border, x0, y0, autoOrigin);
+ preview.open();
+
+ if (print)
+ {
+ PrintDialog.printPreview(preview);
+ }
+ };
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ }
+
+ if (PrintDialog.previewEnabled)
+ {
+ var previewBtn = mxUtils.button(mxResources.get('preview'), function()
+ {
+ editorUi.hideDialog();
+ preview(false);
+ });
+ previewBtn.className = 'geBtn';
+ td.appendChild(previewBtn);
+ }
+
+ var printBtn = mxUtils.button(mxResources.get((!PrintDialog.previewEnabled) ? 'ok' : 'print'), function()
+ {
+ editorUi.hideDialog();
+ preview(true);
+ });
+ printBtn.className = 'geBtn gePrimaryBtn';
+ td.appendChild(printBtn);
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ }
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ table.appendChild(tbody);
+ this.container = table;
+};
+
+/**
+ * Constructs a new print dialog.
+ */
+PrintDialog.printPreview = function(preview)
+{
+ try
+ {
+ if (preview.wnd != null)
+ {
+ var printFn = function()
+ {
+ preview.wnd.focus();
+ preview.wnd.print();
+ preview.wnd.close();
+ };
+
+ // Workaround for rendering SVG output and
+ // make window available for printing
+ window.setTimeout(printFn, 500);
+ }
+ }
+ catch (e)
+ {
+ // ignores possible Access Denied
+ }
+};
+
+/**
+ * Constructs a new print dialog.
+ */
+PrintDialog.createPrintPreview = function(graph, scale, pf, border, x0, y0, autoOrigin)
+{
+ var preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);
+ preview.title = mxResources.get('preview');
+ preview.addPageCss = !mxClient.IS_SF;
+ preview.printBackgroundImage = true;
+ preview.autoOrigin = autoOrigin;
+ var bg = graph.background;
+
+ if (bg == null || bg == '' || bg == mxConstants.NONE)
+ {
+ bg = '#ffffff';
+ }
+
+ preview.backgroundColor = bg;
+
+ var writeHead = preview.writeHead;
+
+ // Adds a border in the preview
+ preview.writeHead = function(doc)
+ {
+ writeHead.apply(this, arguments);
+
+ doc.writeln('');
+ };
+
+ return preview;
+};
+
+/**
+ * Specifies if the preview button should be enabled. Default is true.
+ */
+PrintDialog.previewEnabled = true;
+
+/**
+ * Constructs a new page setup dialog.
+ */
+var PageSetupDialog = function(editorUi)
+{
+ var graph = editorUi.editor.graph;
+ var row, td;
+
+ var table = document.createElement('table');
+ table.style.width = '100%';
+ table.style.height = '100%';
+ var tbody = document.createElement('tbody');
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.verticalAlign = 'top';
+ td.style.fontSize = '10pt';
+ mxUtils.write(td, mxResources.get('paperSize') + ':');
+
+ row.appendChild(td);
+
+ td = document.createElement('td');
+ td.style.verticalAlign = 'top';
+ td.style.fontSize = '10pt';
+
+ var accessor = PageSetupDialog.addPageFormatPanel(td, 'pagesetupdialog', graph.pageFormat);
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ mxUtils.write(td, mxResources.get('gridSize') + ':');
+ row.appendChild(td);
+
+ td = document.createElement('td');
+ td.style.whiteSpace = 'nowrap';
+
+ var gridSizeInput = document.createElement('input');
+ gridSizeInput.setAttribute('type', 'number');
+ gridSizeInput.setAttribute('min', '0');
+ gridSizeInput.style.width = '40px';
+ gridSizeInput.style.marginLeft = '6px';
+
+ gridSizeInput.value = graph.getGridSize();
+ td.appendChild(gridSizeInput);
+
+ mxEvent.addListener(gridSizeInput, 'change', function()
+ {
+ var value = parseInt(gridSizeInput.value);
+ gridSizeInput.value = Math.max(1, (isNaN(value)) ? graph.getGridSize() : value);
+ });
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+ td = document.createElement('td');
+
+ mxUtils.write(td, mxResources.get('background') + ':');
+
+ row.appendChild(td);
+ td = document.createElement('td');
+
+ var changeImageLink = document.createElement('button');
+ changeImageLink.className = 'geBtn';
+ changeImageLink.style.margin = '0px';
+ mxUtils.write(changeImageLink, mxResources.get('change') + '...');
+
+ var imgPreview = document.createElement('div');
+ imgPreview.style.display = 'inline-block';
+ imgPreview.style.verticalAlign = 'middle';
+ imgPreview.style.backgroundPosition = 'center center';
+ imgPreview.style.backgroundRepeat = 'no-repeat';
+ imgPreview.style.backgroundSize = 'contain';
+ imgPreview.style.border = '1px solid lightGray';
+ imgPreview.style.borderRadius = '4px';
+ imgPreview.style.marginRight = '14px';
+ imgPreview.style.height = '32px';
+ imgPreview.style.width = '64px';
+ imgPreview.style.cursor = 'pointer';
+ imgPreview.style.padding = '4px';
+
+ var newBackgroundImage = graph.backgroundImage;
+ var newBackgroundColor = graph.background;
+ var newShadowVisible = graph.shadowVisible;
+
+ function updateBackgroundImage()
+ {
+ var img = newBackgroundImage;
+
+ if (img != null && img.originalSrc != null)
+ {
+ img = editorUi.createImageForPageLink(img.originalSrc, null);
+ }
+
+ if (img != null && img.src != null)
+ {
+ imgPreview.style.backgroundImage = 'url(' + img.src + ')';
+ imgPreview.style.display = 'inline-block';
+ }
+ else
+ {
+ imgPreview.style.backgroundImage = '';
+ imgPreview.style.display = 'none';
+ }
+
+ imgPreview.style.backgroundColor = '';
+
+ if (newBackgroundColor != null && newBackgroundColor != mxConstants.NONE)
+ {
+ imgPreview.style.backgroundColor = newBackgroundColor;
+ imgPreview.style.display = 'inline-block';
+ }
+ };
+
+ var changeImage = function(evt)
+ {
+ editorUi.showBackgroundImageDialog(function(image, failed, color, shadowVisible)
+ {
+ if (!failed)
+ {
+ if (image != null && image.src != null && Graph.isPageLink(image.src))
+ {
+ image = {originalSrc: image.src};
+ }
+
+ newBackgroundImage = image;
+ newShadowVisible = shadowVisible;
+ }
+
+ newBackgroundColor = color;
+ updateBackgroundImage();
+ }, newBackgroundImage, newBackgroundColor, true);
+
+ mxEvent.consume(evt);
+ };
+
+ mxEvent.addListener(changeImageLink, 'click', changeImage);
+ mxEvent.addListener(imgPreview, 'click', changeImage);
+
+ updateBackgroundImage();
+ td.appendChild(imgPreview);
+ td.appendChild(changeImageLink);
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ row = document.createElement('tr');
+ td = document.createElement('td');
+ td.colSpan = 2;
+ td.style.paddingTop = '16px';
+ td.setAttribute('align', 'right');
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ }
+
+ var applyBtn = mxUtils.button(mxResources.get('apply'), function()
+ {
+ editorUi.hideDialog();
+ var gridSize = parseInt(gridSizeInput.value);
+
+ if (!isNaN(gridSize) && graph.gridSize !== gridSize)
+ {
+ graph.setGridSize(gridSize);
+ }
+
+ var change = new ChangePageSetup(editorUi, newBackgroundColor,
+ newBackgroundImage, accessor.get());
+ change.ignoreColor = graph.background == newBackgroundColor;
+
+ var oldSrc = (graph.backgroundImage != null) ? graph.backgroundImage.src : null;
+ var newSrc = (newBackgroundImage != null) ? newBackgroundImage.src : null;
+
+ change.ignoreImage = oldSrc === newSrc;
+
+ if (newShadowVisible != null)
+ {
+ change.shadowVisible = newShadowVisible;
+ }
+
+ if (graph.pageFormat.width != change.previousFormat.width ||
+ graph.pageFormat.height != change.previousFormat.height ||
+ !change.ignoreColor || !change.ignoreImage||
+ change.shadowVisible != graph.shadowVisible)
+ {
+ graph.model.execute(change);
+ }
+ });
+ applyBtn.className = 'geBtn gePrimaryBtn';
+ td.appendChild(applyBtn);
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ }
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+
+ table.appendChild(tbody);
+ this.container = table;
+};
+
+/**
+ *
+ */
+PageSetupDialog.addPageFormatPanel = function(div, namePostfix, pageFormat, pageFormatListener)
+{
+ var formatName = 'format-' + namePostfix;
+
+ var portraitCheckBox = document.createElement('input');
+ portraitCheckBox.setAttribute('name', formatName);
+ portraitCheckBox.setAttribute('type', 'radio');
+ portraitCheckBox.setAttribute('value', 'portrait');
+
+ var landscapeCheckBox = document.createElement('input');
+ landscapeCheckBox.setAttribute('name', formatName);
+ landscapeCheckBox.setAttribute('type', 'radio');
+ landscapeCheckBox.setAttribute('value', 'landscape');
+
+ var paperSizeSelect = document.createElement('select');
+ paperSizeSelect.style.marginBottom = '8px';
+ paperSizeSelect.style.borderRadius = '4px';
+ paperSizeSelect.style.borderWidth = '1px';
+ paperSizeSelect.style.borderStyle = 'solid';
+ paperSizeSelect.style.width = '206px';
+
+ var formatDiv = document.createElement('div');
+ formatDiv.style.marginLeft = '4px';
+ formatDiv.style.width = '210px';
+ formatDiv.style.height = '24px';
+
+ portraitCheckBox.style.marginRight = '6px';
+ formatDiv.appendChild(portraitCheckBox);
+
+ var portraitSpan = document.createElement('span');
+ portraitSpan.style.maxWidth = '100px';
+ mxUtils.write(portraitSpan, mxResources.get('portrait'));
+ formatDiv.appendChild(portraitSpan);
+
+ landscapeCheckBox.style.marginLeft = '10px';
+ landscapeCheckBox.style.marginRight = '6px';
+ formatDiv.appendChild(landscapeCheckBox);
+
+ var landscapeSpan = document.createElement('span');
+ landscapeSpan.style.width = '100px';
+ mxUtils.write(landscapeSpan, mxResources.get('landscape'));
+ formatDiv.appendChild(landscapeSpan)
+
+ var customDiv = document.createElement('div');
+ customDiv.style.marginLeft = '4px';
+ customDiv.style.width = '210px';
+ customDiv.style.height = '24px';
+
+ var widthInput = document.createElement('input');
+ widthInput.setAttribute('size', '7');
+ widthInput.style.textAlign = 'right';
+ customDiv.appendChild(widthInput);
+ mxUtils.write(customDiv, ' in x ');
+
+ var heightInput = document.createElement('input');
+ heightInput.setAttribute('size', '7');
+ heightInput.style.textAlign = 'right';
+ customDiv.appendChild(heightInput);
+ mxUtils.write(customDiv, ' in');
+
+ formatDiv.style.display = 'none';
+ customDiv.style.display = 'none';
+
+ var pf = new Object();
+ var formats = PageSetupDialog.getFormats();
+
+ for (var i = 0; i < formats.length; i++)
+ {
+ var f = formats[i];
+ pf[f.key] = f;
+
+ var paperSizeOption = document.createElement('option');
+ paperSizeOption.setAttribute('value', f.key);
+ mxUtils.write(paperSizeOption, f.title);
+ paperSizeSelect.appendChild(paperSizeOption);
+ }
+
+ var customSize = false;
+
+ function listener(sender, evt, force)
+ {
+ if (force || (widthInput != document.activeElement && heightInput != document.activeElement))
+ {
+ var detected = false;
+
+ for (var i = 0; i < formats.length; i++)
+ {
+ var f = formats[i];
+
+ // Special case where custom was chosen
+ if (customSize)
+ {
+ if (f.key == 'custom')
+ {
+ paperSizeSelect.value = f.key;
+ customSize = false;
+ }
+ }
+ else if (f.format != null)
+ {
+ // Fixes wrong values for previous A4 and A5 page sizes
+ if (f.key == 'a4')
+ {
+ if (pageFormat.width == 826)
+ {
+ pageFormat = mxRectangle.fromRectangle(pageFormat);
+ pageFormat.width = 827;
+ }
+ else if (pageFormat.height == 826)
+ {
+ pageFormat = mxRectangle.fromRectangle(pageFormat);
+ pageFormat.height = 827;
+ }
+ }
+ else if (f.key == 'a5')
+ {
+ if (pageFormat.width == 584)
+ {
+ pageFormat = mxRectangle.fromRectangle(pageFormat);
+ pageFormat.width = 583;
+ }
+ else if (pageFormat.height == 584)
+ {
+ pageFormat = mxRectangle.fromRectangle(pageFormat);
+ pageFormat.height = 583;
+ }
+ }
+
+ if (pageFormat.width == f.format.width && pageFormat.height == f.format.height)
+ {
+ paperSizeSelect.value = f.key;
+ portraitCheckBox.setAttribute('checked', 'checked');
+ portraitCheckBox.defaultChecked = true;
+ portraitCheckBox.checked = true;
+ landscapeCheckBox.removeAttribute('checked');
+ landscapeCheckBox.defaultChecked = false;
+ landscapeCheckBox.checked = false;
+ detected = true;
+ }
+ else if (pageFormat.width == f.format.height && pageFormat.height == f.format.width)
+ {
+ paperSizeSelect.value = f.key;
+ portraitCheckBox.removeAttribute('checked');
+ portraitCheckBox.defaultChecked = false;
+ portraitCheckBox.checked = false;
+ landscapeCheckBox.setAttribute('checked', 'checked');
+ landscapeCheckBox.defaultChecked = true;
+ landscapeCheckBox.checked = true;
+ detected = true;
+ }
+ }
+ }
+
+ // Selects custom format which is last in list
+ if (!detected)
+ {
+ widthInput.value = pageFormat.width / 100;
+ heightInput.value = pageFormat.height / 100;
+ portraitCheckBox.setAttribute('checked', 'checked');
+ paperSizeSelect.value = 'custom';
+ formatDiv.style.display = 'none';
+ customDiv.style.display = '';
+ }
+ else
+ {
+ formatDiv.style.display = '';
+ customDiv.style.display = 'none';
+ }
+ }
+ };
+
+ listener();
+
+ div.appendChild(paperSizeSelect);
+ mxUtils.br(div);
+
+ div.appendChild(formatDiv);
+ div.appendChild(customDiv);
+
+ var currentPageFormat = pageFormat;
+
+ var update = function(evt, selectChanged)
+ {
+ var f = pf[paperSizeSelect.value];
+
+ if (f.format != null)
+ {
+ widthInput.value = f.format.width / 100;
+ heightInput.value = f.format.height / 100;
+ customDiv.style.display = 'none';
+ formatDiv.style.display = '';
+ }
+ else
+ {
+ formatDiv.style.display = 'none';
+ customDiv.style.display = '';
+ }
+
+ var wi = parseFloat(widthInput.value);
+
+ if (isNaN(wi) || wi <= 0)
+ {
+ widthInput.value = pageFormat.width / 100;
+ }
+
+ var hi = parseFloat(heightInput.value);
+
+ if (isNaN(hi) || hi <= 0)
+ {
+ heightInput.value = pageFormat.height / 100;
+ }
+
+ var newPageFormat = new mxRectangle(0, 0,
+ Math.floor(parseFloat(widthInput.value) * 100),
+ Math.floor(parseFloat(heightInput.value) * 100));
+
+ if (paperSizeSelect.value != 'custom' && landscapeCheckBox.checked)
+ {
+ newPageFormat = new mxRectangle(0, 0, newPageFormat.height, newPageFormat.width);
+ }
+
+ // Initial select of custom should not update page format to avoid update of combo
+ if ((!selectChanged || !customSize) && (newPageFormat.width != currentPageFormat.width ||
+ newPageFormat.height != currentPageFormat.height))
+ {
+ currentPageFormat = newPageFormat;
+
+ // Updates page format and reloads format panel
+ if (pageFormatListener != null)
+ {
+ pageFormatListener(currentPageFormat);
+ }
+ }
+ };
+
+ mxEvent.addListener(portraitSpan, 'click', function(evt)
+ {
+ portraitCheckBox.checked = true;
+ update(evt);
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(landscapeSpan, 'click', function(evt)
+ {
+ landscapeCheckBox.checked = true;
+ update(evt);
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(widthInput, 'blur', update);
+ mxEvent.addListener(widthInput, 'click', update);
+ mxEvent.addListener(heightInput, 'blur', update);
+ mxEvent.addListener(heightInput, 'click', update);
+ mxEvent.addListener(landscapeCheckBox, 'change', update);
+ mxEvent.addListener(portraitCheckBox, 'change', update);
+ mxEvent.addListener(paperSizeSelect, 'change', function(evt)
+ {
+ // Handles special case where custom was chosen
+ customSize = paperSizeSelect.value == 'custom';
+ update(evt, true);
+ });
+
+ update();
+
+ return {set: function(value)
+ {
+ pageFormat = value;
+ listener(null, null, true);
+ },get: function()
+ {
+ return currentPageFormat;
+ }, widthInput: widthInput,
+ heightInput: heightInput};
+};
+
+/**
+ *
+ */
+PageSetupDialog.getFormats = function()
+{
+ return [{key: 'letter', title: 'US-Letter (8,5" x 11")', format: mxConstants.PAGE_FORMAT_LETTER_PORTRAIT},
+ {key: 'legal', title: 'US-Legal (8,5" x 14")', format: new mxRectangle(0, 0, 850, 1400)},
+ {key: 'tabloid', title: 'US-Tabloid (11" x 17")', format: new mxRectangle(0, 0, 1100, 1700)},
+ {key: 'executive', title: 'US-Executive (7" x 10")', format: new mxRectangle(0, 0, 700, 1000)},
+ {key: 'a0', title: 'A0 (841 mm x 1189 mm)', format: new mxRectangle(0, 0, 3300, 4681)},
+ {key: 'a1', title: 'A1 (594 mm x 841 mm)', format: new mxRectangle(0, 0, 2339, 3300)},
+ {key: 'a2', title: 'A2 (420 mm x 594 mm)', format: new mxRectangle(0, 0, 1654, 2336)},
+ {key: 'a3', title: 'A3 (297 mm x 420 mm)', format: new mxRectangle(0, 0, 1169, 1654)},
+ {key: 'a4', title: 'A4 (210 mm x 297 mm)', format: mxConstants.PAGE_FORMAT_A4_PORTRAIT},
+ {key: 'a5', title: 'A5 (148 mm x 210 mm)', format: new mxRectangle(0, 0, 583, 827)},
+ {key: 'a6', title: 'A6 (105 mm x 148 mm)', format: new mxRectangle(0, 0, 413, 583)},
+ {key: 'a7', title: 'A7 (74 mm x 105 mm)', format: new mxRectangle(0, 0, 291, 413)},
+ {key: 'b4', title: 'B4 (250 mm x 353 mm)', format: new mxRectangle(0, 0, 980, 1390)},
+ {key: 'b5', title: 'B5 (176 mm x 250 mm)', format: new mxRectangle(0, 0, 690, 980)},
+ {key: '16-9', title: '16:9 (1600 x 900)', format: new mxRectangle(0, 0, 900, 1600)},
+ {key: '16-10', title: '16:10 (1920 x 1200)', format: new mxRectangle(0, 0, 1200, 1920)},
+ {key: '4-3', title: '4:3 (1600 x 1200)', format: new mxRectangle(0, 0, 1200, 1600)},
+ {key: 'custom', title: mxResources.get('custom'), format: null}];
+};
+
+/**
+ * Constructs a new filename dialog.
+ */
+var FilenameDialog = function(editorUi, filename, buttonText, fn, label, validateFn, content, helpLink, closeOnBtn, cancelFn, hints, w, lblW)
+{
+ closeOnBtn = (closeOnBtn != null) ? closeOnBtn : true;
+ var row, td;
+
+ var table = document.createElement('table');
+ var tbody = document.createElement('tbody');
+ table.style.position = 'absolute';
+ table.style.top = '30px';
+ table.style.left = '20px';
+
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.textOverflow = 'ellipsis';
+ td.style.whiteSpace = 'nowrap';
+ td.style.textAlign = 'right';
+ td.style.maxWidth = (lblW? lblW + 15 : 100) + 'px';
+ td.style.fontSize = '10pt';
+ td.style.width = (lblW? lblW : 84) + 'px';
+ mxUtils.write(td, (label || mxResources.get('filename')) + ':');
+
+ row.appendChild(td);
+
+ var nameInput = document.createElement('input');
+ nameInput.setAttribute('value', filename || '');
+ nameInput.style.marginLeft = '4px';
+ nameInput.style.width = (w != null) ? w + 'px' : '180px';
+
+ var genericBtn = mxUtils.button(buttonText, function()
+ {
+ if (validateFn == null || validateFn(nameInput.value))
+ {
+ if (closeOnBtn)
+ {
+ editorUi.hideDialog();
+ }
+
+ fn(nameInput.value);
+ }
+ });
+ genericBtn.className = 'geBtn gePrimaryBtn';
+
+ this.init = function()
+ {
+ if (label == null && content != null)
+ {
+ return;
+ }
+
+ if (hints != null)
+ {
+ Editor.selectFilename(nameInput);
+ }
+ else
+ {
+ nameInput.focus();
+
+ if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
+ {
+ nameInput.select();
+ }
+ else
+ {
+ document.execCommand('selectAll', false, null);
+ }
+ }
+
+ // Installs drag and drop handler for links
+ if (Graph.fileSupport)
+ {
+ // Setup the dnd listeners
+ var dlg = table.parentNode;
+
+ if (dlg != null)
+ {
+ var graph = editorUi.editor.graph;
+ var dropElt = null;
+
+ mxEvent.addListener(dlg, 'dragleave', function(evt)
+ {
+ if (dropElt != null)
+ {
+ dropElt.style.backgroundColor = '';
+ dropElt = null;
+ }
+
+ evt.stopPropagation();
+ evt.preventDefault();
+ });
+
+ mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt)
+ {
+ // IE 10 does not implement pointer-events so it can't have a drop highlight
+ if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10))
+ {
+ dropElt = nameInput;
+ dropElt.style.backgroundColor = '#ebf2f9';
+ }
+
+ evt.stopPropagation();
+ evt.preventDefault();
+ }));
+
+ mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt)
+ {
+ if (dropElt != null)
+ {
+ dropElt.style.backgroundColor = '';
+ dropElt = null;
+ }
+
+ if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
+ {
+ nameInput.value = decodeURIComponent(evt.dataTransfer.getData('text/uri-list'));
+ genericBtn.click();
+ }
+
+ evt.stopPropagation();
+ evt.preventDefault();
+ }));
+ }
+ }
+ };
+
+ td = document.createElement('td');
+ td.style.whiteSpace = 'nowrap';
+ td.appendChild(nameInput);
+ row.appendChild(td);
+
+ if (label != null || content == null)
+ {
+ tbody.appendChild(row);
+
+ if (hints != null)
+ {
+ td.appendChild(FilenameDialog.createTypeHint(editorUi, nameInput, hints));
+
+ if (editorUi.editor.diagramFileTypes != null)
+ {
+ row = document.createElement('tr');
+
+ td = document.createElement('td');
+ td.style.textOverflow = 'ellipsis';
+ td.style.textAlign = 'right';
+ td.style.maxWidth = '100px';
+ td.style.fontSize = '10pt';
+ td.style.width = '84px';
+ mxUtils.write(td, mxResources.get('type') + ':');
+ row.appendChild(td);
+
+ td = document.createElement('td');
+ td.style.whiteSpace = 'nowrap';
+ row.appendChild(td);
+
+ var typeSelect = FilenameDialog.createFileTypes(editorUi,
+ nameInput, editorUi.editor.diagramFileTypes);
+ typeSelect.style.marginLeft = '4px';
+ typeSelect.style.width = '198px';
+
+ td.appendChild(typeSelect);
+ nameInput.style.width = (w != null) ? (w - 40) + 'px' : '190px';
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+ }
+ }
+ }
+
+ if (content != null)
+ {
+ row = document.createElement('tr');
+ td = document.createElement('td');
+ td.colSpan = 2;
+ td.appendChild(content);
+ row.appendChild(td);
+ tbody.appendChild(row);
+ }
+
+ row = document.createElement('tr');
+ td = document.createElement('td');
+ td.colSpan = 2;
+ td.style.paddingTop = (hints != null) ? '12px' : '20px';
+ td.style.whiteSpace = 'nowrap';
+ td.setAttribute('align', 'right');
+
+ var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+ {
+ editorUi.hideDialog();
+
+ if (cancelFn != null)
+ {
+ cancelFn();
+ }
+ });
+ cancelBtn.className = 'geBtn';
+
+ if (editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ }
+
+ if (helpLink != null)
+ {
+ var helpBtn = mxUtils.button(mxResources.get('help'), function()
+ {
+ editorUi.editor.graph.openLink(helpLink);
+ });
+
+ helpBtn.className = 'geBtn';
+ td.appendChild(helpBtn);
+ }
+
+ mxEvent.addListener(nameInput, 'keypress', function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ genericBtn.click();
+ }
+ });
+
+ td.appendChild(genericBtn);
+
+ if (!editorUi.editor.cancelFirst)
+ {
+ td.appendChild(cancelBtn);
+ }
+
+ row.appendChild(td);
+ tbody.appendChild(row);
+ table.appendChild(tbody);
+
+ this.container = table;
+};
+
+/**
+ *
+ */
+FilenameDialog.filenameHelpLink = null;
+
+/**
+ *
+ */
+FilenameDialog.createTypeHint = function(ui, nameInput, hints)
+{
+ var hint = document.createElement('img');
+ hint.style.backgroundPosition = 'center bottom';
+ hint.style.backgroundRepeat = 'no-repeat';
+ hint.style.margin = '2px 0 0 4px';
+ hint.style.verticalAlign = 'top';
+ hint.style.cursor = 'pointer';
+ hint.style.height = '16px';
+ hint.style.width = '16px';
+ mxUtils.setOpacity(hint, 70);
+
+ var nameChanged = function()
+ {
+ hint.setAttribute('src', Editor.helpImage);
+ hint.setAttribute('title', mxResources.get('help'));
+
+ for (var i = 0; i < hints.length; i++)
+ {
+ if (hints[i].ext.length > 0 && nameInput.value.toLowerCase().substring(
+ nameInput.value.length - hints[i].ext.length - 1) == '.' + hints[i].ext)
+ {
+ hint.setAttribute('title', mxResources.get(hints[i].title));
+ break;
+ }
+ }
+ };
+
+ mxEvent.addListener(nameInput, 'keyup', nameChanged);
+ mxEvent.addListener(nameInput, 'change', nameChanged);
+ mxEvent.addListener(hint, 'click', function(evt)
+ {
+ var title = hint.getAttribute('title');
+
+ if (hint.getAttribute('src') == Editor.helpImage)
+ {
+ ui.editor.graph.openLink(FilenameDialog.filenameHelpLink);
+ }
+ else if (title != '')
+ {
+ ui.showError(null, title, mxResources.get('help'), function()
+ {
+ ui.editor.graph.openLink(FilenameDialog.filenameHelpLink);
+ }, null, mxResources.get('ok'), null, null, null, 340, 90);
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ nameChanged();
+
+ return hint;
+};
+
+/**
+ *
+ */
+FilenameDialog.createFileTypes = function(editorUi, nameInput, types)
+{
+ var typeSelect = document.createElement('select');
+
+ for (var i = 0; i < types.length; i++)
+ {
+ var typeOption = document.createElement('option');
+ typeOption.setAttribute('value', i);
+ mxUtils.write(typeOption, mxResources.get(types[i].description) +
+ ' (.' + types[i].extension + ')');
+ typeSelect.appendChild(typeOption);
+ }
+
+ mxEvent.addListener(typeSelect, 'change', function(evt)
+ {
+ var ext = types[typeSelect.value].extension;
+ var idx2 = nameInput.value.lastIndexOf('.drawio.');
+ var idx = (idx2 > 0) ? idx2 : nameInput.value.lastIndexOf('.');
+
+ if (ext != 'drawio')
+ {
+ ext = 'drawio.' + ext;
+ }
+
+ if (idx > 0)
+ {
+ nameInput.value = nameInput.value.substring(0, idx + 1) + ext;
+ }
+ else
+ {
+ nameInput.value = nameInput.value + '.' + ext;
+ }
+
+ if ('createEvent' in document)
+ {
+ var changeEvent = document.createEvent('HTMLEvents');
+ changeEvent.initEvent('change', false, true);
+ nameInput.dispatchEvent(changeEvent);
+ }
+ else
+ {
+ nameInput.fireEvent('onchange');
+ }
+ });
+
+ var nameInputChanged = function(evt)
+ {
+ var name = nameInput.value.toLowerCase();
+ var active = 0;
+
+ // Finds current extension
+ for (var i = 0; i < types.length; i++)
+ {
+ var ext = types[i].extension;
+ var subExt = null;
+
+ if (ext != 'drawio')
+ {
+ subExt = ext;
+ ext = '.drawio.' + ext;
+ }
+
+ if (name.substring(name.length - ext.length - 1) == '.' + ext ||
+ (subExt != null && name.substring(name.length - subExt.length - 1) == '.' + subExt))
+ {
+ active = i;
+ break;
+ }
+ }
+
+ typeSelect.value = active;
+ };
+
+ mxEvent.addListener(nameInput, 'change', nameInputChanged);
+ mxEvent.addListener(nameInput, 'keyup', nameInputChanged);
+ nameInputChanged();
+
+ return typeSelect;
+};
+
+/**
+ *
+ */
+var WrapperWindow = function(editorUi, title, x, y, w, h, fn)
+{
+ var div = editorUi.createSidebarContainer();
+ fn(div);
+
+ this.window = new mxWindow(title, div, x, y, w, h, true, true);
+ this.window.destroyOnClose = false;
+ this.window.setMaximizable(false);
+ this.window.setResizable(true);
+ this.window.setClosable(true);
+ this.window.setVisible(true);
+
+ editorUi.installResizeHandler(this, true);
+
+ // Workaround for text selection starting in Safari
+ // when dragging shapes outside of window
+ if (mxClient.IS_SF)
+ {
+ this.window.div.onselectstart = mxUtils.bind(this, function(evt)
+ {
+ if (evt == null)
+ {
+ evt = window.event;
+ }
+
+ return (evt != null && editorUi.isSelectionAllowed(evt));
+ });
+ }
+};
+
+/**
+ * Static overrides
+ */
+(function()
+{
+ // Uses HTML for background pages (to support grid background image)
+ mxGraphView.prototype.validateBackgroundPage = function()
+ {
+ var graph = this.graph;
+
+ if (graph.container != null && !graph.transparentBackground)
+ {
+ if (graph.pageVisible)
+ {
+ var bounds = this.getBackgroundPageBounds();
+
+ if (this.backgroundPageShape == null)
+ {
+ // Finds first element in graph container
+ var firstChild = graph.container.firstChild;
+
+ while (firstChild != null && firstChild.nodeType != mxConstants.NODETYPE_ELEMENT)
+ {
+ firstChild = firstChild.nextSibling;
+ }
+
+ if (firstChild != null)
+ {
+ this.backgroundPageShape = this.createBackgroundPageShape(bounds);
+ this.backgroundPageShape.scale = 1;
+
+ // IE8 standards has known rendering issues inside mxWindow but not using shadow is worse.
+ this.backgroundPageShape.isShadow = true;
+ this.backgroundPageShape.dialect = mxConstants.DIALECT_STRICTHTML;
+ this.backgroundPageShape.init(graph.container);
+
+ // Required for the browser to render the background page in correct order
+ firstChild.style.position = 'absolute';
+ graph.container.insertBefore(this.backgroundPageShape.node, firstChild);
+ this.backgroundPageShape.redraw();
+
+ this.backgroundPageShape.node.className = 'geBackgroundPage';
+
+ // Adds listener for double click handling on background
+ mxEvent.addListener(this.backgroundPageShape.node, 'dblclick',
+ mxUtils.bind(this, function(evt)
+ {
+ graph.dblClick(evt);
+ })
+ );
+
+ // Adds basic listeners for graph event dispatching outside of the
+ // container and finishing the handling of a single gesture
+ mxEvent.addGestureListeners(this.backgroundPageShape.node,
+ mxUtils.bind(this, function(evt)
+ {
+ graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
+ }),
+ mxUtils.bind(this, function(evt)
+ {
+ // Hides the tooltip if mouse is outside container
+ if (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover())
+ {
+ graph.tooltipHandler.hide();
+ }
+
+ if (graph.isMouseDown && !mxEvent.isConsumed(evt))
+ {
+ graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
+ }
+ }),
+ mxUtils.bind(this, function(evt)
+ {
+ graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
+ })
+ );
+ }
+ }
+ else
+ {
+ this.backgroundPageShape.scale = 1;
+ this.backgroundPageShape.bounds = bounds;
+ this.backgroundPageShape.redraw();
+ }
+ }
+ else if (this.backgroundPageShape != null)
+ {
+ this.backgroundPageShape.destroy();
+ this.backgroundPageShape = null;
+ }
+
+ this.validateBackgroundStyles();
+ }
+ };
+
+ // Updates the CSS of the background to draw the grid
+ mxGraphView.prototype.validateBackgroundStyles = function(factor, cx, cy)
+ {
+ var graph = this.graph;
+ factor = (factor != null) ? factor : 1;
+ var color = (graph.background == null || graph.background == mxConstants.NONE) ?
+ graph.defaultPageBackgroundColor : graph.background;
+ var gridColor = (color != null && this.gridColor != color.toLowerCase()) ? this.gridColor : '#ffffff';
+ var image = 'none';
+ var position = '';
+
+ if (graph.isGridEnabled() || graph.gridVisible)
+ {
+ var phase = 10;
+
+ if (mxClient.IS_SVG)
+ {
+ // Generates the SVG required for drawing the dynamic grid
+ image = unescape(encodeURIComponent(this.createSvgGrid(gridColor, factor)));
+ image = (window.btoa) ? btoa(image) : Base64.encode(image, true);
+ image = 'url(' + 'data:image/svg+xml;base64,' + image + ')'
+ phase = graph.gridSize * this.scale * this.gridSteps * factor;
+ }
+ else
+ {
+ // Fallback to grid wallpaper with fixed size
+ image = 'url(' + this.gridImage + ')';
+ }
+
+ var x0 = 0;
+ var y0 = 0;
+
+ var dx = (cx != null) ? cx - this.translate.x * this.scale : 0;
+ var dy = (cy != null) ? cy - this.translate.y * this.scale : 0;
+
+ var p = graph.gridSize * this.scale * this.gridSteps;
+ var ddx = dx % p;
+ var ddy = dy % p;
+
+ if (graph.view.backgroundPageShape != null)
+ {
+ var bds = this.getBackgroundPageBounds();
+
+ x0 = 1 + bds.x;
+ y0 = 1 + bds.y;
+ }
+
+ // Computes the offset to maintain origin for grid
+ position = -Math.round(phase - mxUtils.mod(this.translate.x * this.scale - x0 + dx, phase) + ddx * factor) + 'px ' +
+ -Math.round(phase - mxUtils.mod(this.translate.y * this.scale - y0 + dy, phase) + ddy * factor) + 'px';
+ }
+
+ var canvas = graph.view.canvas;
+
+ if (canvas.ownerSVGElement != null)
+ {
+ canvas = canvas.ownerSVGElement;
+ }
+
+ var useDiagramBackground = !Editor.isDarkMode() && graph.enableDiagramBackground;
+
+ if (graph.view.backgroundPageShape != null)
+ {
+ graph.view.backgroundPageShape.node.style.backgroundPosition = position;
+ graph.view.backgroundPageShape.node.style.backgroundImage = image;
+ graph.view.backgroundPageShape.node.style.backgroundColor = color;
+ graph.view.backgroundPageShape.node.style.borderColor = graph.defaultPageBorderColor;
+ graph.container.className = 'geDiagramContainer geDiagramBackdrop';
+ canvas.style.backgroundImage = 'none';
+ canvas.style.backgroundColor = '';
+
+ if (useDiagramBackground)
+ {
+ graph.container.style.backgroundColor = graph.diagramBackgroundColor;
+ }
+ else
+ {
+ graph.container.style.backgroundColor = '';
+ }
+ }
+ else
+ {
+ graph.container.className = 'geDiagramContainer';
+ canvas.style.backgroundPosition = position;
+ canvas.style.backgroundImage = image;
+
+ if (useDiagramBackground && (graph.background == null ||
+ graph.background == mxConstants.NONE))
+ {
+ canvas.style.backgroundColor = graph.diagramBackgroundColor;
+ graph.container.style.backgroundColor = '';
+ }
+ else
+ {
+ canvas.style.backgroundColor = color;
+ }
+ }
+ };
+
+ // Returns the SVG required for painting the background grid.
+ mxGraphView.prototype.createSvgGrid = function(color, factor)
+ {
+ factor = (factor != null) ? factor : 1;
+ var tmp = this.graph.gridSize * this.scale * factor;
+
+ while (tmp < this.minGridSize)
+ {
+ tmp *= 2;
+ }
+
+ var tmp2 = this.gridSteps * tmp;
+
+ // Small grid lines
+ var d = [];
+
+ for (var i = 1; i < this.gridSteps; i++)
+ {
+ var tmp3 = i * tmp;
+ d.push('M 0 ' + tmp3 + ' L ' + tmp2 + ' ' + tmp3 + ' M ' + tmp3 + ' 0 L ' + tmp3 + ' ' + tmp2);
+ }
+
+ // KNOWN: Rounding errors for certain scales (eg. 144%, 121% in Chrome, FF and Safari). Workaround
+ // in Chrome is to use 100% for the svg size, but this results in blurred grid for large diagrams.
+ var size = tmp2;
+ var svg = '';
+
+ return svg;
+ };
+
+ // Adds panning for the grid with no page view and disabled scrollbars
+ var mxGraphPanGraph = mxGraph.prototype.panGraph;
+ mxGraph.prototype.panGraph = function(dx, dy)
+ {
+ mxGraphPanGraph.apply(this, arguments);
+
+ if (this.shiftPreview1 != null)
+ {
+ var canvas = this.view.canvas;
+
+ if (canvas.ownerSVGElement != null)
+ {
+ canvas = canvas.ownerSVGElement;
+ }
+
+ var phase = this.gridSize * this.view.scale * this.view.gridSteps;
+ var position = -Math.round(phase - mxUtils.mod(this.view.translate.x * this.view.scale + dx, phase)) + 'px ' +
+ -Math.round(phase - mxUtils.mod(this.view.translate.y * this.view.scale + dy, phase)) + 'px';
+ canvas.style.backgroundPosition = position;
+ }
+ };
+
+ // Draws page breaks only within the page
+ mxGraph.prototype.updatePageBreaks = function(visible, width, height)
+ {
+ var scale = this.view.scale;
+ var tr = this.view.translate;
+ var fmt = this.pageFormat;
+ var ps = scale * this.pageScale;
+
+ var bounds2 = this.view.getBackgroundPageBounds();
+
+ width = bounds2.width;
+ height = bounds2.height;
+ var bounds = new mxRectangle(scale * tr.x, scale * tr.y, fmt.width * ps, fmt.height * ps);
+
+ // Does not show page breaks if the scale is too small
+ visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;
+
+ var horizontalCount = (visible) ? Math.ceil(height / bounds.height) - 1 : 0;
+ var verticalCount = (visible) ? Math.ceil(width / bounds.width) - 1 : 0;
+ var right = bounds2.x + width;
+ var bottom = bounds2.y + height;
+
+ if (this.horizontalPageBreaks == null && horizontalCount > 0)
+ {
+ this.horizontalPageBreaks = [];
+ }
+
+ if (this.verticalPageBreaks == null && verticalCount > 0)
+ {
+ this.verticalPageBreaks = [];
+ }
+
+ var drawPageBreaks = mxUtils.bind(this, function(breaks)
+ {
+ if (breaks != null)
+ {
+ var count = (breaks == this.horizontalPageBreaks) ? horizontalCount : verticalCount;
+
+ for (var i = 0; i <= count; i++)
+ {
+ var pts = (breaks == this.horizontalPageBreaks) ?
+ [new mxPoint(Math.round(bounds2.x), Math.round(bounds2.y + (i + 1) * bounds.height)),
+ new mxPoint(Math.round(right), Math.round(bounds2.y + (i + 1) * bounds.height))] :
+ [new mxPoint(Math.round(bounds2.x + (i + 1) * bounds.width), Math.round(bounds2.y)),
+ new mxPoint(Math.round(bounds2.x + (i + 1) * bounds.width), Math.round(bottom))];
+
+ if (breaks[i] != null)
+ {
+ breaks[i].points = pts;
+ breaks[i].redraw();
+ }
+ else
+ {
+ var pageBreak = new mxPolyline(pts, this.pageBreakColor);
+ pageBreak.dialect = this.dialect;
+ pageBreak.isDashed = this.pageBreakDashed;
+ pageBreak.pointerEvents = false;
+ pageBreak.init(this.view.backgroundPane);
+ pageBreak.redraw();
+
+ breaks[i] = pageBreak;
+ }
+ }
+
+ for (var i = count; i < breaks.length; i++)
+ {
+ if (breaks[i] != null)
+ {
+ breaks[i].destroy();
+ }
+ }
+
+ breaks.splice(count, breaks.length - count);
+ }
+ });
+
+ drawPageBreaks(this.horizontalPageBreaks);
+ drawPageBreaks(this.verticalPageBreaks);
+ };
+
+ // Disables removing relative children and table rows and cells from parents
+ var mxGraphHandlerShouldRemoveCellsFromParent = mxGraphHandler.prototype.shouldRemoveCellsFromParent;
+ mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt)
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (this.graph.isTableCell(cells[i]) || this.graph.isTableRow(cells[i]))
+ {
+ return false;
+ }
+ else if (this.graph.getModel().isVertex(cells[i]))
+ {
+ var geo = this.graph.getCellGeometry(cells[i]);
+
+ if (geo != null && geo.relative)
+ {
+ return false;
+ }
+ }
+ }
+
+ return mxGraphHandlerShouldRemoveCellsFromParent.apply(this, arguments);
+ };
+
+ // Overrides to ignore hotspot only for target terminal
+ var mxConnectionHandlerCreateMarker = mxConnectionHandler.prototype.createMarker;
+ mxConnectionHandler.prototype.createMarker = function()
+ {
+ var marker = mxConnectionHandlerCreateMarker.apply(this, arguments);
+
+ marker.intersects = mxUtils.bind(this, function(state, evt)
+ {
+ if (this.isConnecting())
+ {
+ return true;
+ }
+
+ return mxCellMarker.prototype.intersects.apply(marker, arguments);
+ });
+
+ return marker;
+ };
+
+ // Creates background page shape
+ mxGraphView.prototype.createBackgroundPageShape = function(bounds)
+ {
+ return new mxRectangleShape(bounds, '#ffffff', this.graph.defaultPageBorderColor);
+ };
+
+ // Fits the number of background pages to the graph
+ mxGraphView.prototype.getBackgroundPageBounds = function()
+ {
+ var gb = this.getGraphBounds();
+
+ // Computes unscaled, untranslated graph bounds
+ var x = (gb.width > 0) ? gb.x / this.scale - this.translate.x : 0;
+ var y = (gb.height > 0) ? gb.y / this.scale - this.translate.y : 0;
+ var w = gb.width / this.scale;
+ var h = gb.height / this.scale;
+
+ var fmt = this.graph.pageFormat;
+ var ps = this.graph.pageScale;
+
+ var pw = fmt.width * ps;
+ var ph = fmt.height * ps;
+
+ var x0 = Math.floor(Math.min(0, x) / pw);
+ var y0 = Math.floor(Math.min(0, y) / ph);
+ var xe = Math.ceil(Math.max(1, x + w) / pw);
+ var ye = Math.ceil(Math.max(1, y + h) / ph);
+
+ var rows = xe - x0;
+ var cols = ye - y0;
+
+ var bounds = new mxRectangle(this.scale * (this.translate.x + x0 * pw), this.scale *
+ (this.translate.y + y0 * ph), this.scale * rows * pw, this.scale * cols * ph);
+
+ return bounds;
+ };
+
+ // Add panning for background page in VML
+ var graphPanGraph = mxGraph.prototype.panGraph;
+ mxGraph.prototype.panGraph = function(dx, dy)
+ {
+ graphPanGraph.apply(this, arguments);
+
+ if ((this.dialect != mxConstants.DIALECT_SVG && this.view.backgroundPageShape != null) &&
+ (!this.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.container)))
+ {
+ this.view.backgroundPageShape.node.style.marginLeft = dx + 'px';
+ this.view.backgroundPageShape.node.style.marginTop = dy + 'px';
+ }
+ };
+
+ /**
+ * Consumes click events for disabled menu items.
+ */
+ var mxPopupMenuAddItem = mxPopupMenu.prototype.addItem;
+ mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled)
+ {
+ var result = mxPopupMenuAddItem.apply(this, arguments);
+
+ if (enabled != null && !enabled)
+ {
+ mxEvent.addListener(result, 'mousedown', function(evt)
+ {
+ mxEvent.consume(evt);
+ });
+ }
+
+ return result;
+ };
+
+ /**
+ * Selects tables before cells and rows.
+ */
+ var mxGraphHandlerIsPropagateSelectionCell = mxGraphHandler.prototype.isPropagateSelectionCell;
+ mxGraphHandler.prototype.isPropagateSelectionCell = function(cell, immediate, me)
+ {
+ var result = false;
+ var parent = this.graph.model.getParent(cell)
+
+ if (immediate)
+ {
+ var geo = (this.graph.model.isEdge(cell)) ? null :
+ this.graph.getCellGeometry(cell);
+
+ result = !this.graph.model.isEdge(parent) &&
+ !this.graph.isSiblingSelected(cell) &&
+ ((geo != null && geo.relative) ||
+ !this.graph.isContainer(parent) ||
+ this.graph.isPart(cell));
+ }
+ else
+ {
+ result = mxGraphHandlerIsPropagateSelectionCell.apply(this, arguments);
+
+ if (this.graph.isTableCell(cell) || this.graph.isTableRow(cell))
+ {
+ var table = parent;
+
+ if (!this.graph.isTable(table))
+ {
+ table = this.graph.model.getParent(table);
+ }
+
+ result = !this.graph.selectionCellsHandler.isHandled(table) ||
+ (this.graph.isCellSelected(table) && this.graph.isToggleEvent(me.getEvent())) ||
+ (this.graph.isCellSelected(cell) && !this.graph.isToggleEvent(me.getEvent())) ||
+ (this.graph.isTableCell(cell) && this.graph.isCellSelected(parent));
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * Returns last selected ancestor
+ */
+ mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me)
+ {
+ var cell = me.getCell();
+ var model = this.graph.getModel();
+ var parent = model.getParent(cell);
+ var state = this.graph.view.getState(parent);
+ var selected = this.graph.isCellSelected(cell);
+
+ while (state != null && (model.isVertex(parent) || model.isEdge(parent)))
+ {
+ var temp = this.graph.isCellSelected(parent);
+ selected = selected || temp;
+
+ if (temp || (!selected && (this.graph.isTableCell(cell) ||
+ this.graph.isTableRow(cell))))
+ {
+ cell = parent;
+ }
+
+ parent = model.getParent(parent);
+ }
+
+ return cell;
+ };
+
+})();
+
+
+/**
+ * Adds drawing and update of the shape number.
+ */
+mxGraphView.prototype.redrawEnumerationState = function(state)
+{
+ var enumerate = mxUtils.getValue(state.style, 'enumerate', 0) == '1';
+
+ if (enumerate && state.secondLabel == null)
+ {
+ state.secondLabel = new mxText('', new mxRectangle(),
+ mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM);
+ state.secondLabel.size = 12;
+ state.secondLabel.state = state;
+ state.secondLabel.dialect = mxConstants.DIALECT_STRICTHTML;
+
+ this.graph.cellRenderer.initializeLabel(state, state.secondLabel);
+ }
+ else if (!enumerate && state.secondLabel != null)
+ {
+ state.secondLabel.destroy();
+ state.secondLabel = null;
+ }
+
+ var shape = state.secondLabel;
+
+ if (shape != null)
+ {
+ var s = state.view.scale;
+ var value = this.createEnumerationValue(state);
+ var bounds = this.graph.model.isVertex(state.cell) ?
+ new mxRectangle(state.x + state.width - 4 * s, state.y + 4 * s, 0, 0) :
+ mxRectangle.fromPoint(state.view.getPoint(state));
+
+ if (!shape.bounds.equals(bounds) || shape.value != value || shape.scale != s)
+ {
+ shape.bounds = bounds;
+ shape.value = value;
+ shape.scale = s;
+ shape.redraw();
+ }
+ }
+};
+
+Editor.GUID_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+Editor.GUID_LENGTH = 20;
+Editor.guid = function(a) {
+ a = null != a ? a : Editor.GUID_LENGTH;
+ for (var b = [], c = 0; c < a; c++)
+ b.push(Editor.GUID_ALPHABET.charAt(Math.floor(Math.random() * Editor.GUID_ALPHABET.length)));
+ return b.join("")
+}
\ No newline at end of file
diff --git a/static/cherry/drawio_demo/EditorUi.js b/static/cherry/drawio_demo/EditorUi.js
new file mode 100644
index 000000000..61ac7631a
--- /dev/null
+++ b/static/cherry/drawio_demo/EditorUi.js
@@ -0,0 +1,6184 @@
+/**
+ * Copyright (c) 2006-2012, JGraph Ltd
+ */
+/**
+ * Constructs a new graph editor
+ */
+EditorUi = function (editor, container, lightbox) {
+ mxEventSource.call(this);
+
+ this.destroyFunctions = [];
+ this.editor = editor || new Editor();
+ this.container = container || document.body;
+
+ var ui = this;
+ var graph = this.editor.graph;
+ graph.lightbox = lightbox;
+
+ // Overrides graph bounds to include background images
+ var graphGetGraphBounds = graph.getGraphBounds;
+
+ graph.getGraphBounds = function () {
+ var bounds = graphGetGraphBounds.apply(this, arguments);
+ var img = this.backgroundImage;
+
+ if (img != null && img.width != null && img.height != null) {
+ var t = this.view.translate;
+ var s = this.view.scale;
+
+ bounds = mxRectangle.fromRectangle(bounds);
+ bounds.add(new mxRectangle(
+ (t.x + img.x) * s, (t.y + img.y) * s,
+ img.width * s, img.height * s));
+ }
+
+ return bounds;
+ };
+
+ // Faster scrollwheel zoom is possible with CSS transforms
+ if (graph.useCssTransforms) {
+ this.lazyZoomDelay = 0;
+ }
+
+ // Pre-fetches submenu image or replaces with embedded image if supported
+ if (mxClient.IS_SVG) {
+ mxPopupMenu.prototype.submenuImage = 'data:image/gif;base64,R0lGODlhCQAJAIAAAP///zMzMyH5BAEAAAAALAAAAAAJAAkAAAIPhI8WebHsHopSOVgb26AAADs=';
+ }
+ else {
+ new Image().src = mxPopupMenu.prototype.submenuImage;
+ }
+
+ // Pre-fetches connect image
+ if (!mxClient.IS_SVG && mxConnectionHandler.prototype.connectImage != null) {
+ new Image().src = mxConnectionHandler.prototype.connectImage.src;
+ }
+
+ // Installs selection state listener
+ this.selectionStateListener = mxUtils.bind(this, function (sender, evt) {
+ this.clearSelectionState();
+ });
+
+ graph.getSelectionModel().addListener(mxEvent.CHANGE, this.selectionStateListener);
+ graph.getModel().addListener(mxEvent.CHANGE, this.selectionStateListener);
+ graph.addListener(mxEvent.EDITING_STARTED, this.selectionStateListener);
+ graph.addListener(mxEvent.EDITING_STOPPED, this.selectionStateListener);
+ graph.getView().addListener('unitChanged', this.selectionStateListener);
+
+ // Disables graph and forced panning in chromeless mode
+ if (this.editor.chromeless && !this.editor.editable) {
+ this.footerHeight = 0;
+ graph.isEnabled = function () { return false; };
+ graph.panningHandler.isForcePanningEvent = function (me) {
+ return !mxEvent.isPopupTrigger(me.getEvent());
+ };
+ }
+
+ // Creates the user interface
+ this.actions = new Actions(this);
+ this.menus = this.createMenus();
+
+ if (!graph.standalone) {
+ // Stores the current style and assigns it to new cells
+ var styles = ['rounded', 'shadow', 'glass', 'dashed', 'dashPattern', 'labelBackgroundColor',
+ 'labelBorderColor', 'comic', 'sketch', 'fillWeight', 'hachureGap', 'hachureAngle', 'jiggle',
+ 'disableMultiStroke', 'disableMultiStrokeFill', 'fillStyle', 'curveFitting',
+ 'simplification', 'sketchStyle', 'pointerEvents', 'strokeColor', 'strokeWidth'];
+ var connectStyles = ['shape', 'edgeStyle', 'curved', 'rounded', 'elbow', 'jumpStyle', 'jumpSize',
+ 'comic', 'sketch', 'fillWeight', 'hachureGap', 'hachureAngle', 'jiggle',
+ 'disableMultiStroke', 'disableMultiStrokeFill', 'fillStyle', 'curveFitting',
+ 'simplification', 'sketchStyle'];
+ // Styles to be ignored if applyAll is false
+ var ignoredEdgeStyles = ['curved', 'sourcePerimeterSpacing', 'targetPerimeterSpacing',
+ 'startArrow', 'startFill', 'startSize', 'endArrow', 'endFill', 'endSize'];
+ var vertexStyleIgnored = false;
+ var edgeStyleIgnored = false;
+
+ // Note: Everything that is not in styles is ignored (styles is augmented below)
+ this.setDefaultStyle = function (cell) {
+ try {
+ if (graph.getModel().isEdge(cell)) {
+ edgeStyleIgnored = false;
+ }
+ else {
+ vertexStyleIgnored = false;
+ }
+
+ var style = graph.getCellStyle(cell, false);
+ var values = [];
+ var keys = [];
+
+ for (var key in style) {
+ values.push(style[key]);
+ keys.push(key);
+ }
+
+ // Resets current style
+ if (graph.getModel().isEdge(cell)) {
+ graph.currentEdgeStyle = {};
+ }
+ else {
+ graph.currentVertexStyle = {}
+ }
+
+ this.fireEvent(new mxEventObject('styleChanged',
+ 'keys', keys, 'values', values,
+ 'cells', [cell], 'force', true));
+
+ // Blocks update of default style with style changes
+ // once the it was set using this function
+ if (graph.getModel().isEdge(cell)) {
+ edgeStyleIgnored = true;
+ }
+ else {
+ vertexStyleIgnored = true;
+ }
+ }
+ catch (e) {
+ this.handleError(e);
+ }
+ };
+
+ this.clearDefaultStyle = function () {
+ graph.currentEdgeStyle = mxUtils.clone(graph.defaultEdgeStyle);
+ graph.currentVertexStyle = mxUtils.clone(graph.defaultVertexStyle);
+ edgeStyleIgnored = false;
+ vertexStyleIgnored = false;
+
+ // Updates UI
+ this.fireEvent(new mxEventObject('styleChanged', 'keys', [], 'values', [], 'cells', []));
+ };
+
+ // Keys that should be ignored if the cell has a value (known: new default for all cells is html=1 so
+ // for the html key this effecticely only works for edges inserted via the connection handler)
+ var valueStyles = ['fontFamily', 'fontSource', 'fontSize', 'fontColor'];
+
+ for (var i = 0; i < valueStyles.length; i++) {
+ if (mxUtils.indexOf(styles, valueStyles[i]) < 0) {
+ styles.push(valueStyles[i]);
+ }
+ }
+
+ // Keys that always update the current edge style regardless of selection
+ var alwaysEdgeStyles = ['edgeStyle', 'startArrow', 'startFill', 'startSize', 'endArrow',
+ 'endFill', 'endSize'];
+
+ // Keys that are ignored together (if one appears all are ignored)
+ var keyGroups = [['startArrow', 'startFill', 'endArrow', 'endFill'],
+ ['startSize', 'endSize'],
+ ['sourcePerimeterSpacing', 'targetPerimeterSpacing'],
+ ['fillColor', 'gradientColor', 'gradientDirection'],
+ ['opacity'],
+ ['html']];
+
+ // Adds all keys used above to the styles array
+ for (var i = 0; i < keyGroups.length; i++) {
+ for (var j = 0; j < keyGroups[i].length; j++) {
+ styles.push(keyGroups[i][j]);
+ }
+ }
+
+ for (var i = 0; i < connectStyles.length; i++) {
+ if (mxUtils.indexOf(styles, connectStyles[i]) < 0) {
+ styles.push(connectStyles[i]);
+ }
+ }
+
+ // Implements a global current style for edges and vertices that is applied to new cells
+ var insertHandler = function (cells, asText, model, vertexStyle, edgeStyle, applyAll, recurse) {
+ vertexStyle = (vertexStyle != null) ? vertexStyle : graph.currentVertexStyle;
+ edgeStyle = (edgeStyle != null) ? edgeStyle : graph.currentEdgeStyle;
+ applyAll = (applyAll != null) ? applyAll : true;
+
+ model = (model != null) ? model : graph.getModel();
+
+ if (recurse) {
+ var temp = [];
+
+ for (var i = 0; i < cells.length; i++) {
+ temp = temp.concat(model.getDescendants(cells[i]));
+ }
+
+ cells = temp;
+ }
+
+ model.beginUpdate();
+ try {
+ for (var i = 0; i < cells.length; i++) {
+ var cell = cells[i];
+ var isText = asText;
+ var appliedStyles;
+
+ // Applies basic text styles for cells with text class
+ if (cell.style != null && !isText) {
+ pairs = cell.style.split(';');
+ isText = isText || mxUtils.indexOf(pairs, 'text') >= 0;
+ }
+
+ if (isText) {
+ // Applies only basic text styles
+ appliedStyles = ['fontSize', 'fontFamily', 'fontColor'];
+ }
+ else {
+ // Removes styles defined in the cell style from the styles to be applied
+ var cellStyle = model.getStyle(cell);
+ var tokens = (cellStyle != null) ? cellStyle.split(';') : [];
+ appliedStyles = styles.slice();
+
+ for (var j = 0; j < tokens.length; j++) {
+ var tmp = tokens[j];
+ var pos = tmp.indexOf('=');
+
+ if (pos >= 0) {
+ var key = tmp.substring(0, pos);
+ var index = mxUtils.indexOf(appliedStyles, key);
+
+ if (index >= 0) {
+ appliedStyles.splice(index, 1);
+ }
+
+ // Handles special cases where one defined style ignores other styles
+ for (var k = 0; k < keyGroups.length; k++) {
+ var group = keyGroups[k];
+
+ if (mxUtils.indexOf(group, key) >= 0) {
+ for (var l = 0; l < group.length; l++) {
+ var index2 = mxUtils.indexOf(appliedStyles, group[l]);
+
+ if (index2 >= 0) {
+ appliedStyles.splice(index2, 1);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Applies the current style to the cell
+ var edge = model.isEdge(cell);
+ var current = (edge) ? edgeStyle : vertexStyle;
+ var newStyle = model.getStyle(cell);
+
+ for (var j = 0; j < appliedStyles.length; j++) {
+ var key = appliedStyles[j];
+ var styleValue = current[key];
+
+ if (styleValue != null && key != 'edgeStyle' && (key != 'shape' || edge)) {
+ // Special case: Connect styles are not applied here but in the connection handler
+ if (!edge || applyAll || mxUtils.indexOf(ignoredEdgeStyles, key) < 0) {
+ newStyle = mxUtils.setStyle(newStyle, key, styleValue);
+ }
+ }
+ }
+
+ if (Editor.simpleLabels) {
+ newStyle = mxUtils.setStyle(mxUtils.setStyle(
+ newStyle, 'html', null), 'whiteSpace', null);
+ }
+
+ model.setStyle(cell, newStyle);
+ }
+ }
+ finally {
+ model.endUpdate();
+ }
+
+ return cells;
+ };
+
+ graph.addListener('cellsInserted', function (sender, evt) {
+ insertHandler(evt.getProperty('cells'), null, null, null, null, true, true);
+ });
+
+ graph.addListener('textInserted', function (sender, evt) {
+ insertHandler(evt.getProperty('cells'), true);
+ });
+
+ this.insertHandler = insertHandler;
+
+ this.createDivs();
+ this.createUi();
+ this.refresh();
+
+ // Disables HTML and text selection
+ var textEditing = mxUtils.bind(this, function (evt) {
+ if (evt == null) {
+ evt = window.event;
+ }
+
+ return graph.isEditing() || (evt != null && this.isSelectionAllowed(evt));
+ });
+
+ // Disables text selection while not editing and no dialog visible
+ if (this.container == document.body) {
+ this.menubarContainer.onselectstart = textEditing;
+ this.menubarContainer.onmousedown = textEditing;
+ this.toolbarContainer.onselectstart = textEditing;
+ this.toolbarContainer.onmousedown = textEditing;
+ this.diagramContainer.onselectstart = textEditing;
+ this.diagramContainer.onmousedown = textEditing;
+ this.sidebarContainer.onselectstart = textEditing;
+ this.sidebarContainer.onmousedown = textEditing;
+ this.formatContainer.onselectstart = textEditing;
+ this.formatContainer.onmousedown = textEditing;
+ this.footerContainer.onselectstart = textEditing;
+ this.footerContainer.onmousedown = textEditing;
+
+ if (this.tabContainer != null) {
+ // Mouse down is needed for drag and drop
+ this.tabContainer.onselectstart = textEditing;
+ }
+
+ // Workaround for rubberband selection on iPadOS 16
+ // Avoid on previous versions to allow label editing
+ if (mxClient.IS_IOS) {
+ function iOSversion() {
+ if (/iP(hone|od|ad)/.test(navigator.platform)) {
+ // supports iOS 2.0 and later:
+ var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
+
+ return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
+ }
+ }
+
+ var ver = iOSversion();
+
+ if (ver != null && ver[0] >= 16) {
+ mxUtils.setPrefixedStyle(this.menubarContainer.style, 'userSelect', 'none');
+ mxUtils.setPrefixedStyle(this.diagramContainer.style, 'userSelect', 'none');
+ mxUtils.setPrefixedStyle(this.sidebarContainer.style, 'userSelect', 'none');
+ mxUtils.setPrefixedStyle(this.formatContainer.style, 'userSelect', 'none');
+ mxUtils.setPrefixedStyle(this.footerContainer.style, 'userSelect', 'none');
+
+ if (this.tabContainer != null) {
+ mxUtils.setPrefixedStyle(this.tabContainer.style, 'userSelect', 'none');
+ }
+ }
+ }
+ }
+
+ // And uses built-in context menu while editing
+ if (!this.editor.chromeless || this.editor.editable) {
+ // Allows context menu for links in hints
+ var linkHandler = function (evt) {
+ if (evt != null) {
+ var source = mxEvent.getSource(evt);
+
+ if (source.nodeName == 'A') {
+ while (source != null) {
+ if (source.className == 'geHint') {
+ return true;
+ }
+
+ source = source.parentNode;
+ }
+ }
+ }
+
+ return textEditing(evt);
+ };
+
+ if (mxClient.IS_IE && (typeof (document.documentMode) === 'undefined' || document.documentMode < 9)) {
+ mxEvent.addListener(this.diagramContainer, 'contextmenu', linkHandler);
+ }
+ else {
+ // Allows browser context menu outside of diagram and sidebar
+ this.diagramContainer.oncontextmenu = linkHandler;
+ }
+ }
+ else {
+ graph.panningHandler.usePopupTrigger = false;
+ }
+
+ // Contains the main graph instance inside the given panel
+ graph.init(this.diagramContainer);
+
+ // Improves line wrapping for in-place editor
+ if (mxClient.IS_SVG && graph.view.getDrawPane() != null) {
+ var root = graph.view.getDrawPane().ownerSVGElement;
+
+ if (root != null) {
+ root.style.position = 'absolute';
+ }
+ }
+
+ // Creates hover icons
+ this.hoverIcons = this.createHoverIcons();
+
+ // Hides hover icons when cells are moved
+ if (graph.graphHandler != null) {
+ var graphHandlerStart = graph.graphHandler.start;
+
+ graph.graphHandler.start = function () {
+ if (ui.hoverIcons != null) {
+ ui.hoverIcons.reset();
+ }
+
+ graphHandlerStart.apply(this, arguments);
+ };
+ }
+
+ // Adds tooltip when mouse is over scrollbars to show space-drag panning option
+ mxEvent.addListener(this.diagramContainer, 'mousemove', mxUtils.bind(this, function (evt) {
+ var off = mxUtils.getOffset(this.diagramContainer);
+
+ if (mxEvent.getClientX(evt) - off.x - this.diagramContainer.clientWidth > 0 ||
+ mxEvent.getClientY(evt) - off.y - this.diagramContainer.clientHeight > 0) {
+ this.diagramContainer.setAttribute('title', mxResources.get('panTooltip'));
+ }
+ else {
+ this.diagramContainer.removeAttribute('title');
+ }
+ }));
+
+ // Overrides hovericons to disable while space key is pressed
+ var hoverIconsIsResetEvent = this.hoverIcons.isResetEvent;
+
+ this.hoverIcons.isResetEvent = function (evt, allowShift) {
+ return ui.isSpaceDown() || hoverIconsIsResetEvent.apply(this, arguments);
+ };
+
+ this.keydownHandler = mxUtils.bind(this, function (evt) {
+ if (evt.which == 16 /* Shift */) {
+ this.shiftDown = true;
+ }
+ else if (evt.which == 32 /* Space */ && !graph.isEditing()) {
+ this.spaceDown = true;
+ this.hoverIcons.reset();
+ graph.container.style.cursor = 'move';
+
+ // Disables scroll after space keystroke with scrollbars
+ if (!graph.isEditing() && mxEvent.getSource(evt) == graph.container) {
+ mxEvent.consume(evt);
+ }
+ }
+ else if (!mxEvent.isConsumed(evt) && evt.keyCode == 27 /* Escape */) {
+ this.hideDialog(null, true);
+ }
+ });
+
+ mxEvent.addListener(document, 'keydown', this.keydownHandler);
+
+ this.keyupHandler = mxUtils.bind(this, function (evt) {
+ graph.container.style.cursor = '';
+ this.spaceDown = false;
+ this.shiftDown = false;
+ });
+
+ mxEvent.addListener(document, 'keyup', this.keyupHandler);
+
+ // Forces panning for middle and right mouse buttons
+ var panningHandlerIsForcePanningEvent = graph.panningHandler.isForcePanningEvent;
+ graph.panningHandler.isForcePanningEvent = function (me) {
+ // Ctrl+left button is reported as right button in FF on Mac
+ return panningHandlerIsForcePanningEvent.apply(this, arguments) ||
+ ui.isSpaceDown() || (mxEvent.isMouseEvent(me.getEvent()) &&
+ (this.usePopupTrigger || !mxEvent.isPopupTrigger(me.getEvent())) &&
+ ((!mxEvent.isControlDown(me.getEvent()) &&
+ mxEvent.isRightMouseButton(me.getEvent())) ||
+ mxEvent.isMiddleMouseButton(me.getEvent())));
+ };
+
+ // Ctrl/Cmd+Enter applies editing value except in Safari where Ctrl+Enter creates
+ // a new line (while Enter creates a new paragraph and Shift+Enter stops)
+ var cellEditorIsStopEditingEvent = graph.cellEditor.isStopEditingEvent;
+ graph.cellEditor.isStopEditingEvent = function (evt) {
+ return cellEditorIsStopEditingEvent.apply(this, arguments) ||
+ (evt.keyCode == 13 && ((!mxClient.IS_SF && mxEvent.isControlDown(evt)) ||
+ (mxClient.IS_MAC && mxEvent.isMetaDown(evt)) ||
+ (mxClient.IS_SF && mxEvent.isShiftDown(evt))));
+ };
+
+ // Adds space+wheel for zoom
+ var graphIsZoomWheelEvent = graph.isZoomWheelEvent;
+
+ graph.isZoomWheelEvent = function () {
+ return ui.isSpaceDown() || graphIsZoomWheelEvent.apply(this, arguments);
+ };
+
+ // Switches toolbar for text editing
+ var textMode = false;
+ var fontMenu = null;
+ var sizeMenu = null;
+ var nodes = null;
+
+ var updateToolbar = mxUtils.bind(this, function () {
+ if (this.toolbar != null && textMode != graph.cellEditor.isContentEditing()) {
+ var node = this.toolbar.container.firstChild;
+ var newNodes = [];
+
+ while (node != null) {
+ var tmp = node.nextSibling;
+
+ if (mxUtils.indexOf(this.toolbar.staticElements, node) < 0) {
+ node.parentNode.removeChild(node);
+ newNodes.push(node);
+ }
+
+ node = tmp;
+ }
+
+ // Saves references to special items
+ var tmp1 = this.toolbar.fontMenu;
+ var tmp2 = this.toolbar.sizeMenu;
+
+ if (nodes == null) {
+ this.toolbar.createTextToolbar();
+ }
+ else {
+ for (var i = 0; i < nodes.length; i++) {
+ this.toolbar.container.appendChild(nodes[i]);
+ }
+
+ // Restores references to special items
+ this.toolbar.fontMenu = fontMenu;
+ this.toolbar.sizeMenu = sizeMenu;
+ }
+
+ textMode = graph.cellEditor.isContentEditing();
+ fontMenu = tmp1;
+ sizeMenu = tmp2;
+ nodes = newNodes;
+ }
+ });
+
+ // Overrides cell editor to update toolbar
+ var cellEditorStartEditing = graph.cellEditor.startEditing;
+ graph.cellEditor.startEditing = function () {
+ cellEditorStartEditing.apply(this, arguments);
+ updateToolbar();
+
+ if (graph.cellEditor.isContentEditing()) {
+ var updating = false;
+
+ var updateCssHandler = function () {
+ if (!updating) {
+ updating = true;
+
+ window.setTimeout(function () {
+ var node = graph.getSelectedEditingElement();
+
+ if (node != null) {
+ var css = mxUtils.getCurrentStyle(node);
+
+ if (css != null && ui.toolbar != null) {
+ ui.toolbar.setFontName(Graph.stripQuotes(css.fontFamily));
+ ui.toolbar.setFontSize(parseInt(css.fontSize));
+ }
+ }
+
+ updating = false;
+ }, 0);
+ }
+ };
+
+ mxEvent.addListener(graph.cellEditor.textarea, 'input', updateCssHandler)
+ mxEvent.addListener(graph.cellEditor.textarea, 'touchend', updateCssHandler);
+ mxEvent.addListener(graph.cellEditor.textarea, 'mouseup', updateCssHandler);
+ mxEvent.addListener(graph.cellEditor.textarea, 'keyup', updateCssHandler);
+ updateCssHandler();
+ }
+ };
+
+ // Updates toolbar and handles possible errors
+ var cellEditorStopEditing = graph.cellEditor.stopEditing;
+ graph.cellEditor.stopEditing = function (cell, trigger) {
+ try {
+ cellEditorStopEditing.apply(this, arguments);
+ updateToolbar();
+ }
+ catch (e) {
+ ui.handleError(e);
+ }
+ };
+
+ // Enables scrollbars and sets cursor style for the container
+ graph.container.setAttribute('tabindex', '0');
+ graph.container.style.cursor = 'default';
+
+ // Workaround for page scroll if embedded via iframe
+ if (window.self === window.top && graph.container.parentNode != null) {
+ try {
+ graph.container.focus();
+ }
+ catch (e) {
+ // ignores error in old versions of IE
+ }
+ }
+
+ // Keeps graph container focused on mouse down
+ var graphFireMouseEvent = graph.fireMouseEvent;
+ graph.fireMouseEvent = function (evtName, me, sender) {
+ try {
+ if (evtName == mxEvent.MOUSE_DOWN) {
+ this.container.focus();
+ }
+
+ graphFireMouseEvent.apply(this, arguments);
+ }
+ catch (e) {
+ ui.handleError(e);
+ }
+ };
+
+ // Adds error handling for foldCells
+ var graphFoldCells = graph.foldCells;
+ graph.foldCells = function (collapse, recurse, cells, checkFoldable, evt) {
+ try {
+ graphFoldCells.apply(this, arguments);
+ }
+ catch (e) {
+ ui.handleError(e);
+ }
+ };
+
+ // Configures automatic expand on mouseover
+ graph.popupMenuHandler.autoExpand = true;
+
+ // Installs context menu
+ if (this.menus != null) {
+ graph.popupMenuHandler.factoryMethod = mxUtils.bind(this, function (menu, cell, evt) {
+ this.menus.createPopupMenu(menu, cell, evt);
+ });
+ }
+
+ // Hides context menu
+ mxEvent.addGestureListeners(document, mxUtils.bind(this, function (evt) {
+ graph.popupMenuHandler.hideMenu();
+ }));
+
+ // Create handler for key events
+ this.keyHandler = this.createKeyHandler(editor);
+
+ // Getter for key handler
+ this.getKeyHandler = function () {
+ return keyHandler;
+ };
+
+ graph.connectionHandler.addListener(mxEvent.CONNECT, function (sender, evt) {
+ var cells = [evt.getProperty('cell')];
+
+ if (evt.getProperty('terminalInserted')) {
+ cells.push(evt.getProperty('terminal'));
+
+ window.setTimeout(function () {
+ if (ui.hoverIcons != null) {
+ ui.hoverIcons.update(graph.view.getState(cells[cells.length - 1]));
+ }
+ }, 0);
+ }
+
+ insertHandler(cells);
+ });
+
+ this.addListener('styleChanged', mxUtils.bind(this, function (sender, evt) {
+ var force = evt.getProperty('force');
+
+ // Checks if edges and/or vertices were modified
+ if (this.updateDefaultStyle || force) {
+ var cells = evt.getProperty('cells');
+ var vertex = false;
+ var edge = false;
+
+ if (cells.length > 0) {
+ for (var i = 0; i < cells.length; i++) {
+ vertex = graph.getModel().isVertex(cells[i]) || vertex;
+ edge = graph.getModel().isEdge(cells[i]) || edge;
+
+ if (edge && vertex) {
+ break;
+ }
+ }
+ }
+ else {
+ vertex = true;
+ edge = true;
+ }
+
+ vertex = vertex && !vertexStyleIgnored;
+ edge = edge && !edgeStyleIgnored;
+
+ var keys = evt.getProperty('keys');
+ var values = evt.getProperty('values');
+
+ for (var i = 0; i < keys.length; i++) {
+ var common = mxUtils.indexOf(valueStyles, keys[i]) >= 0;
+
+ // Ignores transparent stroke colors
+ if (keys[i] != 'strokeColor' || (values[i] != null && values[i] != 'none')) {
+ // Special case: Edge style and shape
+ if (mxUtils.indexOf(connectStyles, keys[i]) >= 0) {
+ if (edge || mxUtils.indexOf(alwaysEdgeStyles, keys[i]) >= 0) {
+ if (values[i] == null) {
+ delete graph.currentEdgeStyle[keys[i]];
+ }
+ else {
+ graph.currentEdgeStyle[keys[i]] = values[i];
+ }
+ }
+ // Uses style for vertex if defined in styles
+ else if (vertex && mxUtils.indexOf(styles, keys[i]) >= 0) {
+ if (values[i] == null) {
+ delete graph.currentVertexStyle[keys[i]];
+ }
+ else {
+ graph.currentVertexStyle[keys[i]] = values[i];
+ }
+ }
+ }
+ else if (mxUtils.indexOf(styles, keys[i]) >= 0) {
+ if (vertex || common) {
+ if (values[i] == null) {
+ delete graph.currentVertexStyle[keys[i]];
+ }
+ else {
+ graph.currentVertexStyle[keys[i]] = values[i];
+ }
+ }
+
+ if (edge || common || mxUtils.indexOf(alwaysEdgeStyles, keys[i]) >= 0) {
+ if (values[i] == null) {
+ delete graph.currentEdgeStyle[keys[i]];
+ }
+ else {
+ graph.currentEdgeStyle[keys[i]] = values[i];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (this.toolbar != null) {
+ this.toolbar.setFontName(graph.currentVertexStyle['fontFamily'] || Menus.prototype.defaultFont);
+ this.toolbar.setFontSize(graph.currentVertexStyle['fontSize'] || Menus.prototype.defaultFontSize);
+
+ if (this.toolbar.edgeStyleMenu != null) {
+ // Updates toolbar icon for edge style
+ var edgeStyleDiv = this.toolbar.edgeStyleMenu.getElementsByTagName('div')[0];
+
+ if (graph.currentEdgeStyle['edgeStyle'] == 'orthogonalEdgeStyle' && graph.currentEdgeStyle['curved'] == '1') {
+ edgeStyleDiv.className = 'geSprite geSprite-curved';
+ }
+ else if (graph.currentEdgeStyle['edgeStyle'] == 'straight' || graph.currentEdgeStyle['edgeStyle'] == 'none' ||
+ graph.currentEdgeStyle['edgeStyle'] == null) {
+ edgeStyleDiv.className = 'geSprite geSprite-straight';
+ }
+ else if (graph.currentEdgeStyle['edgeStyle'] == 'entityRelationEdgeStyle') {
+ edgeStyleDiv.className = 'geSprite geSprite-entity';
+ }
+ else if (graph.currentEdgeStyle['edgeStyle'] == 'elbowEdgeStyle') {
+ edgeStyleDiv.className = 'geSprite geSprite-' + ((graph.currentEdgeStyle['elbow'] == 'vertical') ?
+ 'verticalelbow' : 'horizontalelbow');
+ }
+ else if (graph.currentEdgeStyle['edgeStyle'] == 'isometricEdgeStyle') {
+ edgeStyleDiv.className = 'geSprite geSprite-' + ((graph.currentEdgeStyle['elbow'] == 'vertical') ?
+ 'verticalisometric' : 'horizontalisometric');
+ }
+ else {
+ edgeStyleDiv.className = 'geSprite geSprite-orthogonal';
+ }
+ }
+
+ if (this.toolbar.edgeShapeMenu != null) {
+ // Updates icon for edge shape
+ var edgeShapeDiv = this.toolbar.edgeShapeMenu.getElementsByTagName('div')[0];
+
+ if (graph.currentEdgeStyle['shape'] == 'link') {
+ edgeShapeDiv.className = 'geSprite geSprite-linkedge';
+ }
+ else if (graph.currentEdgeStyle['shape'] == 'flexArrow') {
+ edgeShapeDiv.className = 'geSprite geSprite-arrow';
+ }
+ else if (graph.currentEdgeStyle['shape'] == 'arrow') {
+ edgeShapeDiv.className = 'geSprite geSprite-simplearrow';
+ }
+ else {
+ edgeShapeDiv.className = 'geSprite geSprite-connection';
+ }
+ }
+ }
+ }));
+
+ // Update font size and font family labels
+ if (this.toolbar != null) {
+ var update = mxUtils.bind(this, function () {
+ var ff = graph.currentVertexStyle['fontFamily'] || 'Helvetica';
+ var fs = String(graph.currentVertexStyle['fontSize'] || '12');
+ var state = graph.getView().getState(graph.getSelectionCell());
+
+ if (state != null) {
+ ff = state.style[mxConstants.STYLE_FONTFAMILY] || ff;
+ fs = state.style[mxConstants.STYLE_FONTSIZE] || fs;
+
+ if (ff.length > 10) {
+ ff = ff.substring(0, 8) + '...';
+ }
+ }
+
+ this.toolbar.setFontName(ff);
+ this.toolbar.setFontSize(fs);
+ });
+
+ graph.getSelectionModel().addListener(mxEvent.CHANGE, update);
+ graph.getModel().addListener(mxEvent.CHANGE, update);
+ }
+
+ // Makes sure the current layer is visible when cells are added
+ graph.addListener(mxEvent.CELLS_ADDED, function (sender, evt) {
+ var cells = evt.getProperty('cells');
+ var parent = evt.getProperty('parent');
+
+ if (parent != null && graph.getModel().isLayer(parent) &&
+ !graph.isCellVisible(parent) && cells != null &&
+ cells.length > 0) {
+ graph.getModel().setVisible(parent, true);
+ }
+ });
+
+ // Global handler to hide the current menu
+ this.gestureHandler = mxUtils.bind(this, function (evt) {
+ if (this.currentMenu != null && mxEvent.getSource(evt) != this.currentMenu.div) {
+ this.hideCurrentMenu();
+ }
+ });
+
+ mxEvent.addGestureListeners(document, this.gestureHandler);
+
+ // Updates the editor UI after the window has been resized or the orientation changes
+ // Timeout is workaround for old IE versions which have a delay for DOM client sizes.
+ var resizeThread = null;
+
+ this.resizeHandler = mxUtils.bind(this, function () {
+ if (resizeThread != null) {
+ window.clearTimeout(resizeThread);
+ }
+
+ resizeThread = window.setTimeout(mxUtils.bind(this, function () {
+ resizeThread = null;
+ this.windowResized();
+ }), 100);
+ });
+
+ mxEvent.addListener(window, 'resize', this.resizeHandler);
+
+ this.orientationChangeHandler = mxUtils.bind(this, function () {
+ this.refresh();
+ });
+
+ mxEvent.addListener(window, 'orientationchange', this.orientationChangeHandler);
+
+ // Workaround for bug on iOS see
+ // http://stackoverflow.com/questions/19012135/ios-7-ipad-safari-landscape-innerheight-outerheight-layout-issue
+ if (mxClient.IS_IOS && !window.navigator.standalone && typeof Menus !== 'undefined') {
+ this.scrollHandler = mxUtils.bind(this, function () {
+ window.scrollTo(0, 0);
+ });
+
+ mxEvent.addListener(window, 'scroll', this.scrollHandler);
+ }
+
+ /**
+ * Sets the initial scrollbar locations after a file was loaded.
+ */
+ this.editor.addListener('resetGraphView', mxUtils.bind(this, function () {
+ this.resetScrollbars();
+ }));
+
+ /**
+ * Repaints the grid.
+ */
+ this.addListener('gridEnabledChanged', mxUtils.bind(this, function () {
+ graph.view.validateBackground();
+ }));
+
+ this.addListener('backgroundColorChanged', mxUtils.bind(this, function () {
+ graph.view.validateBackground();
+ }));
+
+ /**
+ * Repaints the grid.
+ */
+ graph.addListener('gridSizeChanged', mxUtils.bind(this, function () {
+ if (graph.isGridEnabled()) {
+ graph.view.validateBackground();
+ }
+ }));
+
+ // Resets UI, updates action and menu states
+ this.editor.resetGraph();
+ }
+
+ this.init();
+
+ if (!graph.standalone) {
+ this.open();
+ }
+};
+
+/**
+ * Global config that specifies if the compact UI elements should be used.
+ */
+EditorUi.compactUi = true;
+
+/**
+ * Static method for pasing PNG files.
+ */
+EditorUi.parsePng = function (f, fn, error) {
+ var pos = 0;
+
+ function fread(d, count) {
+ var start = pos;
+ pos += count;
+
+ return d.substring(start, pos);
+ };
+
+ // Reads unsigned long 32 bit big endian
+ function _freadint(d) {
+ var bytes = fread(d, 4);
+
+ return bytes.charCodeAt(3) + (bytes.charCodeAt(2) << 8) +
+ (bytes.charCodeAt(1) << 16) + (bytes.charCodeAt(0) << 24);
+ };
+
+ // Checks signature
+ if (fread(f, 8) != String.fromCharCode(137) + 'PNG' + String.fromCharCode(13, 10, 26, 10)) {
+ if (error != null) {
+ error();
+ }
+
+ return;
+ }
+
+ // Reads header chunk
+ fread(f, 4);
+
+ if (fread(f, 4) != 'IHDR') {
+ if (error != null) {
+ error();
+ }
+
+ return;
+ }
+
+ fread(f, 17);
+
+ do {
+ var n = _freadint(f);
+ var type = fread(f, 4);
+
+ if (fn != null) {
+ if (fn(pos - 8, type, n)) {
+ break;
+ }
+ }
+
+ value = fread(f, n);
+ fread(f, 4);
+
+ if (type == 'IEND') {
+ break;
+ }
+ }
+ while (n);
+};
+
+// Extends mxEventSource
+mxUtils.extend(EditorUi, mxEventSource);
+
+/**
+ * Specifies the size of the split bar.
+ */
+EditorUi.prototype.splitSize = (mxClient.IS_TOUCH || mxClient.IS_POINTER) ? 12 : 8;
+
+/**
+ * Specifies the height of the menubar. Default is 30.
+ */
+EditorUi.prototype.menubarHeight = 30;
+
+/**
+ * Specifies the width of the format panel should be enabled. Default is true.
+ */
+EditorUi.prototype.formatEnabled = true;
+
+/**
+ * Specifies the width of the format panel. Default is 240.
+ */
+EditorUi.prototype.formatWidth = 240;
+
+/**
+ * Specifies the height of the toolbar. Default is 38.
+ */
+EditorUi.prototype.toolbarHeight = 38;
+
+/**
+ * Specifies the height of the footer. Default is 28.
+ */
+EditorUi.prototype.footerHeight = 28;
+
+/**
+ * Specifies the position of the horizontal split bar. Default is 240 or 118 for
+ * screen widths <= 640px.
+ */
+EditorUi.prototype.hsplitPosition = (screen.width <= Editor.smallScreenWidth) ? 0 :
+ ((urlParams['sidebar-entries'] != 'large') ? 212 : 240);
+
+/**
+ * Specifies if animations are allowed in . Default is true.
+ */
+EditorUi.prototype.allowAnimation = true;
+
+/**
+ * Default is 2.
+ */
+EditorUi.prototype.lightboxMaxFitScale = 2;
+
+/**
+ * Default is 4.
+ */
+EditorUi.prototype.lightboxVerticalDivider = 4;
+
+/**
+ * Specifies if single click on horizontal split should collapse sidebar. Default is false.
+ */
+EditorUi.prototype.hsplitClickEnabled = false;
+
+/**
+ * Whether the default styles should be updated when styles are changed. Default is true.
+ */
+EditorUi.prototype.updateDefaultStyle = false;
+
+/**
+ * Whether the default styles should be updated when styles are changed. Default is true.
+ */
+EditorUi.prototype.spaceDown = false;
+
+/**
+ * Whether the default styles should be updated when styles are changed. Default is true.
+ */
+EditorUi.prototype.shiftDown = false;
+
+/**
+ * Installs the listeners to update the action states.
+ */
+EditorUi.prototype.init = function () {
+ var graph = this.editor.graph;
+
+ if (!graph.standalone) {
+ if (urlParams['shape-picker'] != '0') {
+ this.installShapePicker();
+ }
+
+ // Hides tooltips and connection points when scrolling
+ mxEvent.addListener(graph.container, 'scroll', mxUtils.bind(this, function () {
+ graph.tooltipHandler.hide();
+
+ if (graph.connectionHandler != null && graph.connectionHandler.constraintHandler != null) {
+ graph.connectionHandler.constraintHandler.reset();
+ }
+ }));
+
+ // Hides tooltip on escape
+ graph.addListener(mxEvent.ESCAPE, mxUtils.bind(this, function () {
+ graph.tooltipHandler.hide();
+ var rb = graph.getRubberband();
+
+ if (rb != null) {
+ rb.cancel();
+ }
+ }));
+
+ mxEvent.addListener(graph.container, 'keydown', mxUtils.bind(this, function (evt) {
+ this.onKeyDown(evt);
+ }));
+
+ mxEvent.addListener(graph.container, 'keypress', mxUtils.bind(this, function (evt) {
+ this.onKeyPress(evt);
+ }));
+
+ // Updates action states
+ this.addUndoListener();
+ this.addBeforeUnloadListener();
+
+ graph.getSelectionModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function () {
+ this.updateActionStates();
+ }));
+
+ graph.getModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function () {
+ this.updateActionStates();
+ }));
+
+ // Changes action states after change of default parent
+ var graphSetDefaultParent = graph.setDefaultParent;
+ var ui = this;
+
+ this.editor.graph.setDefaultParent = function () {
+ graphSetDefaultParent.apply(this, arguments);
+ ui.updateActionStates();
+ };
+
+ // Hack to make showLinkDialog and editLink available in vertex handler
+ graph.showLinkDialog = mxUtils.bind(ui, ui.showLinkDialog);
+ graph.editLink = ui.actions.get('editLink').funct;
+
+ this.updateActionStates();
+ this.initClipboard();
+ this.initCanvas();
+
+ if (this.format != null) {
+ this.format.init();
+ }
+ }
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.clearSelectionState = function () {
+ this.selectionState = null;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.getSelectionState = function () {
+ if (this.selectionState == null) {
+ this.selectionState = this.createSelectionState();
+ }
+
+ return this.selectionState;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.createSelectionState = function () {
+ var graph = this.editor.graph;
+ var cells = graph.getSelectionCells();
+ var result = this.initSelectionState();
+ var initial = true;
+
+ for (var i = 0; i < cells.length; i++) {
+ var style = graph.getCurrentCellStyle(cells[i]);
+
+ if (mxUtils.getValue(style, mxConstants.STYLE_EDITABLE, '1') != '0') {
+ this.updateSelectionStateForCell(result, cells[i], cells, initial);
+ initial = false;
+ }
+ }
+
+ this.updateSelectionStateForTableCells(result);
+
+ return result;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.initSelectionState = function () {
+ return {
+ vertices: [], edges: [], cells: [], x: null, y: null, width: null, height: null,
+ style: {}, containsImage: false, containsLabel: false, fill: true, glass: true,
+ rounded: true, autoSize: false, image: false, shadow: true, lineJumps: true, resizable: true,
+ table: false, cell: false, row: false, movable: true, rotatable: true, stroke: true,
+ swimlane: false, unlocked: this.editor.graph.isEnabled(), connections: false
+ };
+};
+
+/**
+ * Adds information about current selected table cells range.
+ */
+EditorUi.prototype.updateSelectionStateForTableCells = function (result) {
+ if (result.cells.length > 1 && result.cell) {
+ var cells = mxUtils.sortCells(result.cells);
+ var model = this.editor.graph.model;
+ var parent = model.getParent(cells[0]);
+ var table = model.getParent(parent);
+
+ if (parent != null && table != null) {
+ var col = parent.getIndex(cells[0]);
+ var row = table.getIndex(parent);
+ var lastspan = null;
+ var colspan = 1;
+ var rowspan = 1;
+ var index = 0;
+
+ var nextRowCell = (row < table.getChildCount() - 1) ?
+ model.getChildAt(model.getChildAt(
+ table, row + 1), col) : null;
+
+ while (index < cells.length - 1) {
+ var next = cells[++index];
+
+ if (nextRowCell != null && nextRowCell == next &&
+ (lastspan == null || colspan == lastspan)) {
+ lastspan = colspan;
+ colspan = 0;
+ rowspan++;
+ parent = model.getParent(nextRowCell);
+ nextRowCell = (row + rowspan < table.getChildCount()) ?
+ model.getChildAt(model.getChildAt(
+ table, row + rowspan), col) : null;
+ }
+
+ var state = this.editor.graph.view.getState(next);
+
+ if (next == model.getChildAt(parent, col + colspan) && state != null &&
+ mxUtils.getValue(state.style, 'colspan', 1) == 1 &&
+ mxUtils.getValue(state.style, 'rowspan', 1) == 1) {
+ colspan++;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (index == rowspan * colspan - 1) {
+ result.mergeCell = cells[0];
+ result.colspan = colspan;
+ result.rowspan = rowspan;
+ }
+ }
+ }
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.windowResized = function () {
+ window.setTimeout(mxUtils.bind(this, function () {
+ if (this.editor.graph != null) {
+ this.refresh();
+ }
+ }), 0);
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.createTimeout = function (timeout, fn, error) {
+ var acceptResponse = true;
+ var result = null;
+
+ var handleError = mxUtils.bind(this, function (e) {
+ if (result.clear()) {
+ acceptResponse = false;
+ e = (e != null) ? e : {
+ code: App.ERROR_TIMEOUT,
+ message: mxResources.get('timeout'),
+ retry: mxUtils.bind(this, function () {
+ this.createTimeout(timeout, fn, error);
+ })
+ };
+
+ if (error != null) {
+ error(e);
+ }
+ else {
+ this.handleError(e);
+ }
+ }
+ });
+
+ var timeoutThread = window.setTimeout(handleError,
+ (timeout != null) ? timeout : this.timeout);
+
+ var result = {
+ clear: function () {
+ window.clearTimeout(timeoutThread);
+
+ return acceptResponse;
+ },
+ isAlive: function () {
+ return acceptResponse;
+ }
+ };
+
+ if (fn != null) {
+ this.tryAndHandle(mxUtils.bind(this, function () {
+ fn(result);
+ }), handleError);
+ }
+
+ return result;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.tryAndHandle = function (fn, error) {
+ try {
+ fn();
+ }
+ catch (e) {
+ if (error != null) {
+ error(e);
+ }
+ else {
+ this.handleError(e);
+ }
+ }
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.updateSelectionStateForCell = function (result, cell, cells, initial) {
+ var graph = this.editor.graph;
+ result.cells.push(cell);
+
+ if (graph.getModel().isVertex(cell)) {
+ result.connections = graph.model.getEdgeCount(cell) > 0;
+ result.unlocked = result.unlocked && !graph.isCellLocked(cell);
+ result.resizable = result.resizable && graph.isCellResizable(cell);
+ result.rotatable = result.rotatable && graph.isCellRotatable(cell);
+ result.movable = result.movable && graph.isCellMovable(cell) &&
+ !graph.isTableRow(cell) && !graph.isTableCell(cell);
+ result.swimlane = result.swimlane || graph.isSwimlane(cell);
+ result.table = result.table || graph.isTable(cell);
+ result.cell = result.cell || graph.isTableCell(cell);
+ result.row = result.row || graph.isTableRow(cell);
+ result.vertices.push(cell);
+ var geo = graph.getCellGeometry(cell);
+
+ if (geo != null) {
+ if (geo.width > 0) {
+ if (result.width == null) {
+ result.width = geo.width;
+ }
+ else if (result.width != geo.width) {
+ result.width = '';
+ }
+ }
+ else {
+ result.containsLabel = true;
+ }
+
+ if (geo.height > 0) {
+ if (result.height == null) {
+ result.height = geo.height;
+ }
+ else if (result.height != geo.height) {
+ result.height = '';
+ }
+ }
+ else {
+ result.containsLabel = true;
+ }
+
+ if (!geo.relative || geo.offset != null) {
+ var x = (geo.relative) ? geo.offset.x : geo.x;
+ var y = (geo.relative) ? geo.offset.y : geo.y;
+
+ if (result.x == null) {
+ result.x = x;
+ }
+ else if (result.x != x) {
+ result.x = '';
+ }
+
+ if (result.y == null) {
+ result.y = y;
+ }
+ else if (result.y != y) {
+ result.y = '';
+ }
+ }
+ }
+ }
+ else if (graph.getModel().isEdge(cell)) {
+ result.edges.push(cell);
+ result.connections = true;
+ result.resizable = false;
+ result.rotatable = false;
+ result.movable = false;
+ }
+
+ var state = graph.view.getState(cell);
+
+ if (state != null) {
+ result.autoSize = result.autoSize || graph.isAutoSizeState(state);
+ result.glass = result.glass && graph.isGlassState(state);
+ result.rounded = result.rounded && graph.isRoundedState(state);
+ result.lineJumps = result.lineJumps && graph.isLineJumpState(state);
+ result.image = result.image || graph.isImageState(state);
+ result.shadow = result.shadow && graph.isShadowState(state);
+ result.fill = result.fill && graph.isFillState(state);
+ result.gradient = result.fill && graph.isGradientState(state);
+ result.stroke = result.stroke && graph.isStrokeState(state);
+
+ var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null);
+ result.containsImage = result.containsImage || shape == 'image';
+ graph.mergeStyle(state.style, result.style, initial);
+ }
+};
+
+/**
+ * Returns true if the given event should start editing. This implementation returns true.
+ */
+EditorUi.prototype.installShapePicker = function () {
+ var graph = this.editor.graph;
+ var ui = this;
+
+ // Uses this event to process mouseDown to check the selection state before it is changed
+ graph.addListener(mxEvent.FIRE_MOUSE_EVENT, mxUtils.bind(this, function (sender, evt) {
+ if (evt.getProperty('eventName') == 'mouseDown') {
+ ui.hideShapePicker();
+ }
+ }));
+
+ var hidePicker = mxUtils.bind(this, function () {
+ ui.hideShapePicker(true);
+ });
+
+ graph.addListener('wheel', hidePicker);
+ graph.addListener(mxEvent.ESCAPE, hidePicker);
+ graph.view.addListener(mxEvent.SCALE, hidePicker);
+ graph.view.addListener(mxEvent.SCALE_AND_TRANSLATE, hidePicker);
+ graph.getSelectionModel().addListener(mxEvent.CHANGE, hidePicker);
+
+ // Counts as popup menu
+ var popupMenuHandlerIsMenuShowing = graph.popupMenuHandler.isMenuShowing;
+
+ graph.popupMenuHandler.isMenuShowing = function () {
+ return popupMenuHandlerIsMenuShowing.apply(this, arguments) ||
+ ui.shapePicker != null || ui.currentMenu != null;
+ };
+
+ // Adds dbl click dialog for inserting shapes
+ var graphDblClick = graph.dblClick;
+
+ graph.dblClick = function (evt, cell) {
+ if (this.isEnabled()) {
+ if (cell == null && ui.sidebar != null && !mxEvent.isShiftDown(evt) &&
+ !graph.isCellLocked(graph.getDefaultParent())) {
+ var pt = mxUtils.convertPoint(this.container, mxEvent.getClientX(evt), mxEvent.getClientY(evt));
+ mxEvent.consume(evt);
+
+ // Asynchronous to avoid direct insert after double tap
+ window.setTimeout(mxUtils.bind(this, function () {
+ ui.showShapePicker(pt.x, pt.y);
+ }), 30);
+ }
+ else {
+ graphDblClick.apply(this, arguments);
+ }
+ }
+ };
+
+ if (this.hoverIcons != null) {
+ this.hoverIcons.addListener('reset', hidePicker);
+ var hoverIconsDrag = this.hoverIcons.drag;
+
+ this.hoverIcons.drag = function () {
+ ui.hideShapePicker();
+ hoverIconsDrag.apply(this, arguments);
+ };
+
+ var hoverIconsExecute = this.hoverIcons.execute;
+
+ this.hoverIcons.execute = function (state, dir, me) {
+ var evt = me.getEvent();
+
+ if (!this.graph.isCloneEvent(evt) && !mxEvent.isShiftDown(evt)) {
+ this.graph.connectVertex(state.cell, dir, this.graph.defaultEdgeLength, evt, null, null, mxUtils.bind(this, function (x, y, execute) {
+ var temp = graph.getCompositeParent(state.cell);
+ var geo = graph.getCellGeometry(temp);
+ me.consume();
+
+ while (temp != null && graph.model.isVertex(temp) && geo != null && geo.relative) {
+ cell = temp;
+ temp = graph.model.getParent(cell)
+ geo = graph.getCellGeometry(temp);
+ }
+
+ // Asynchronous to avoid direct insert after double tap
+ window.setTimeout(mxUtils.bind(this, function () {
+ ui.showShapePicker(me.getGraphX(), me.getGraphY(), temp, mxUtils.bind(this, function (cell) {
+ execute(cell);
+
+ if (ui.hoverIcons != null) {
+ ui.hoverIcons.update(graph.view.getState(cell));
+ }
+ }), dir);
+ }), 30);
+ }), mxUtils.bind(this, function (result) {
+ this.graph.selectCellsForConnectVertex(result, evt, this);
+ }));
+ }
+ else {
+ hoverIconsExecute.apply(this, arguments);
+ }
+ };
+
+ var thread = null;
+
+ this.hoverIcons.addListener('focus', mxUtils.bind(this, function (sender, evt) {
+ if (thread != null) {
+ window.clearTimeout(thread);
+ }
+
+ thread = window.setTimeout(mxUtils.bind(this, function () {
+ var arrow = evt.getProperty('arrow');
+ var dir = evt.getProperty('direction');
+ var mouseEvent = evt.getProperty('event');
+
+ var rect = arrow.getBoundingClientRect();
+ var offset = mxUtils.getOffset(graph.container);
+ var x = graph.container.scrollLeft + rect.x - offset.x;
+ var y = graph.container.scrollTop + rect.y - offset.y;
+
+ var temp = graph.getCompositeParent((this.hoverIcons.currentState != null) ?
+ this.hoverIcons.currentState.cell : null);
+ var div = ui.showShapePicker(x, y, temp, mxUtils.bind(this, function (cell) {
+ if (cell != null) {
+ graph.connectVertex(temp, dir, graph.defaultEdgeLength, mouseEvent, true, false, function (x, y, execute) {
+ execute(cell);
+
+ if (ui.hoverIcons != null) {
+ ui.hoverIcons.update(graph.view.getState(cell));
+ }
+ }, function (cells) {
+ graph.selectCellsForConnectVertex(cells);
+ }, mouseEvent, this.hoverIcons);
+ }
+ }), dir, true);
+
+ this.centerShapePicker(div, rect, x, y, dir);
+ mxUtils.setOpacity(div, 30);
+
+ mxEvent.addListener(div, 'mouseenter', function () {
+ mxUtils.setOpacity(div, 100);
+ });
+
+ mxEvent.addListener(div, 'mouseleave', function () {
+ ui.hideShapePicker();
+ });
+ }), Editor.shapePickerHoverDelay);
+ }));
+
+ this.hoverIcons.addListener('blur', mxUtils.bind(this, function (sender, evt) {
+ if (thread != null) {
+ window.clearTimeout(thread);
+ }
+ }));
+ }
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.centerShapePicker = function (div, rect, x, y, dir) {
+ if (dir == mxConstants.DIRECTION_EAST || dir == mxConstants.DIRECTION_WEST) {
+ div.style.width = '40px';
+ }
+
+ var r2 = div.getBoundingClientRect();
+
+ if (dir == mxConstants.DIRECTION_NORTH) {
+ x -= r2.width / 2 - 10;
+ y -= r2.height + 6;
+ }
+ else if (dir == mxConstants.DIRECTION_SOUTH) {
+ x -= r2.width / 2 - 10;
+ y += rect.height + 6;
+ }
+ else if (dir == mxConstants.DIRECTION_WEST) {
+ x -= r2.width + 6;
+ y -= r2.height / 2 - 10;
+ }
+ else if (dir == mxConstants.DIRECTION_EAST) {
+ x += rect.width + 6;
+ y -= r2.height / 2 - 10;
+ }
+
+ div.style.left = x + 'px';
+ div.style.top = y + 'px';
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.showShapePicker = function (x, y, source, callback, direction, hovering,
+ getInsertLocationFn, showEdges, startEditing) {
+ showEdges = showEdges || source == null;
+
+ var div = this.createShapePicker(x, y, source, callback, direction, mxUtils.bind(this, function () {
+ this.hideShapePicker();
+ }), this.getCellsForShapePicker(source, hovering, showEdges), hovering,
+ getInsertLocationFn, showEdges, startEditing);
+
+ if (div != null) {
+ if (this.hoverIcons != null && !hovering) {
+ this.hoverIcons.reset();
+ }
+
+ var graph = this.editor.graph;
+ graph.popupMenuHandler.hideMenu();
+ graph.tooltipHandler.hideTooltip();
+ this.hideCurrentMenu();
+ this.hideShapePicker();
+
+ this.shapePickerCallback = callback;
+ this.shapePicker = div;
+ }
+
+ return div;
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.createShapePicker = function (x, y, source, callback, direction,
+ afterClick, cells, hovering, getInsertLocationFn, showEdges, startEditing) {
+ startEditing = (startEditing != null) ? startEditing : true;
+ var graph = this.editor.graph;
+ var div = null;
+
+ getInsertLocationFn = (getInsertLocationFn != null) ? getInsertLocationFn : function (cells) {
+ var cell = cells[0];
+ var w = 0;
+ var h = 0;
+ var geo = cell.geometry;
+
+ if (geo != null) {
+ if (graph.model.isEdge(cell)) {
+ var pt = geo.getTerminalPoint(false);
+ geo = new mxRectangle(0, 0, pt.x, pt.y);
+ }
+
+ w = geo.width / 2;
+ h = geo.height / 2;
+ }
+
+ return new mxPoint(graph.snap(Math.round(x / graph.view.scale) - graph.view.translate.x - w),
+ graph.snap(Math.round(y / graph.view.scale) - graph.view.translate.y - h));
+ };
+
+ if (cells != null && cells.length > 0) {
+ var ui = this;
+ var graph = this.editor.graph;
+ div = document.createElement('div');
+ var sourceState = graph.view.getState(source);
+ var style = (source != null && (sourceState == null ||
+ !graph.isTransparentState(sourceState))) ?
+ graph.copyStyle(source) : null;
+
+ // Do not place entry under pointer for touch devices
+ var w = (cells.length < 6) ? cells.length * 35 : 140;
+ div.className = 'geToolbarContainer geSidebarContainer geShapePicker';
+ div.setAttribute('title', mxResources.get('sidebarTooltip'));
+ div.style.left = x + 'px';
+ div.style.top = y + 'px';
+ div.style.width = w + 'px';
+
+ // Disables built-in pan and zoom on touch devices
+ if (mxClient.IS_POINTER) {
+ div.style.touchAction = 'none';
+ }
+
+ if (!hovering) {
+ mxUtils.setPrefixedStyle(div.style, 'transform', 'translate(-22px,-22px)');
+ }
+
+ if (graph.background != null && graph.background != mxConstants.NONE) {
+ div.style.backgroundColor = graph.background;
+ }
+
+ graph.container.appendChild(div);
+
+ var addCell = mxUtils.bind(this, function (cell) {
+ // Wrapper needed to catch events
+ var node = document.createElement('a');
+ node.className = 'geItem';
+ node.style.cssText = 'position:relative;display:inline-block;position:relative;' +
+ 'width:30px;height:30px;cursor:pointer;overflow:hidden;padding:1px';
+ div.appendChild(node);
+
+ if (style != null && urlParams['sketch'] != '1') {
+ this.sidebar.graph.pasteStyle(style, [cell]);
+ }
+ else {
+ ui.insertHandler([cell], cell.value != '' && urlParams['sketch'] != '1', this.sidebar.graph.model);
+ }
+
+ var geo = cell.geometry;
+
+ if (graph.model.isEdge(cell)) {
+ var pt = geo.getTerminalPoint(false);
+ geo = new mxRectangle(0, 0, pt.x, pt.y);
+ }
+
+ if (geo != null) {
+ node.appendChild(this.sidebar.createVertexTemplateFromCells([cell],
+ geo.width, geo.height, '', true, false, null, false,
+ mxUtils.bind(this, function (evt) {
+ if (mxEvent.isShiftDown(evt) && (source != null ||
+ !graph.isSelectionEmpty())) {
+ var temp = graph.getEditableCells((source != null) ?
+ [source] : graph.getSelectionCells());
+ graph.updateShapes(cell, temp);
+ }
+ else {
+ var clone = graph.cloneCell(cell);
+
+ if (callback != null) {
+ callback(clone);
+ }
+ else {
+ var pt = getInsertLocationFn([clone]);
+
+ if (graph.model.isEdge(clone)) {
+ clone.geometry.translate(pt.x, pt.y);
+ }
+ else {
+ clone.geometry.x = pt.x;
+ clone.geometry.y = pt.y;
+ }
+
+ graph.model.beginUpdate();
+ try {
+ graph.addCell(clone);
+
+ if (graph.model.isVertex(clone) &&
+ graph.isAutoSizeCell(clone)) {
+ graph.updateCellSize(clone);
+ }
+ }
+ finally {
+ graph.model.endUpdate();
+ }
+
+ graph.setSelectionCell(clone);
+ graph.scrollCellToVisible(clone);
+
+ if (startEditing) {
+ graph.startEditing(clone);
+ }
+
+ if (ui.hoverIcons != null) {
+ ui.hoverIcons.update(graph.view.getState(clone));
+ }
+ }
+ }
+
+ if (afterClick != null) {
+ afterClick(evt);
+ }
+
+ mxEvent.consume(evt);
+ }), 25, 25, null, null, source));
+ }
+ });
+
+ for (var i = 0; i < (hovering ? Math.min(cells.length, 4) : cells.length); i++) {
+ addCell(cells[i]);
+ }
+
+ var b = graph.container.scrollTop + graph.container.offsetHeight;
+ var dy = div.offsetTop + div.clientHeight - b;
+
+ if (dy > 0) {
+ div.style.top = Math.max(graph.container.scrollTop + 22, y - dy) + 'px';
+ }
+
+ var r = graph.container.scrollLeft + graph.container.offsetWidth;
+ var dx = div.offsetLeft + div.clientWidth - r;
+
+ if (dx > 0) {
+ div.style.left = Math.max(graph.container.scrollLeft + 22, x - dx) + 'px';
+ }
+ }
+
+ return div;
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.getCellsForShapePicker = function (cell, hovering, showEdges) {
+ var graph = this.editor.graph;
+
+ var createVertex = mxUtils.bind(this, function (style, w, h, value) {
+ return graph.createVertex(null, null, value || '', 0, 0, w || 120, h || 60, style, false);
+ });
+
+ var createEdge = mxUtils.bind(this, function (style, y, value) {
+ var cell = new mxCell(value || '', new mxGeometry(0, 0, graph.defaultEdgeLength + 20, 0), style);
+ cell.geometry.setTerminalPoint(new mxPoint(0, 0), true);
+ cell.geometry.setTerminalPoint(new mxPoint(cell.geometry.width, (y != null) ? y : 0), false);
+ cell.geometry.points = (y != null) ? [new mxPoint(cell.geometry.width / 2, y)] : [];
+ cell.geometry.relative = true;
+ cell.edge = true;
+
+ return cell;
+ });
+
+ // Creates a clone of the source cell and moves it to the origin
+ if (cell != null) {
+ try {
+ cell = graph.cloneCell(cell);
+
+ if (graph.model.isVertex(cell) && cell.geometry != null) {
+ cell.geometry.x = 0;
+ cell.geometry.y = 0;
+ }
+ }
+ catch (e) {
+ cell = null;
+ }
+ }
+
+ if (cell == null) {
+ cell = createVertex('text;html=1;align=center;verticalAlign=middle;resizable=0;' +
+ 'points=[];autosize=1;strokeColor=none;fillColor=none;', 40, 20, 'Text');
+
+ if (graph.model.isVertex(cell) && graph.isAutoSizeCell(cell)) {
+ // Uses offscreen graph to bypass undo history
+ var tempGraph = Graph.createOffscreenGraph(graph.getStylesheet());
+ tempGraph.updateCellSize(cell);
+ }
+ }
+
+ var cells = [cell, createVertex('whiteSpace=wrap;html=1;'),
+ createVertex('ellipse;whiteSpace=wrap;html=1;', 80, 80),
+ createVertex('rhombus;whiteSpace=wrap;html=1;', 80, 80),
+ createVertex('rounded=1;whiteSpace=wrap;html=1;'),
+ createVertex('shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;'),
+ createVertex('shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;', 120, 60),
+ createVertex('shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;', 120, 80),
+ createVertex('shape=step;perimeter=stepPerimeter;whiteSpace=wrap;html=1;fixedSize=1;', 120, 80),
+ createVertex('shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;'),
+ createVertex('triangle;whiteSpace=wrap;html=1;', 60, 80),
+ createVertex('shape=document;whiteSpace=wrap;html=1;boundedLbl=1;', 120, 80),
+ createVertex('shape=tape;whiteSpace=wrap;html=1;', 120, 100),
+ createVertex('ellipse;shape=cloud;whiteSpace=wrap;html=1;', 120, 80),
+ createVertex('shape=singleArrow;whiteSpace=wrap;html=1;arrowWidth=0.4;arrowSize=0.4;', 80, 60),
+ createVertex('shape=waypoint;sketch=0;size=6;pointerEvents=1;points=[];fillColor=none;resizable=0;' +
+ 'rotatable=0;perimeter=centerPerimeter;snapToPoint=1;', 20, 20)];
+
+ if (showEdges) {
+ cells = cells.concat([
+ createEdge('edgeStyle=none;orthogonalLoop=1;jettySize=auto;html=1;'),
+ createEdge('edgeStyle=none;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;startArrow=classic;endSize=8;startSize=8;'),
+ createEdge('edgeStyle=none;orthogonalLoop=1;jettySize=auto;html=1;shape=flexArrow;rounded=1;startSize=8;endSize=8;'),
+ createEdge('edgeStyle=segmentEdgeStyle;endArrow=classic;html=1;curved=0;rounded=0;endSize=8;startSize=8;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;',
+ this.editor.graph.defaultEdgeLength / 2)
+ ]);
+ }
+
+ return cells;
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.isShapePickerVisible = function (cancel) {
+ return this.shapePicker != null;
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.hideShapePicker = function (cancel) {
+ if (this.shapePicker != null) {
+ this.shapePicker.parentNode.removeChild(this.shapePicker);
+ this.shapePicker = null;
+
+ if (!cancel && this.shapePickerCallback != null) {
+ this.shapePickerCallback();
+ }
+
+ this.shapePickerCallback = null;
+ }
+};
+
+/**
+ * Whether the default styles should be updated when styles are changed. Default is true.
+ */
+EditorUi.prototype.isSpaceDown = function () {
+ return this.spaceDown;
+};
+
+/**
+ * Whether the default styles should be updated when styles are changed. Default is true.
+ */
+EditorUi.prototype.isShiftDown = function () {
+ return this.shiftDown;
+};
+
+/**
+ * Returns true if the given event should start editing. This implementation returns true.
+ */
+EditorUi.prototype.onKeyDown = function (evt) {
+ var graph = this.editor.graph;
+
+ // Alt+tab for task switcher in Windows, ctrl+tab for tab control in Chrome
+ if (evt.which == 9 && graph.isEnabled() && !mxEvent.isControlDown(evt)) {
+ if (graph.isEditing()) {
+ if (mxEvent.isAltDown(evt)) {
+ graph.stopEditing(false);
+ }
+ else {
+ try {
+ var nesting = graph.cellEditor.isContentEditing() && graph.cellEditor.isTextSelected();
+
+ if (window.getSelection && graph.cellEditor.isContentEditing() &&
+ !nesting && !mxClient.IS_IE && !mxClient.IS_IE11) {
+ var selection = window.getSelection();
+ var container = (selection.rangeCount > 0) ? selection.getRangeAt(0).commonAncestorContainer : null;
+ nesting = container != null && (container.nodeName == 'LI' || (container.parentNode != null &&
+ container.parentNode.nodeName == 'LI'));
+ }
+
+ if (nesting) {
+ // (Shift+)tab indents/outdents with text selection or inside list elements
+ document.execCommand(mxEvent.isShiftDown(evt) ? 'outdent' : 'indent', false, null);
+ }
+ // Shift+tab applies value with cursor
+ else if (mxEvent.isShiftDown(evt)) {
+ graph.stopEditing(false);
+ }
+ else {
+ // Inserts tab character
+ graph.cellEditor.insertTab(!graph.cellEditor.isContentEditing() ? 4 : null);
+ }
+ }
+ catch (e) {
+ // ignore
+ }
+ }
+ }
+ else if (mxEvent.isAltDown(evt)) {
+ graph.selectParentCell();
+ }
+ else {
+ graph.selectCell(!mxEvent.isShiftDown(evt));
+ }
+
+ mxEvent.consume(evt);
+ }
+};
+
+/**
+ * Returns true if the given event should start editing. This implementation returns true.
+ */
+EditorUi.prototype.onKeyPress = function (evt) {
+ var graph = this.editor.graph;
+
+ // KNOWN: Focus does not work if label is empty in quirks mode
+ if (this.isImmediateEditingEvent(evt) && !graph.isEditing() && !graph.isSelectionEmpty() && evt.which !== 0 &&
+ evt.which !== 27 && !mxEvent.isAltDown(evt) && !mxEvent.isControlDown(evt) && !mxEvent.isMetaDown(evt)) {
+ graph.escape();
+ graph.startEditing();
+
+ // Workaround for FF where char is lost if cursor is placed before char
+ if (mxClient.IS_FF) {
+ var ce = graph.cellEditor;
+
+ if (ce.textarea != null) {
+ ce.textarea.innerHTML = String.fromCharCode(evt.which);
+
+ // Moves cursor to end of textarea
+ var range = document.createRange();
+ range.selectNodeContents(ce.textarea);
+ range.collapse(false);
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(range);
+ }
+ }
+ }
+};
+
+/**
+ * Returns true if the given event should start editing. This implementation returns true.
+ */
+EditorUi.prototype.isImmediateEditingEvent = function (evt) {
+ return true;
+};
+
+/**
+ * Updates the CSS for the given element to match the selection.
+ */
+EditorUi.prototype.updateCssForMarker = function (markerDiv, prefix, shape, marker, fill) {
+ markerDiv.style.display = 'inline-flex';
+ markerDiv.style.alignItems = 'center';
+ markerDiv.style.justifyContent = 'center';
+ markerDiv.innerText = '';
+
+ if (shape == 'flexArrow') {
+ markerDiv.className = (marker != null && marker != mxConstants.NONE) ?
+ 'geSprite geSprite-' + prefix + 'blocktrans' : 'geSprite geSprite-noarrow';
+ }
+ else {
+ var src = this.getImageForMarker(marker, fill);
+
+ if (src != null) {
+ var img = document.createElement('img');
+ img.className = 'geAdaptiveAsset';
+ img.setAttribute('src', src);
+ markerDiv.className = '';
+
+ if (prefix == 'end') {
+ mxUtils.setPrefixedStyle(img.style, 'transform', 'scaleX(-1)');
+ }
+
+ markerDiv.appendChild(img);
+ }
+ else {
+ markerDiv.className = 'geSprite geSprite-noarrow';
+ markerDiv.innerHTML = mxUtils.htmlEntities(mxResources.get('none'));
+ markerDiv.style.backgroundImage = 'none';
+ markerDiv.style.fontSize = '11px';
+ markerDiv.style.filter = 'none';
+ }
+ }
+};
+
+/**
+ * Returns true if the given event should start editing. This implementation returns true.
+ */
+EditorUi.prototype.getImageForMarker = function (marker, fill) {
+ var result = null;
+
+ if (marker == mxConstants.ARROW_CLASSIC) {
+ result = (fill != '1') ? Format.classicMarkerImage.src :
+ Format.classicFilledMarkerImage.src
+ }
+ else if (marker == mxConstants.ARROW_CLASSIC_THIN) {
+ result = (fill != '1') ? Format.classicThinMarkerImage.src :
+ Format.openThinFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_OPEN) {
+ result = Format.openFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_OPEN_THIN) {
+ result = Format.openThinFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_BLOCK) {
+ result = (fill != '1') ? Format.blockMarkerImage.src :
+ Format.blockFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_BLOCK_THIN) {
+ result = (fill != '1') ? Format.blockThinMarkerImage.src :
+ Format.blockThinFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_OVAL) {
+ result = (fill != '1') ? Format.ovalMarkerImage.src :
+ Format.ovalFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_DIAMOND) {
+ result = (fill != '1') ? Format.diamondMarkerImage.src :
+ Format.diamondFilledMarkerImage.src;
+ }
+ else if (marker == mxConstants.ARROW_DIAMOND_THIN) {
+ result = (fill != '1') ? Format.diamondThinMarkerImage.src :
+ Format.diamondThinFilledMarkerImage.src;
+ }
+ else if (marker == 'doubleBlock') {
+ result = (fill != '1') ? Format.doubleBlockMarkerImage.src :
+ Format.doubleBlockFilledMarkerImage.src;
+ }
+ else if (marker == 'box') {
+ result = Format.boxMarkerImage.src;
+ }
+ else if (marker == 'halfCircle') {
+ result = Format.halfCircleMarkerImage.src;
+ }
+ else if (marker == 'openAsync') {
+ result = Format.openAsyncFilledMarkerImage.src;
+ }
+ else if (marker == 'async') {
+ result = (fill != '1') ? Format.asyncMarkerImage.src :
+ Format.asyncFilledMarkerImage.src;
+ }
+ else if (marker == 'dash') {
+ result = Format.dashMarkerImage.src;
+ }
+ else if (marker == 'baseDash') {
+ result = Format.baseDashMarkerImage.src;
+ }
+ else if (marker == 'cross') {
+ result = Format.crossMarkerImage.src;
+ }
+ else if (marker == 'circle') {
+ result = Format.circleMarkerImage.src;
+ }
+ else if (marker == 'circlePlus') {
+ result = Format.circlePlusMarkerImage.src;
+ }
+ else if (marker == 'ERone') {
+ result = Format.EROneMarkerImage.src;
+ }
+ else if (marker == 'ERmandOne') {
+ result = Format.ERmandOneMarkerImage.src;
+ }
+ else if (marker == 'ERmany') {
+ result = Format.ERmanyMarkerImage.src;
+ }
+ else if (marker == 'ERoneToMany') {
+ result = Format.ERoneToManyMarkerImage.src;
+ }
+ else if (marker == 'ERzeroToOne') {
+ result = Format.ERzeroToOneMarkerImage.src;
+ }
+ else if (marker == 'ERzeroToMany') {
+ result = Format.ERzeroToManyMarkerImage.src;
+ }
+
+ return result;
+};
+
+/**
+ * Overridden in Menus.js
+ */
+EditorUi.prototype.createMenus = function () {
+ return null;
+};
+
+/**
+ * Hook for allowing selection and context menu for certain events.
+ */
+EditorUi.prototype.updatePasteActionStates = function () {
+ var graph = this.editor.graph;
+ var paste = this.actions.get('paste');
+ var pasteHere = this.actions.get('pasteHere');
+
+ paste.setEnabled(this.editor.graph.cellEditor.isContentEditing() ||
+ (((!mxClient.IS_FF && navigator.clipboard != null) || !mxClipboard.isEmpty()) &&
+ graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent())));
+ pasteHere.setEnabled(paste.isEnabled());
+};
+
+/**
+ * Hook for allowing selection and context menu for certain events.
+ */
+EditorUi.prototype.initClipboard = function () {
+ var ui = this;
+
+ var mxClipboardCut = mxClipboard.cut;
+ mxClipboard.cut = function (graph) {
+ if (graph.cellEditor.isContentEditing()) {
+ document.execCommand('cut', false, null);
+ }
+ else {
+ mxClipboardCut.apply(this, arguments);
+ }
+
+ ui.updatePasteActionStates();
+ };
+
+ var mxClipboardCopy = mxClipboard.copy;
+ mxClipboard.copy = function (graph) {
+ var result = null;
+
+ if (graph.cellEditor.isContentEditing()) {
+ document.execCommand('copy', false, null);
+ }
+ else {
+ result = result || graph.getSelectionCells();
+ result = graph.getExportableCells(graph.model.getTopmostCells(result));
+
+ var cloneMap = new Object();
+ var lookup = graph.createCellLookup(result);
+ var clones = graph.cloneCells(result, null, cloneMap);
+
+ // Uses temporary model to force new IDs to be assigned
+ // to avoid having to carry over the mapping from object
+ // ID to cell ID to the paste operation
+ var model = new mxGraphModel();
+ var parent = model.getChildAt(model.getRoot(), 0);
+
+ for (var i = 0; i < clones.length; i++) {
+ model.add(parent, clones[i]);
+
+ // Checks for orphaned relative children and makes absolute
+ var state = graph.view.getState(result[i]);
+
+ if (state != null) {
+ var geo = graph.getCellGeometry(clones[i]);
+
+ if (geo != null && geo.relative && !model.isEdge(result[i]) &&
+ lookup[mxObjectIdentity.get(model.getParent(result[i]))] == null) {
+ geo.offset = null;
+ geo.relative = false;
+ geo.x = state.x / state.view.scale - state.view.translate.x;
+ geo.y = state.y / state.view.scale - state.view.translate.y;
+ }
+ }
+ }
+
+ graph.updateCustomLinks(graph.createCellMapping(cloneMap, lookup), clones);
+
+ mxClipboard.insertCount = 1;
+ mxClipboard.setCells(clones);
+ }
+
+ ui.updatePasteActionStates();
+
+ return result;
+ };
+
+ var mxClipboardPaste = mxClipboard.paste;
+ mxClipboard.paste = function (graph) {
+ var result = null;
+
+ if (graph.cellEditor.isContentEditing()) {
+ document.execCommand('paste', false, null);
+ }
+ else {
+ result = mxClipboardPaste.apply(this, arguments);
+ }
+
+ ui.updatePasteActionStates();
+
+ return result;
+ };
+
+ // Overrides cell editor to update paste action state
+ var cellEditorStartEditing = this.editor.graph.cellEditor.startEditing;
+
+ this.editor.graph.cellEditor.startEditing = function () {
+ cellEditorStartEditing.apply(this, arguments);
+ ui.updatePasteActionStates();
+ };
+
+ var cellEditorStopEditing = this.editor.graph.cellEditor.stopEditing;
+
+ this.editor.graph.cellEditor.stopEditing = function (cell, trigger) {
+ cellEditorStopEditing.apply(this, arguments);
+ ui.updatePasteActionStates();
+ };
+
+ this.updatePasteActionStates();
+};
+
+/**
+ * Delay between zoom steps when not using preview.
+ */
+EditorUi.prototype.lazyZoomDelay = 20;
+
+/**
+ * Delay before update of DOM when using preview.
+ */
+EditorUi.prototype.wheelZoomDelay = 500;
+
+/**
+ * Delay before update of DOM when using preview.
+ */
+EditorUi.prototype.buttonZoomDelay = 600;
+
+/**
+ * Initializes the infinite canvas.
+ */
+EditorUi.prototype.initCanvas = function () {
+ // Initial page layout view, scrollBuffer and timer-based scrolling
+ var graph = this.editor.graph;
+ graph.timerAutoScroll = true;
+
+ /**
+ * Returns the padding for pages in page view with scrollbars.
+ */
+ graph.getPagePadding = function () {
+ return new mxPoint(Math.max(0, Math.round((graph.container.offsetWidth - 34) / graph.view.scale)),
+ Math.max(0, Math.round((graph.container.offsetHeight - 34) / graph.view.scale)));
+ };
+
+ // Fits the number of background pages to the graph
+ graph.view.getBackgroundPageBounds = function () {
+ var layout = this.graph.getPageLayout();
+ var page = this.graph.getPageSize();
+
+ return new mxRectangle(this.scale * (this.translate.x + layout.x * page.width),
+ this.scale * (this.translate.y + layout.y * page.height),
+ this.scale * layout.width * page.width,
+ this.scale * layout.height * page.height);
+ };
+
+ graph.getPreferredPageSize = function (bounds, width, height) {
+ var pages = this.getPageLayout();
+ var size = this.getPageSize();
+
+ return new mxRectangle(0, 0, pages.width * size.width, pages.height * size.height);
+ };
+
+ // Scales pages/graph to fit available size
+ var resize = null;
+ var ui = this;
+
+ if (this.editor.isChromelessView()) {
+ resize = mxUtils.bind(this, function (autoscale, maxScale, cx, cy) {
+ if (graph.container != null && !graph.isViewer()) {
+ cx = (cx != null) ? cx : 0;
+ cy = (cy != null) ? cy : 0;
+
+ var bds = (graph.pageVisible) ?
+ graph.view.getBackgroundPageBounds() :
+ graph.getGraphBounds();
+ var scroll = mxUtils.hasScrollbars(graph.container);
+ var tr = graph.view.translate;
+ var s = graph.view.scale;
+
+ // Normalizes the bounds
+ var b = mxRectangle.fromRectangle(bds);
+ b.x = b.x / s - tr.x;
+ b.y = b.y / s - tr.y;
+ b.width /= s;
+ b.height /= s;
+
+ var st = graph.container.scrollTop;
+ var sl = graph.container.scrollLeft;
+ var sb = (document.documentMode >= 8) ? 20 : 14;
+
+ if (document.documentMode == 8 || document.documentMode == 9) {
+ sb += 3;
+ }
+
+ var cw = graph.container.offsetWidth - sb;
+ var ch = graph.container.offsetHeight - sb;
+
+ var ns = (autoscale) ? Math.max(0.3, Math.min(maxScale || 1, cw / b.width)) : s;
+ var dx = ((cw - ns * b.width) / 2) / ns;
+ var dy = (this.lightboxVerticalDivider == 0) ? 0 : ((ch - ns * b.height) / this.lightboxVerticalDivider) / ns;
+
+ if (scroll) {
+ dx = Math.max(dx, 0);
+ dy = Math.max(dy, 0);
+ }
+
+ if (scroll || bds.width < cw || bds.height < ch) {
+ graph.view.scaleAndTranslate(ns, Math.floor(dx - b.x), Math.floor(dy - b.y));
+ graph.container.scrollTop = st * ns / s;
+ graph.container.scrollLeft = sl * ns / s;
+ }
+ else if (cx != 0 || cy != 0) {
+ var t = graph.view.translate;
+ graph.view.setTranslate(Math.floor(t.x + cx / s), Math.floor(t.y + cy / s));
+ }
+ }
+ });
+
+ // Hack to make function available to subclassers
+ this.chromelessResize = resize;
+
+ // Hook for subclassers for override
+ this.chromelessWindowResize = mxUtils.bind(this, function () {
+ this.chromelessResize(false);
+ });
+
+ // Removable resize listener
+ var autoscaleResize = mxUtils.bind(this, function () {
+ this.chromelessWindowResize(false);
+ });
+
+ mxEvent.addListener(window, 'resize', autoscaleResize);
+
+ this.destroyFunctions.push(function () {
+ mxEvent.removeListener(window, 'resize', autoscaleResize);
+ });
+
+ this.editor.addListener('resetGraphView', mxUtils.bind(this, function () {
+ this.chromelessResize(true);
+ }));
+
+ this.actions.get('zoomIn').funct = mxUtils.bind(this, function (evt) {
+ graph.zoomIn();
+ this.chromelessResize(false);
+ });
+ this.actions.get('zoomOut').funct = mxUtils.bind(this, function (evt) {
+ graph.zoomOut();
+ this.chromelessResize(false);
+ });
+
+ // Creates toolbar for viewer - do not use CSS here
+ // as this may be used in a viewer that has no CSS
+ if (urlParams['toolbar'] != '0') {
+ var toolbarConfig = JSON.parse(decodeURIComponent(urlParams['toolbar-config'] || '{}'));
+
+ this.chromelessToolbar = document.createElement('div');
+ this.chromelessToolbar.style.position = 'fixed';
+ this.chromelessToolbar.style.overflow = 'hidden';
+ this.chromelessToolbar.style.boxSizing = 'border-box';
+ this.chromelessToolbar.style.whiteSpace = 'nowrap';
+ this.chromelessToolbar.style.padding = '10px 10px 8px 10px';
+ this.chromelessToolbar.style.left = (graph.isViewer()) ? '0' : '50%';
+
+ if (!mxClient.IS_IE && !mxClient.IS_IE11) {
+ this.chromelessToolbar.style.backgroundColor = '#000000';
+ }
+ else {
+ this.chromelessToolbar.style.backgroundColor = '#ffffff';
+ this.chromelessToolbar.style.border = '3px solid black';
+ }
+
+ mxUtils.setPrefixedStyle(this.chromelessToolbar.style, 'borderRadius', '16px');
+ mxUtils.setPrefixedStyle(this.chromelessToolbar.style, 'transition', 'opacity 600ms ease-in-out');
+
+ var updateChromelessToolbarPosition = mxUtils.bind(this, function () {
+ var css = mxUtils.getCurrentStyle(graph.container);
+
+ if (graph.isViewer()) {
+ this.chromelessToolbar.style.top = '0';
+ }
+ else {
+ this.chromelessToolbar.style.bottom = ((css != null) ? parseInt(css['margin-bottom'] || 0) : 0) +
+ ((this.tabContainer != null) ? (20 + parseInt(this.tabContainer.style.height)) : 20) + 'px';
+ }
+ });
+
+ this.editor.addListener('resetGraphView', updateChromelessToolbarPosition);
+ updateChromelessToolbarPosition();
+
+ var btnCount = 0;
+
+ var addButton = mxUtils.bind(this, function (fn, imgSrc, tip) {
+ btnCount++;
+
+ var a = document.createElement('span');
+ a.style.paddingLeft = '8px';
+ a.style.paddingRight = '8px';
+ a.style.cursor = 'pointer';
+ mxEvent.addListener(a, 'click', fn);
+
+ if (tip != null) {
+ a.setAttribute('title', tip);
+ }
+
+ var img = document.createElement('img');
+ img.setAttribute('border', '0');
+ img.setAttribute('src', imgSrc);
+ img.style.width = '36px';
+ img.style.filter = 'invert(100%)';
+
+ a.appendChild(img);
+ this.chromelessToolbar.appendChild(a);
+
+ return a;
+ });
+
+ if (toolbarConfig.backBtn != null) {
+ var backUrl = Graph.sanitizeLink(toolbarConfig.backBtn.url);
+
+ if (backUrl != null) {
+ addButton(mxUtils.bind(this, function (evt) {
+ window.location.href = backUrl;
+ mxEvent.consume(evt);
+ }), Editor.backImage, mxResources.get('back', null, 'Back'));
+ }
+ }
+
+ if (this.isPagesEnabled()) {
+ var prevButton = addButton(mxUtils.bind(this, function (evt) {
+ this.actions.get('previousPage').funct();
+ mxEvent.consume(evt);
+ }), Editor.previousImage, mxResources.get('previousPage'));
+
+ var pageInfo = document.createElement('div');
+ pageInfo.style.fontFamily = Editor.defaultHtmlFont;
+ pageInfo.style.display = 'inline-block';
+ pageInfo.style.verticalAlign = 'top';
+ pageInfo.style.fontWeight = 'bold';
+ pageInfo.style.marginTop = '8px';
+ pageInfo.style.fontSize = '14px';
+
+ if (!mxClient.IS_IE && !mxClient.IS_IE11) {
+ pageInfo.style.color = '#ffffff';
+ }
+ else {
+ pageInfo.style.color = '#000000';
+ }
+
+ this.chromelessToolbar.appendChild(pageInfo);
+
+ var nextButton = addButton(mxUtils.bind(this, function (evt) {
+ this.actions.get('nextPage').funct();
+ mxEvent.consume(evt);
+ }), Editor.nextImage, mxResources.get('nextPage'));
+
+ var updatePageInfo = mxUtils.bind(this, function () {
+ if (this.pages != null && this.pages.length > 1 && this.currentPage != null) {
+ pageInfo.innerText = '';
+ mxUtils.write(pageInfo, (mxUtils.indexOf(this.pages, this.currentPage) + 1) + ' / ' + this.pages.length);
+ }
+ });
+
+ prevButton.style.paddingLeft = '0px';
+ prevButton.style.paddingRight = '4px';
+ nextButton.style.paddingLeft = '4px';
+ nextButton.style.paddingRight = '0px';
+
+ var updatePageButtons = mxUtils.bind(this, function () {
+ if (this.pages != null && this.pages.length > 1 && this.currentPage != null) {
+ nextButton.style.display = '';
+ prevButton.style.display = '';
+ pageInfo.style.display = 'inline-block';
+ }
+ else {
+ nextButton.style.display = 'none';
+ prevButton.style.display = 'none';
+ pageInfo.style.display = 'none';
+ }
+
+ updatePageInfo();
+ });
+
+ this.editor.addListener('resetGraphView', updatePageButtons);
+ this.editor.addListener('pageSelected', updatePageInfo);
+ }
+
+ addButton(mxUtils.bind(this, function (evt) {
+ this.actions.get('zoomOut').funct();
+ mxEvent.consume(evt);
+ }), Editor.zoomOutImage, mxResources.get('zoomOut') + ' (Alt+Mousewheel)');
+
+ addButton(mxUtils.bind(this, function (evt) {
+ this.actions.get('zoomIn').funct();
+ mxEvent.consume(evt);
+ }), Editor.zoomInImage, mxResources.get('zoomIn') + ' (Alt+Mousewheel)');
+
+ addButton(mxUtils.bind(this, function (evt) {
+ if (graph.isLightboxView()) {
+ if (graph.view.scale == 1) {
+ this.lightboxFit();
+ }
+ else {
+ graph.zoomTo(1);
+ }
+
+ this.chromelessResize(false);
+ }
+ else {
+ this.chromelessResize(true);
+ }
+
+ mxEvent.consume(evt);
+ }), Editor.zoomFitImage, mxResources.get('fit'));
+
+ // Changes toolbar opacity on hover
+ var fadeThread = null;
+ var fadeThread2 = null;
+
+ var fadeOut = mxUtils.bind(this, function (delay) {
+ if (fadeThread != null) {
+ window.clearTimeout(fadeThread);
+ fadeThread = null;
+ }
+
+ if (fadeThread2 != null) {
+ window.clearTimeout(fadeThread2);
+ fadeThread2 = null;
+ }
+
+ fadeThread = window.setTimeout(mxUtils.bind(this, function () {
+ mxUtils.setOpacity(this.chromelessToolbar, 0);
+ fadeThread = null;
+
+ fadeThread2 = window.setTimeout(mxUtils.bind(this, function () {
+ this.chromelessToolbar.style.display = 'none';
+ fadeThread2 = null;
+ }), 600);
+ }), delay || 200);
+ });
+
+ var fadeIn = mxUtils.bind(this, function (opacity) {
+ if (fadeThread != null) {
+ window.clearTimeout(fadeThread);
+ fadeThread = null;
+ }
+
+ if (fadeThread2 != null) {
+ window.clearTimeout(fadeThread2);
+ fadeThread2 = null;
+ }
+
+ this.chromelessToolbar.style.display = '';
+ mxUtils.setOpacity(this.chromelessToolbar, opacity || 30);
+ });
+
+ if (urlParams['layers'] == '1') {
+ this.layersDialog = null;
+
+ var layersButton = addButton(mxUtils.bind(this, function (evt) {
+ if (this.layersDialog != null) {
+ this.layersDialog.parentNode.removeChild(this.layersDialog);
+ this.layersDialog = null;
+ }
+ else {
+ this.layersDialog = graph.createLayersDialog(null, true);
+
+ mxEvent.addListener(this.layersDialog, 'mouseleave', mxUtils.bind(this, function () {
+ this.layersDialog.parentNode.removeChild(this.layersDialog);
+ this.layersDialog = null;
+ }));
+
+ var r = layersButton.getBoundingClientRect();
+
+ mxUtils.setPrefixedStyle(this.layersDialog.style, 'borderRadius', '5px');
+ this.layersDialog.style.position = 'fixed';
+ this.layersDialog.style.fontFamily = Editor.defaultHtmlFont;
+ this.layersDialog.style.width = '160px';
+ this.layersDialog.style.padding = '4px 2px 4px 2px';
+ this.layersDialog.style.left = r.left + 'px';
+ this.layersDialog.style.bottom = parseInt(this.chromelessToolbar.style.bottom) +
+ this.chromelessToolbar.offsetHeight + 4 + 'px';
+
+ if (!mxClient.IS_IE && !mxClient.IS_IE11) {
+ this.layersDialog.style.backgroundColor = '#000000';
+ this.layersDialog.style.color = '#ffffff';
+ mxUtils.setOpacity(this.layersDialog, 80);
+ }
+ else {
+ this.layersDialog.style.backgroundColor = '#ffffff';
+ this.layersDialog.style.border = '2px solid black';
+ this.layersDialog.style.color = '#000000';
+ }
+
+ // Puts the dialog on top of the container z-index
+ var style = mxUtils.getCurrentStyle(this.editor.graph.container);
+ this.layersDialog.style.zIndex = style.zIndex;
+
+ document.body.appendChild(this.layersDialog);
+ this.editor.fireEvent(new mxEventObject('layersDialogShown'));
+ }
+
+ mxEvent.consume(evt);
+ }), Editor.layersImage, mxResources.get('layers'));
+
+ // Shows/hides layers button depending on content
+ var model = graph.getModel();
+
+ model.addListener(mxEvent.CHANGE, function () {
+ layersButton.style.display = (model.getChildCount(model.root) > 1) ? '' : 'none';
+ });
+ }
+
+ if (urlParams['openInSameWin'] != '1' || navigator.standalone) {
+ this.addChromelessToolbarItems(addButton);
+ }
+
+ if (this.editor.editButtonLink != null || this.editor.editButtonFunc != null) {
+ addButton(mxUtils.bind(this, function (evt) {
+ if (this.editor.editButtonFunc != null) {
+ this.editor.editButtonFunc();
+ }
+ else if (this.editor.editButtonLink == '_blank') {
+ this.editor.editAsNew(this.getEditBlankXml());
+ }
+ else {
+ graph.openLink(this.editor.editButtonLink, 'editWindow');
+ }
+
+ mxEvent.consume(evt);
+ }), Editor.editImage, mxResources.get('edit'));
+ }
+
+ if (this.lightboxToolbarActions != null) {
+ for (var i = 0; i < this.lightboxToolbarActions.length; i++) {
+ var lbAction = this.lightboxToolbarActions[i];
+ lbAction.elem = addButton(lbAction.fn, lbAction.icon, lbAction.tooltip);
+ }
+ }
+
+ if (toolbarConfig.refreshBtn != null) {
+ var refreshUrl = (toolbarConfig.refreshBtn.url == null) ? null :
+ Graph.sanitizeLink(toolbarConfig.refreshBtn.url);
+
+ addButton(mxUtils.bind(this, function (evt) {
+ if (refreshUrl != null) {
+ window.location.href = refreshUrl;
+ }
+ else {
+ window.location.reload();
+ }
+
+ mxEvent.consume(evt);
+ }), Editor.refreshImage, mxResources.get('refresh', null, 'Refresh'));
+ }
+
+ if (toolbarConfig.fullscreenBtn != null && window.self !== window.top) {
+ addButton(mxUtils.bind(this, function (evt) {
+ if (toolbarConfig.fullscreenBtn.url) {
+ graph.openLink(toolbarConfig.fullscreenBtn.url);
+ }
+ else {
+ graph.openLink(window.location.href);
+ }
+
+ mxEvent.consume(evt);
+ }), Editor.fullscreenImage, mxResources.get('openInNewWindow', null, 'Open in New Window'));
+ }
+
+ if (!toolbarConfig.noCloseBtn && ((toolbarConfig.closeBtn && window.self === window.top) ||
+ (graph.lightbox && (urlParams['close'] == '1' || this.container != document.body)))) {
+ addButton(mxUtils.bind(this, function (evt) {
+ if (urlParams['close'] == '1' || toolbarConfig.closeBtn) {
+ window.close();
+ }
+ else {
+ this.destroy();
+ mxEvent.consume(evt);
+ }
+ }), Editor.closeImage, mxResources.get('close') + ' (Escape)');
+ }
+
+ // Initial state invisible
+ this.chromelessToolbar.style.display = 'none';
+
+ if (!graph.isViewer()) {
+ mxUtils.setPrefixedStyle(this.chromelessToolbar.style, 'transform', 'translate(-50%,0)');
+ }
+
+ graph.container.appendChild(this.chromelessToolbar);
+
+ mxEvent.addListener(graph.container, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', mxUtils.bind(this, function (evt) {
+ if (!mxEvent.isTouchEvent(evt)) {
+ if (!mxEvent.isShiftDown(evt)) {
+ fadeIn(30);
+ }
+
+ fadeOut();
+ }
+ }));
+
+ mxEvent.addListener(this.chromelessToolbar, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', function (evt) {
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(this.chromelessToolbar, 'mouseenter', mxUtils.bind(this, function (evt) {
+ graph.tooltipHandler.resetTimer();
+ graph.tooltipHandler.hideTooltip();
+
+ if (!mxEvent.isShiftDown(evt)) {
+ fadeIn(100);
+ }
+ else {
+ fadeOut();
+ }
+ }));
+
+ mxEvent.addListener(this.chromelessToolbar, 'mousemove', mxUtils.bind(this, function (evt) {
+ if (!mxEvent.isShiftDown(evt)) {
+ fadeIn(100);
+ }
+ else {
+ fadeOut();
+ }
+
+ mxEvent.consume(evt);
+ }));
+
+ mxEvent.addListener(this.chromelessToolbar, 'mouseleave', mxUtils.bind(this, function (evt) {
+ if (!mxEvent.isTouchEvent(evt)) {
+ fadeIn(30);
+ }
+ }));
+
+ // Shows/hides toolbar for touch devices
+ var tol = graph.getTolerance();
+
+ graph.addMouseListener(
+ {
+ startX: 0,
+ startY: 0,
+ scrollLeft: 0,
+ scrollTop: 0,
+ mouseDown: function (sender, me) {
+ this.startX = me.getGraphX();
+ this.startY = me.getGraphY();
+ this.scrollLeft = graph.container.scrollLeft;
+ this.scrollTop = graph.container.scrollTop;
+ },
+ mouseMove: function (sender, me) { },
+ mouseUp: function (sender, me) {
+ if (mxEvent.isTouchEvent(me.getEvent())) {
+ if ((Math.abs(this.scrollLeft - graph.container.scrollLeft) < tol &&
+ Math.abs(this.scrollTop - graph.container.scrollTop) < tol) &&
+ (Math.abs(this.startX - me.getGraphX()) < tol &&
+ Math.abs(this.startY - me.getGraphY()) < tol)) {
+ if (parseFloat(ui.chromelessToolbar.style.opacity || 0) > 0) {
+ fadeOut();
+ }
+ else {
+ fadeIn(30);
+ }
+ }
+ }
+ }
+ });
+ } // end if toolbar
+
+ // Installs handling of highlight and handling links to relative links and anchors
+ if (!this.editor.editable) {
+ this.addChromelessClickHandler();
+ }
+ }
+ else if (this.editor.extendCanvas) {
+ /**
+ * Guesses autoTranslate to avoid another repaint (see below).
+ * Works if only the scale of the graph changes or if pages
+ * are visible and the visible pages do not change. Uses
+ * geometries to guess the bounding box of the graph.
+ */
+ var graphViewValidate = graph.view.validate;
+ var zero = new mxPoint();
+ var lastPage = null;
+
+ graph.view.validate = function () {
+ if (graph.container != null &&
+ mxUtils.hasScrollbars(graph.container)) {
+ // Sets initial state after page changes
+ if (ui.currentPage != null &&
+ lastPage != ui.currentPage) {
+ lastPage = ui.currentPage;
+
+ // Sets initial translate based on geometries
+ // to avoid revalidation in sizeDidChange
+ var bbox = graph.getBoundingBoxFromGeometry(
+ graph.model.getCells(), true);
+
+ // Handles blank diagrams
+ if (bbox == null) {
+ bbox = new mxRectangle(
+ graph.view.translate.x * graph.view.scale,
+ graph.view.translate.y * graph.view.scale);
+ }
+
+ var pageLayout = graph.getPageLayout(bbox, zero, 1);
+ var tr = graph.getDefaultTranslate(pageLayout);
+ this.x0 = pageLayout.x;
+ this.y0 = pageLayout.y;
+
+ if (tr.x != this.translate.x ||
+ tr.y != this.translate.y) {
+ this.invalidate();
+ this.translate.x = tr.x;
+ this.translate.y = tr.y;
+ }
+ }
+
+ var pad = graph.getPagePadding();
+ var size = graph.getPageSize();
+ var tx = pad.x - (this.x0 || 0) * size.width;
+ var ty = pad.y - (this.y0 || 0) * size.height;
+
+ if (this.translate.x != tx || this.translate.y != ty) {
+ this.invalidate();
+ this.translate.x = tx
+ this.translate.y = ty
+ }
+ }
+
+ graphViewValidate.apply(this, arguments);
+ };
+
+ if (!graph.isViewer()) {
+ var graphSizeDidChange = graph.sizeDidChange;
+
+ graph.sizeDidChange = function () {
+ if (this.container != null &&
+ mxUtils.hasScrollbars(this.container)) {
+ this.updateMinimumSize();
+
+ if (!this.autoTranslate) {
+ var pageLayout = this.getPageLayout();
+ var tr = this.getDefaultTranslate(pageLayout);
+ var tx = this.view.translate.x;
+ var ty = this.view.translate.y;
+
+ if (tr.x != tx || tr.y != ty) {
+ this.view.x0 = pageLayout.x;
+ this.view.y0 = pageLayout.y;
+ this.autoTranslate = true;
+
+ // Requires full revalidation
+ this.view.setTranslate(tr.x, tr.y);
+ this.container.scrollLeft += Math.round((tr.x - tx) * this.view.scale);
+ this.container.scrollTop += Math.round((tr.y - ty) * this.view.scale);
+ this.autoTranslate = false;
+
+ return;
+ }
+ }
+
+ graphSizeDidChange.apply(this, arguments);
+ }
+ else {
+ // Fires event but does not invoke superclass
+ this.fireEvent(new mxEventObject(mxEvent.SIZE,
+ 'bounds', this.getGraphBounds()));
+ }
+ };
+ }
+ }
+
+ // Accumulates the zoom factor while the rendering is taking place
+ // so that not the complete sequence of zoom steps must be painted
+ var bgGroup = graph.view.getBackgroundPane();
+ var mainGroup = graph.view.getDrawPane();
+ graph.cumulativeZoomFactor = 1;
+ var updateZoomTimeout = null;
+ var cursorPosition = null;
+ var scrollPosition = null;
+ var forcedZoom = null;
+ var filter = null;
+ var mult = 20;
+
+ var scheduleZoom = function (delay) {
+ if (updateZoomTimeout != null) {
+ window.clearTimeout(updateZoomTimeout);
+ }
+
+ if (delay >= 0) {
+ window.setTimeout(function () {
+ if (!graph.isMouseDown || forcedZoom) {
+ updateZoomTimeout = window.setTimeout(mxUtils.bind(this, function () {
+ if (graph.isFastZoomEnabled()) {
+ // Transforms background page
+ if (graph.view.backgroundPageShape != null && graph.view.backgroundPageShape.node != null) {
+ mxUtils.setPrefixedStyle(graph.view.backgroundPageShape.node.style, 'transform-origin', null);
+ mxUtils.setPrefixedStyle(graph.view.backgroundPageShape.node.style, 'transform', null);
+ }
+
+ // Transforms graph and background image
+ mainGroup.style.transformOrigin = '';
+ bgGroup.style.transformOrigin = '';
+
+ // Workaround for no reset of transform in Safari
+ if (mxClient.IS_SF) {
+ mainGroup.style.transform = 'scale(1)';
+ bgGroup.style.transform = 'scale(1)';
+
+ window.setTimeout(function () {
+ mainGroup.style.transform = '';
+ bgGroup.style.transform = '';
+ }, 0)
+ }
+ else {
+ mainGroup.style.transform = '';
+ bgGroup.style.transform = '';
+ }
+
+ // Shows interactive elements
+ graph.view.getDecoratorPane().style.opacity = '';
+ graph.view.getOverlayPane().style.opacity = '';
+ }
+
+ var sp = new mxPoint(graph.container.scrollLeft, graph.container.scrollTop);
+ var offset = mxUtils.getOffset(graph.container);
+ var prev = graph.view.scale;
+ var dx = 0;
+ var dy = 0;
+
+ if (cursorPosition != null) {
+ dx = graph.container.offsetWidth / 2 - cursorPosition.x + offset.x;
+ dy = graph.container.offsetHeight / 2 - cursorPosition.y + offset.y;
+ }
+
+ graph.zoom(graph.cumulativeZoomFactor, null,
+ graph.isFastZoomEnabled() ? mult : null);
+ var s = graph.view.scale;
+
+ if (s != prev) {
+ if (scrollPosition != null) {
+ dx += sp.x - scrollPosition.x;
+ dy += sp.y - scrollPosition.y;
+ }
+
+ if (resize != null) {
+ ui.chromelessResize(false, null, dx * (graph.cumulativeZoomFactor - 1),
+ dy * (graph.cumulativeZoomFactor - 1));
+ }
+
+ if (mxUtils.hasScrollbars(graph.container) && (dx != 0 || dy != 0)) {
+ graph.container.scrollLeft -= dx * (graph.cumulativeZoomFactor - 1);
+ graph.container.scrollTop -= dy * (graph.cumulativeZoomFactor - 1);
+ }
+ }
+
+ if (filter != null) {
+ mainGroup.setAttribute('filter', filter);
+ }
+
+ graph.cumulativeZoomFactor = 1;
+ updateZoomTimeout = null;
+ scrollPosition = null;
+ cursorPosition = null;
+ forcedZoom = null;
+ filter = null;
+ }), (delay != null) ? delay : ((graph.isFastZoomEnabled()) ? ui.wheelZoomDelay : ui.lazyZoomDelay));
+ }
+ }, 0);
+ }
+ };
+
+ graph.lazyZoom = function (zoomIn, ignoreCursorPosition, delay, factor) {
+ factor = (factor != null) ? factor : this.zoomFactor;
+
+ // TODO: Fix ignored cursor position if scrollbars are disabled
+ ignoreCursorPosition = ignoreCursorPosition || !graph.scrollbars;
+
+ if (ignoreCursorPosition) {
+ cursorPosition = new mxPoint(
+ graph.container.offsetLeft + graph.container.clientWidth / 2,
+ graph.container.offsetTop + graph.container.clientHeight / 2);
+ }
+
+ // Switches to 5% zoom steps below 15%
+ if (zoomIn) {
+ if (this.view.scale * this.cumulativeZoomFactor <= 0.15) {
+ this.cumulativeZoomFactor *= (this.view.scale + 0.05) / this.view.scale;
+ }
+ else {
+ this.cumulativeZoomFactor *= factor;
+ this.cumulativeZoomFactor = Math.round(this.view.scale * this.cumulativeZoomFactor * 100) / 100 / this.view.scale;
+ }
+ }
+ else {
+ if (this.view.scale * this.cumulativeZoomFactor <= 0.15) {
+ this.cumulativeZoomFactor *= (this.view.scale - 0.05) / this.view.scale;
+ }
+ else {
+ this.cumulativeZoomFactor /= factor;
+ this.cumulativeZoomFactor = Math.round(this.view.scale * this.cumulativeZoomFactor * 100) / 100 / this.view.scale;
+ }
+ }
+
+ this.cumulativeZoomFactor = Math.max(0.05, Math.min(this.view.scale * this.cumulativeZoomFactor, 160)) / this.view.scale;
+
+ if (graph.isFastZoomEnabled()) {
+ if (filter == null && mainGroup.getAttribute('filter') != '') {
+ filter = mainGroup.getAttribute('filter');
+ mainGroup.removeAttribute('filter');
+ }
+
+ scrollPosition = new mxPoint(graph.container.scrollLeft, graph.container.scrollTop);
+
+ // Applies final rounding to preview
+ var f = Math.round((Math.round(this.view.scale * this.cumulativeZoomFactor *
+ 100) / 100) * mult) / (mult * this.view.scale);
+
+ var cx = (ignoreCursorPosition || cursorPosition == null) ?
+ graph.container.scrollLeft + graph.container.clientWidth / 2 :
+ cursorPosition.x + graph.container.scrollLeft - graph.container.offsetLeft;
+ var cy = (ignoreCursorPosition || cursorPosition == null) ?
+ graph.container.scrollTop + graph.container.clientHeight / 2 :
+ cursorPosition.y + graph.container.scrollTop - graph.container.offsetTop;
+ mainGroup.style.transformOrigin = cx + 'px ' + cy + 'px';
+ mainGroup.style.transform = 'scale(' + f + ')';
+ bgGroup.style.transformOrigin = cx + 'px ' + cy + 'px';
+ bgGroup.style.transform = 'scale(' + f + ')';
+
+ if (graph.view.backgroundPageShape != null && graph.view.backgroundPageShape.node != null) {
+ var page = graph.view.backgroundPageShape.node;
+
+ mxUtils.setPrefixedStyle(page.style, 'transform-origin',
+ ((ignoreCursorPosition || cursorPosition == null) ?
+ ((graph.container.clientWidth / 2 + graph.container.scrollLeft -
+ page.offsetLeft) + 'px') : ((cursorPosition.x + graph.container.scrollLeft -
+ page.offsetLeft - graph.container.offsetLeft) + 'px')) + ' ' +
+ ((ignoreCursorPosition || cursorPosition == null) ?
+ ((graph.container.clientHeight / 2 + graph.container.scrollTop -
+ page.offsetTop) + 'px') : ((cursorPosition.y + graph.container.scrollTop -
+ page.offsetTop - graph.container.offsetTop) + 'px')));
+ mxUtils.setPrefixedStyle(page.style, 'transform', 'scale(' + f + ')');
+ }
+ else {
+ graph.view.validateBackgroundStyles(f, cx, cy);
+ }
+
+ graph.view.getDecoratorPane().style.opacity = '0';
+ graph.view.getOverlayPane().style.opacity = '0';
+
+ if (ui.hoverIcons != null) {
+ ui.hoverIcons.reset();
+ }
+
+ graph.fireEvent(new mxEventObject('zoomPreview', 'factor', f));
+ }
+
+ scheduleZoom(graph.isFastZoomEnabled() ? delay : 0);
+ };
+
+ // Holds back repaint until after mouse gestures
+ mxEvent.addGestureListeners(graph.container, function (evt) {
+ if (updateZoomTimeout != null) {
+ window.clearTimeout(updateZoomTimeout);
+ }
+ }, null, function (evt) {
+ if (graph.cumulativeZoomFactor != 1) {
+ scheduleZoom(0);
+ }
+ });
+
+ // Holds back repaint until scroll ends
+ mxEvent.addListener(graph.container, 'scroll', function (evt) {
+ if (updateZoomTimeout != null && !graph.isMouseDown && graph.cumulativeZoomFactor != 1) {
+ scheduleZoom(0);
+ }
+ });
+
+ mxEvent.addMouseWheelListener(mxUtils.bind(this, function (evt, up, force, cx, cy) {
+ graph.fireEvent(new mxEventObject('wheel'));
+
+ if (this.dialogs == null || this.dialogs.length == 0) {
+ // Scrolls with scrollbars turned off
+ if (!graph.scrollbars && !force && graph.isScrollWheelEvent(evt)) {
+ var t = graph.view.getTranslate();
+ var step = 40 / graph.view.scale;
+
+ if (!mxEvent.isShiftDown(evt)) {
+ graph.view.setTranslate(t.x, t.y + ((up) ? step : -step));
+ }
+ else {
+ graph.view.setTranslate(t.x + ((up) ? -step : step), t.y);
+ }
+ }
+ else if (force || graph.isZoomWheelEvent(evt)) {
+ var source = mxEvent.getSource(evt);
+
+ while (source != null) {
+ if (source == graph.container) {
+ graph.tooltipHandler.hideTooltip();
+ cursorPosition = (cx != null && cy != null) ? new mxPoint(cx, cy) :
+ new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
+ forcedZoom = force;
+ var factor = graph.zoomFactor;
+ var delay = null;
+
+ // Slower zoom for pinch gesture on trackpad with max delta to
+ // filter out mouse wheel events in Brave browser for Windows
+ if (evt.ctrlKey && evt.deltaY != null && Math.abs(evt.deltaY) < 40 &&
+ Math.round(evt.deltaY) != evt.deltaY) {
+ factor = 1 + (Math.abs(evt.deltaY) / 20) * (factor - 1);
+ }
+ // Slower zoom for pinch gesture on touch screens
+ else if (evt.movementY != null && evt.type == 'pointermove') {
+ factor = 1 + (Math.max(1, Math.abs(evt.movementY)) / 20) * (factor - 1);
+ delay = -1;
+ }
+
+ graph.lazyZoom(up, null, delay, factor);
+ mxEvent.consume(evt);
+
+ return false;
+ }
+
+ source = source.parentNode;
+ }
+ }
+ }
+ }), graph.container);
+
+ // Uses fast zoom for pinch gestures on iOS
+ graph.panningHandler.zoomGraph = function (evt) {
+ graph.cumulativeZoomFactor = evt.scale;
+ graph.lazyZoom(evt.scale > 0, true);
+ mxEvent.consume(evt);
+ };
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.addChromelessToolbarItems = function (addButton) {
+ addButton(mxUtils.bind(this, function (evt) {
+ this.actions.get('print').funct();
+ mxEvent.consume(evt);
+ }), Editor.printImage, mxResources.get('print'));
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.isPagesEnabled = function () {
+ return this.editor.editable || urlParams['hide-pages'] != '1';
+};
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+EditorUi.prototype.createTemporaryGraph = function (stylesheet) {
+ return Graph.createOffscreenGraph(stylesheet);
+};
+
+/**
+ *
+ */
+EditorUi.prototype.addChromelessClickHandler = function () {
+ var hl = urlParams['highlight'];
+
+ // Adds leading # for highlight color code
+ if (hl != null && hl.length > 0) {
+ hl = '#' + hl;
+ }
+
+ this.editor.graph.addClickHandler(hl);
+};
+
+/**
+ *
+ */
+EditorUi.prototype.toggleFormatPanel = function (visible) {
+ visible = (visible != null) ? visible : this.formatWidth == 0;
+
+ if (this.format != null) {
+ this.formatWidth = (visible) ? 240 : 0;
+ this.formatContainer.style.width = this.formatWidth + 'px';
+ this.refresh();
+ this.format.refresh();
+ this.fireEvent(new mxEventObject('formatWidthChanged'));
+ }
+};
+
+/**
+ *
+ */
+EditorUi.prototype.isFormatPanelVisible = function () {
+ return this.formatWidth > 0;
+};
+
+/**
+ * Adds support for placeholders in labels.
+ */
+EditorUi.prototype.lightboxFit = function (maxHeight) {
+ if (this.isDiagramEmpty()) {
+ this.editor.graph.view.setScale(1);
+ }
+ else {
+ var p = urlParams['border'];
+ var border = 60;
+
+ if (p != null) {
+ border = parseInt(p);
+ }
+
+ // LATER: Use initial graph bounds to avoid rounding errors
+ this.editor.graph.maxFitScale = this.lightboxMaxFitScale;
+ this.editor.graph.fit(border, null, null, null, null, null, maxHeight);
+ this.editor.graph.maxFitScale = null;
+ }
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.isDiagramEmpty = function () {
+ var model = this.editor.graph.getModel();
+
+ return model.getChildCount(model.root) == 1 && model.getChildCount(model.getChildAt(model.root, 0)) == 0;
+};
+
+/**
+ * Hook for allowing selection and context menu for certain events.
+ */
+EditorUi.prototype.isSelectionAllowed = function (evt) {
+ return mxEvent.getSource(evt).nodeName == 'SELECT' || (mxEvent.getSource(evt).nodeName == 'INPUT' &&
+ mxUtils.isAncestorNode(this.formatContainer, mxEvent.getSource(evt)));
+};
+
+/**
+ * Installs dialog if browser window is closed without saving
+ * This must be disabled during save and image export.
+ */
+EditorUi.prototype.addBeforeUnloadListener = function () {
+ // Installs dialog if browser window is closed without saving
+ // This must be disabled during save and image export
+ window.onbeforeunload = mxUtils.bind(this, function () {
+ if (!this.editor.isChromelessView()) {
+ return this.onBeforeUnload();
+ }
+ });
+};
+
+/**
+ * Sets the onbeforeunload for the application
+ */
+EditorUi.prototype.onBeforeUnload = function () {
+ if (this.editor.modified) {
+ return mxResources.get('allChangesLost');
+ }
+};
+
+/**
+ * Opens the current diagram via the window.opener if one exists.
+ */
+EditorUi.prototype.open = function () {
+ // Cross-domain window access is not allowed in FF, so if we
+ // were opened from another domain then this will fail.
+ try {
+ if (window.opener != null && window.opener.openFile != null) {
+ window.opener.openFile.setConsumer(mxUtils.bind(this, function (xml, filename) {
+ try {
+ var doc = mxUtils.parseXml(xml);
+ this.editor.setGraphXml(doc.documentElement);
+ this.editor.setModified(false);
+ this.editor.undoManager.clear();
+
+ if (filename != null) {
+ this.editor.setFilename(filename);
+ this.updateDocumentTitle();
+ }
+
+ return;
+ }
+ catch (e) {
+ mxUtils.alert(mxResources.get('invalidOrMissingFile') + ': ' + e.message);
+ }
+ }));
+ }
+ }
+ catch (e) {
+ // ignore
+ }
+
+ // Fires as the last step if no file was loaded
+ this.editor.graph.view.validate();
+
+ // Required only in special cases where an initial file is opened
+ // and the minimumGraphSize changes and CSS must be updated.
+ this.editor.graph.sizeDidChange();
+ this.editor.fireEvent(new mxEventObject('resetGraphView'));
+};
+
+/**
+ * Shows the given popup menu.
+ */
+EditorUi.prototype.showPopupMenu = function (fn, x, y, evt) {
+ this.editor.graph.popupMenuHandler.hideMenu();
+
+ var menu = new mxPopupMenu(fn);
+ menu.div.className += ' geMenubarMenu';
+ menu.smartSeparators = true;
+ menu.showDisabled = true;
+ menu.autoExpand = true;
+
+ // Disables autoexpand and destroys menu when hidden
+ menu.hideMenu = mxUtils.bind(this, function () {
+ mxPopupMenu.prototype.hideMenu.apply(menu, arguments);
+ menu.destroy();
+ });
+
+ menu.popup(x, y, null, evt);
+
+ // Allows hiding by clicking on document
+ this.setCurrentMenu(menu);
+};
+
+/**
+ * Sets the current menu and element.
+ */
+EditorUi.prototype.setCurrentMenu = function (menu, elt) {
+ this.currentMenuElt = elt;
+ this.currentMenu = menu;
+ this.hideShapePicker();
+};
+
+/**
+ * Resets the current menu and element.
+ */
+EditorUi.prototype.resetCurrentMenu = function () {
+ this.currentMenuElt = null;
+ this.currentMenu = null;
+};
+
+/**
+ * Hides and destroys the current menu.
+ */
+EditorUi.prototype.hideCurrentMenu = function () {
+ if (this.currentMenu != null) {
+ this.currentMenu.hideMenu();
+ this.resetCurrentMenu();
+ }
+};
+
+/**
+ * Updates the document title.
+ */
+EditorUi.prototype.updateDocumentTitle = function () {
+ var title = this.editor.getOrCreateFilename();
+
+ if (this.editor.appName != null) {
+ title += ' - ' + this.editor.appName;
+ }
+
+ document.title = title;
+};
+
+/**
+ * Updates the document title.
+ */
+EditorUi.prototype.createHoverIcons = function () {
+ return new HoverIcons(this.editor.graph);
+};
+
+/**
+ * Returns the URL for a copy of this editor with no state.
+ */
+EditorUi.prototype.redo = function () {
+ try {
+ var graph = this.editor.graph;
+
+ if (graph.isEditing()) {
+ document.execCommand('redo', false, null);
+ }
+ else {
+ this.editor.undoManager.redo();
+ }
+ }
+ catch (e) {
+ // ignore all errors
+ }
+};
+
+/**
+ * Returns the URL for a copy of this editor with no state.
+ */
+EditorUi.prototype.undo = function () {
+ try {
+ var graph = this.editor.graph;
+
+ if (graph.isEditing()) {
+ // Stops editing and executes undo on graph if native undo
+ // does not affect current editing value
+ var value = graph.cellEditor.textarea.innerHTML;
+ document.execCommand('undo', false, null);
+
+ if (value == graph.cellEditor.textarea.innerHTML) {
+ graph.stopEditing(true);
+ this.editor.undoManager.undo();
+ }
+ }
+ else {
+ this.editor.undoManager.undo();
+ }
+ }
+ catch (e) {
+ // ignore all errors
+ }
+};
+
+/**
+ * Returns the URL for a copy of this editor with no state.
+ */
+EditorUi.prototype.canRedo = function () {
+ return this.editor.graph.isEditing() || this.editor.undoManager.canRedo();
+};
+
+/**
+ * Returns the URL for a copy of this editor with no state.
+ */
+EditorUi.prototype.canUndo = function () {
+ return this.editor.graph.isEditing() || this.editor.undoManager.canUndo();
+};
+
+/**
+ *
+ */
+EditorUi.prototype.getEditBlankXml = function () {
+ return mxUtils.getXml(this.editor.getGraphXml());
+};
+
+/**
+ * Returns the URL for a copy of this editor with no state.
+ */
+EditorUi.prototype.getUrl = function (pathname) {
+ var href = (pathname != null) ? pathname : window.location.pathname;
+ var parms = (href.indexOf('?') > 0) ? 1 : 0;
+
+ // Removes template URL parameter for new blank diagram
+ for (var key in urlParams) {
+ if (parms == 0) {
+ href += '?';
+ }
+ else {
+ href += '&';
+ }
+
+ href += key + '=' + urlParams[key];
+ parms++;
+ }
+
+ return href;
+};
+
+/**
+ * Specifies if the graph has scrollbars.
+ */
+EditorUi.prototype.setScrollbars = function (value) {
+ var graph = this.editor.graph;
+ var prev = graph.container.style.overflow;
+ graph.scrollbars = value;
+ this.editor.updateGraphComponents();
+
+ if (prev != graph.container.style.overflow) {
+ graph.container.scrollTop = 0;
+ graph.container.scrollLeft = 0;
+ graph.view.scaleAndTranslate(1, 0, 0);
+ this.resetScrollbars();
+ }
+
+ this.fireEvent(new mxEventObject('scrollbarsChanged'));
+};
+
+/**
+ * Function: fitDiagramToWindow
+ *
+ * Zooms the diagram to fit into the window.
+ */
+EditorUi.prototype.fitDiagramToWindow = function () {
+ var graph = this.editor.graph;
+ var bounds = (graph.isSelectionEmpty()) ?
+ mxRectangle.fromRectangle(graph.getGraphBounds()) :
+ graph.getBoundingBox(graph.getSelectionCells())
+ var t = graph.view.translate;
+ var s = graph.view.scale;
+
+ bounds.x = bounds.x / s - t.x;
+ bounds.y = bounds.y / s - t.y;
+ bounds.width /= s;
+ bounds.height /= s;
+
+ if (graph.backgroundImage != null) {
+ bounds.add(new mxRectangle(0, 0,
+ graph.backgroundImage.width,
+ graph.backgroundImage.height));
+ }
+
+ if (bounds.width == 0 || bounds.height == 0) {
+ graph.zoomTo(1);
+ this.resetScrollbars();
+ }
+ else {
+ var b = Editor.fitWindowBorders;
+
+ if (b != null) {
+ bounds.x -= b.x;
+ bounds.y -= b.y;
+ bounds.width += b.width + b.x;
+ bounds.height += b.height + b.y;
+ }
+
+ graph.fitWindow(bounds);
+ }
+};
+
+/**
+ * Returns true if the graph has scrollbars.
+ */
+EditorUi.prototype.hasScrollbars = function () {
+ return this.editor.graph.scrollbars;
+};
+
+/**
+ * Resets the state of the scrollbars.
+ */
+EditorUi.prototype.resetScrollbars = function () {
+ var graph = this.editor.graph;
+ var c = graph.container;
+
+ if (!this.editor.extendCanvas) {
+ c.scrollTop = 0;
+ c.scrollLeft = 0;
+
+ if (!mxUtils.hasScrollbars(c)) {
+ graph.view.setTranslate(0, 0);
+ }
+ }
+ else if (!this.editor.isChromelessView()) {
+ if (mxUtils.hasScrollbars(c)) {
+ if (graph.pageVisible) {
+ var pad = graph.getPagePadding();
+ c.scrollTop = Math.floor(pad.y - this.editor.initialTopSpacing) - 1;
+ c.scrollLeft = Math.floor(Math.min(pad.x,
+ (c.scrollWidth - c.clientWidth) / 2)) - 1;
+
+ // Scrolls graph to visible area
+ var bounds = graph.getGraphBounds();
+
+ if (bounds.width > 0 && bounds.height > 0) {
+ if (bounds.x > c.scrollLeft + c.clientWidth * 0.9) {
+ c.scrollLeft = Math.min(bounds.x + bounds.width - c.clientWidth, bounds.x - 10);
+ }
+
+ if (bounds.y > c.scrollTop + c.clientHeight * 0.9) {
+ c.scrollTop = Math.min(bounds.y + bounds.height - c.clientHeight, bounds.y - 10);
+ }
+ }
+ }
+ else {
+ var bounds = graph.getGraphBounds();
+
+ if (bounds.width == 0 && bounds.height == 0) {
+ c.scrollLeft = (c.scrollWidth - c.clientWidth) / 2;
+ c.scrollTop = (c.scrollHeight - c.clientHeight) / 2;
+ }
+ else {
+ var width = Math.max(bounds.width, graph.scrollTileSize.width * graph.view.scale);
+ var height = Math.max(bounds.height, graph.scrollTileSize.height * graph.view.scale);
+
+ c.scrollLeft = Math.floor(Math.max(0, bounds.x - Math.max(0, (c.clientWidth - width) / 2)));
+ c.scrollTop = Math.floor(Math.max(0, bounds.y - Math.max(20, (c.clientHeight - height) / 4)));
+ }
+ }
+ }
+ else {
+ var b = mxRectangle.fromRectangle((graph.pageVisible) ?
+ graph.view.getBackgroundPageBounds() :
+ graph.getGraphBounds())
+ var tr = graph.view.translate;
+ var s = graph.view.scale;
+ b.x = b.x / s - tr.x;
+ b.y = b.y / s - tr.y;
+ b.width /= s;
+ b.height /= s;
+
+ var dy = (graph.pageVisible) ? 0 : Math.max(0, (c.clientHeight - b.height) / 4);
+
+ graph.view.setTranslate(Math.floor(Math.max(0,
+ (c.clientWidth - b.width) / 2) - b.x + 2),
+ Math.floor(dy - b.y + 1));
+ }
+ }
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setPageVisible = function (value) {
+ var graph = this.editor.graph;
+ var hasScrollbars = mxUtils.hasScrollbars(graph.container);
+ var tx = 0;
+ var ty = 0;
+
+ if (hasScrollbars) {
+ tx = graph.view.translate.x * graph.view.scale - graph.container.scrollLeft;
+ ty = graph.view.translate.y * graph.view.scale - graph.container.scrollTop;
+ }
+
+ graph.pageVisible = value;
+ graph.pageBreaksVisible = value;
+ graph.preferPageSize = value;
+ graph.view.validateBackground();
+
+ // Workaround for possible handle offset
+ if (hasScrollbars) {
+ var cells = graph.getSelectionCells();
+ graph.clearSelection();
+ graph.setSelectionCells(cells);
+ }
+
+ // Calls updatePageBreaks
+ graph.sizeDidChange();
+
+ if (hasScrollbars) {
+ graph.container.scrollLeft = graph.view.translate.x * graph.view.scale - tx;
+ graph.container.scrollTop = graph.view.translate.y * graph.view.scale - ty;
+ }
+
+ graph.defaultPageVisible = value;
+ this.fireEvent(new mxEventObject('pageViewChanged'));
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.installResizeHandler = function (dialog, resizable, destroy) {
+ if (resizable) {
+ dialog.window.setSize = function (w, h) {
+ if (!this.minimized) {
+ var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth;
+ var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
+ w = Math.min(w, iw - this.getX());
+ h = Math.min(h, ih - this.getY());
+ }
+
+ mxWindow.prototype.setSize.apply(this, arguments);
+ };
+ }
+
+ dialog.window.setLocation = function (x, y) {
+ var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth;
+ var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
+
+ var w = parseInt(this.div.style.width);
+ var h = parseInt(this.div.style.height);
+
+ x = Math.max(0, Math.min(x, iw - w));
+ y = Math.max(0, Math.min(y, ih - h));
+
+ if (this.getX() != x || this.getY() != y) {
+ mxWindow.prototype.setLocation.apply(this, arguments);
+ }
+
+ if (resizable && !this.minimized) {
+ this.setSize(w, h);
+ }
+ };
+
+ var resizeListener = mxUtils.bind(this, function () {
+ var x = dialog.window.getX();
+ var y = dialog.window.getY();
+
+ dialog.window.setLocation(x, y);
+ });
+
+ mxEvent.addListener(window, 'resize', resizeListener);
+
+ dialog.destroy = function () {
+ mxEvent.removeListener(window, 'resize', resizeListener);
+ dialog.window.destroy();
+
+ if (destroy != null) {
+ destroy();
+ }
+ }
+};
+
+/**
+ * Class: ChangeGridColor
+ *
+ * Undoable change to grid color.
+ */
+function ChangeGridColor(ui, color) {
+ this.ui = ui;
+ this.color = color;
+};
+
+/**
+ * Executes selection of a new page.
+ */
+ChangeGridColor.prototype.execute = function () {
+ var temp = this.ui.editor.graph.view.gridColor;
+ this.ui.setGridColor(this.color);
+ this.color = temp;
+};
+
+// Registers codec for ChangePageSetup
+(function () {
+ var codec = new mxObjectCodec(new ChangeGridColor(), ['ui']);
+
+ mxCodecRegistry.register(codec);
+})();
+
+/**
+ * Change types
+ */
+function ChangePageSetup(ui, color, image, format, pageScale) {
+ this.ui = ui;
+ this.color = color;
+ this.previousColor = color;
+ this.image = image;
+ this.previousImage = image;
+ this.format = format;
+ this.previousFormat = format;
+ this.pageScale = pageScale;
+ this.previousPageScale = pageScale;
+
+ // Needed since null are valid values for color and image
+ this.ignoreColor = false;
+ this.ignoreImage = false;
+}
+
+/**
+ * Implementation of the undoable page rename.
+ */
+ChangePageSetup.prototype.execute = function () {
+ var graph = this.ui.editor.graph;
+
+ if (!this.ignoreColor) {
+ this.color = this.previousColor;
+ var tmp = graph.background;
+ this.ui.setBackgroundColor(this.previousColor);
+ this.previousColor = tmp;
+ }
+
+ if (!this.ignoreImage) {
+ this.image = this.previousImage;
+ var tmp = graph.backgroundImage;
+ var img = this.previousImage;
+
+ if (img != null && Graph.isPageLink(img.src)) {
+ img = this.ui.createImageForPageLink(img.src, this.ui.currentPage);
+ }
+
+ this.ui.setBackgroundImage(img);
+ this.previousImage = tmp;
+ }
+
+ if (this.previousFormat != null) {
+ this.format = this.previousFormat;
+ var tmp = graph.pageFormat;
+
+ if (this.previousFormat.width != tmp.width ||
+ this.previousFormat.height != tmp.height) {
+ this.ui.setPageFormat(this.previousFormat);
+ this.previousFormat = tmp;
+ }
+ }
+
+ if (this.foldingEnabled != null && this.foldingEnabled != this.ui.editor.graph.foldingEnabled) {
+ this.ui.setFoldingEnabled(this.foldingEnabled);
+ this.foldingEnabled = !this.foldingEnabled;
+ }
+
+ if (this.previousPageScale != null) {
+ var currentPageScale = this.ui.editor.graph.pageScale;
+
+ if (this.previousPageScale != currentPageScale) {
+ this.ui.setPageScale(this.previousPageScale);
+ this.previousPageScale = currentPageScale;
+ }
+ }
+};
+
+// Registers codec for ChangePageSetup
+(function () {
+ var codec = new mxObjectCodec(new ChangePageSetup(), ['ui', 'previousColor', 'previousImage', 'previousFormat', 'previousPageScale']);
+
+ codec.afterDecode = function (dec, node, obj) {
+ obj.previousColor = obj.color;
+ obj.previousImage = obj.image;
+ obj.previousFormat = obj.format;
+ obj.previousPageScale = obj.pageScale;
+
+ if (obj.foldingEnabled != null) {
+ obj.foldingEnabled = !obj.foldingEnabled;
+ }
+
+ return obj;
+ };
+
+ mxCodecRegistry.register(codec);
+})();
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setBackgroundColor = function (value) {
+ this.editor.graph.background = value;
+ this.editor.graph.view.validateBackground();
+
+ this.fireEvent(new mxEventObject('backgroundColorChanged'));
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setFoldingEnabled = function (value) {
+ this.editor.graph.foldingEnabled = value;
+ this.editor.graph.view.revalidate();
+
+ this.fireEvent(new mxEventObject('foldingEnabledChanged'));
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setPageFormat = function (value, ignorePageVisible) {
+ ignorePageVisible = (ignorePageVisible != null) ? ignorePageVisible : urlParams['sketch'] == '1';
+ this.editor.graph.pageFormat = value;
+
+ if (!ignorePageVisible) {
+ if (!this.editor.graph.pageVisible) {
+ this.actions.get('pageView').funct();
+ }
+ else {
+ this.editor.graph.view.validateBackground();
+ this.editor.graph.sizeDidChange();
+ }
+ }
+
+ this.fireEvent(new mxEventObject('pageFormatChanged'));
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setPageScale = function (value) {
+ this.editor.graph.pageScale = value;
+
+ if (!this.editor.graph.pageVisible) {
+ this.actions.get('pageView').funct();
+ }
+ else {
+ this.editor.graph.view.validateBackground();
+ this.editor.graph.sizeDidChange();
+ }
+
+ this.fireEvent(new mxEventObject('pageScaleChanged'));
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setGridColor = function (value) {
+ this.editor.graph.view.gridColor = value;
+ this.editor.graph.view.validateBackground();
+ this.fireEvent(new mxEventObject('gridColorChanged'));
+};
+
+/**
+ * Updates the states of the given undo/redo items.
+ */
+EditorUi.prototype.addUndoListener = function () {
+ var undoMgr = this.editor.undoManager;
+
+ var undoListener = mxUtils.bind(this, function () {
+ this.updateActionStates();
+ });
+
+ undoMgr.addListener(mxEvent.ADD, undoListener);
+ undoMgr.addListener(mxEvent.UNDO, undoListener);
+ undoMgr.addListener(mxEvent.REDO, undoListener);
+ undoMgr.addListener(mxEvent.CLEAR, undoListener);
+
+ // Overrides cell editor to update action states
+ var cellEditorStartEditing = this.editor.graph.cellEditor.startEditing;
+
+ this.editor.graph.cellEditor.startEditing = function () {
+ cellEditorStartEditing.apply(this, arguments);
+ undoListener();
+ };
+
+ var cellEditorStopEditing = this.editor.graph.cellEditor.stopEditing;
+
+ this.editor.graph.cellEditor.stopEditing = function (cell, trigger) {
+ cellEditorStopEditing.apply(this, arguments);
+ undoListener();
+ };
+
+ // Updates the button states once
+ undoListener();
+};
+
+/**
+* Updates the states of the given toolbar items based on the selection.
+*/
+EditorUi.prototype.updateActionStates = function () {
+ var graph = this.editor.graph;
+ var ss = this.getSelectionState();
+ var unlocked = graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent());
+ var editable = !this.editor.chromeless || this.editor.editable;
+
+ // Updates action states
+ var actions = ['cut', 'copy', 'bold', 'italic', 'underline', 'delete', 'duplicate',
+ 'editStyle', 'editTooltip', 'editLink', 'backgroundColor', 'borderColor',
+ 'edit', 'toFront', 'toBack', 'solid', 'dashed', 'pasteSize',
+ 'dotted', 'fillColor', 'gradientColor', 'shadow', 'fontColor',
+ 'formattedText', 'rounded', 'toggleRounded', 'strokeColor',
+ 'sharp', 'snapToGrid'];
+
+ for (var i = 0; i < actions.length; i++) {
+ this.actions.get(actions[i]).setEnabled(ss.cells.length > 0);
+ }
+
+ this.actions.get('grid').setEnabled(editable);
+ this.actions.get('undo').setEnabled(this.canUndo() && editable);
+ this.actions.get('redo').setEnabled(this.canRedo() && editable);
+ this.actions.get('pasteSize').setEnabled(this.copiedSize != null && ss.vertices.length > 0);
+ this.actions.get('pasteData').setEnabled(this.copiedValue != null && ss.cells.length > 0);
+ this.actions.get('setAsDefaultStyle').setEnabled(graph.getSelectionCount() == 1);
+ this.actions.get('lockUnlock').setEnabled(!graph.isSelectionEmpty());
+ this.actions.get('bringForward').setEnabled(ss.cells.length == 1);
+ this.actions.get('sendBackward').setEnabled(ss.cells.length == 1);
+ this.actions.get('rotation').setEnabled(ss.vertices.length == 1);
+ this.actions.get('wordWrap').setEnabled(ss.vertices.length == 1);
+ this.actions.get('autosize').setEnabled(ss.vertices.length > 0);
+ this.actions.get('copySize').setEnabled(ss.vertices.length == 1);
+ this.actions.get('clearWaypoints').setEnabled(ss.connections);
+ this.actions.get('curved').setEnabled(ss.edges.length > 0);
+ this.actions.get('turn').setEnabled(ss.cells.length > 0);
+ this.actions.get('group').setEnabled(!ss.row && !ss.cell &&
+ (ss.cells.length > 1 || (ss.vertices.length == 1 &&
+ graph.model.getChildCount(ss.cells[0]) == 0 &&
+ !graph.isContainer(ss.vertices[0]))));
+ this.actions.get('ungroup').setEnabled(!ss.row && !ss.cell && !ss.table &&
+ ss.vertices.length > 0 && (graph.isContainer(ss.vertices[0]) ||
+ graph.getModel().getChildCount(ss.vertices[0]) > 0));
+ this.actions.get('removeFromGroup').setEnabled(ss.cells.length == 1 &&
+ graph.getModel().isVertex(graph.getModel().getParent(ss.cells[0])));
+ this.actions.get('collapsible').setEnabled(ss.vertices.length == 1 &&
+ (graph.model.getChildCount(ss.vertices[0]) > 0 ||
+ graph.isContainer(ss.vertices[0])));
+ this.actions.get('exitGroup').setEnabled(graph.view.currentRoot != null);
+ this.actions.get('home').setEnabled(graph.view.currentRoot != null);
+ this.actions.get('enterGroup').setEnabled(ss.cells.length == 1 &&
+ graph.isValidRoot(ss.cells[0]));
+ this.actions.get('copyData').setEnabled(ss.cells.length == 1);
+ this.actions.get('editLink').setEnabled(ss.cells.length == 1);
+ this.actions.get('editStyle').setEnabled(ss.cells.length == 1);
+ this.actions.get('editTooltip').setEnabled(ss.cells.length == 1);
+ this.actions.get('openLink').setEnabled(ss.cells.length == 1 &&
+ graph.getLinkForCell(ss.cells[0]) != null);
+ this.actions.get('guides').setEnabled(graph.isEnabled());
+ this.actions.get('selectVertices').setEnabled(unlocked);
+ this.actions.get('selectEdges').setEnabled(unlocked);
+ this.actions.get('selectAll').setEnabled(unlocked);
+ this.actions.get('selectNone').setEnabled(unlocked);
+
+ var foldable = ss.vertices.length == 1 &&
+ graph.isCellFoldable(ss.vertices[0]);
+ this.actions.get('expand').setEnabled(foldable);
+ this.actions.get('collapse').setEnabled(foldable);
+
+ // Updates menu states
+ this.menus.get('navigation').setEnabled(ss.cells.length > 0 ||
+ graph.view.currentRoot != null);
+ this.menus.get('layout').setEnabled(unlocked);
+ this.menus.get('insert').setEnabled(unlocked);
+ this.menus.get('direction').setEnabled(ss.unlocked &&
+ ss.vertices.length == 1);
+ this.menus.get('distribute').setEnabled(ss.unlocked &&
+ ss.vertices.length > 1);
+ this.menus.get('align').setEnabled(ss.unlocked &&
+ ss.cells.length > 0);
+
+ this.updatePasteActionStates();
+};
+
+EditorUi.prototype.zeroOffset = new mxPoint(0, 0);
+
+EditorUi.prototype.getDiagramContainerOffset = function () {
+ return this.zeroOffset;
+};
+
+/**
+ * Refreshes the viewport.
+ */
+EditorUi.prototype.refresh = function (sizeDidChange) {
+ sizeDidChange = (sizeDidChange != null) ? sizeDidChange : true;
+
+ var w = this.container.clientWidth;
+ var h = this.container.clientHeight;
+
+ if (this.container == document.body) {
+ w = document.body.clientWidth || document.documentElement.clientWidth;
+ h = document.documentElement.clientHeight;
+ }
+
+ // Workaround for bug on iOS see
+ // http://stackoverflow.com/questions/19012135/ios-7-ipad-safari-landscape-innerheight-outerheight-layout-issue
+ // FIXME: Fix if footer visible
+ var off = 0;
+
+ if (mxClient.IS_IOS && !window.navigator.standalone && typeof Menus !== 'undefined') {
+ if (window.innerHeight != document.documentElement.clientHeight) {
+ off = document.documentElement.clientHeight - window.innerHeight;
+ window.scrollTo(0, 0);
+ }
+ }
+
+ var effHsplitPosition = Math.max(0, Math.min(
+ this.hsplitPosition, w - this.splitSize - 40));
+ var tmp = 0;
+
+ if (this.menubar != null) {
+ this.menubarContainer.style.height = this.menubarHeight + 'px';
+ tmp += this.menubarHeight;
+ }
+
+ if (this.toolbar != null) {
+ this.toolbarContainer.style.top = this.menubarHeight + 'px';
+ this.toolbarContainer.style.height = this.toolbarHeight + 'px';
+ tmp += this.toolbarHeight;
+ }
+
+ if (tmp > 0) {
+ tmp += 1;
+ }
+
+ var fw = (this.format != null) ? this.formatWidth : 0;
+ this.sidebarContainer.style.top = tmp + 'px';
+ this.sidebarContainer.style.width = effHsplitPosition + 'px';
+ this.formatContainer.style.top = tmp + 'px';
+ this.formatContainer.style.width = fw + 'px';
+ this.formatContainer.style.display = (this.format != null) ? '' : 'none';
+
+ var diagContOffset = this.getDiagramContainerOffset();
+ var contLeft = (this.hsplit.parentNode != null) ? (effHsplitPosition) : 0;
+ this.footerContainer.style.height = this.footerHeight + 'px';
+ this.hsplit.style.top = this.sidebarContainer.style.top;
+ this.hsplit.style.left = effHsplitPosition + 'px';
+ this.footerContainer.style.display = (this.footerHeight == 0) ? 'none' : '';
+
+ if (this.tabContainer != null) {
+ this.tabContainer.style.left = contLeft + 'px';
+ this.hsplit.style.bottom = this.tabContainer.offsetHeight + 'px';
+ }
+ else {
+ this.hsplit.style.bottom = (this.footerHeight + off) + 'px';
+ }
+
+ if (this.footerHeight > 0) {
+ this.footerContainer.style.bottom = off + 'px';
+ }
+
+ var th = 0;
+
+ if (this.tabContainer != null) {
+ this.tabContainer.style.bottom = (this.footerHeight + off) + 'px';
+ this.tabContainer.style.right = fw + 'px';
+ th = this.tabContainer.clientHeight;
+ this.checkTabScrollerOverflow();
+ }
+
+ this.sidebarContainer.style.bottom = (this.footerHeight + off) + 'px';
+ this.formatContainer.style.bottom = (this.footerHeight + off) + 'px';
+
+ this.diagramContainer.style.left = (contLeft + diagContOffset.x) + 'px';
+ this.diagramContainer.style.top = (tmp + diagContOffset.y) + 'px';
+ this.diagramContainer.style.right = fw + 'px';
+ this.diagramContainer.style.bottom = (this.footerHeight + off + th) + 'px';
+
+ if (sizeDidChange) {
+ this.editor.graph.sizeDidChange();
+ }
+};
+
+/**
+ * Creates the required containers.
+ */
+EditorUi.prototype.createTabContainer = function () {
+ return null;
+};
+
+/**
+ * Creates the required containers.
+ */
+EditorUi.prototype.createDivs = function () {
+ this.menubarContainer = this.createDiv('geMenubarContainer');
+ this.toolbarContainer = this.createDiv('geToolbarContainer');
+ this.sidebarContainer = this.createDiv('geSidebarContainer');
+ this.formatContainer = this.createDiv('geSidebarContainer geFormatContainer');
+ this.diagramContainer = this.createDiv('geDiagramContainer');
+ this.footerContainer = this.createDiv('geFooterContainer');
+ this.hsplit = this.createDiv('geHsplit');
+
+ // Sets static style for containers
+ this.menubarContainer.style.top = '0px';
+ this.menubarContainer.style.left = '0px';
+ this.menubarContainer.style.right = '0px';
+ this.toolbarContainer.style.left = '0px';
+ this.toolbarContainer.style.right = '0px';
+ this.sidebarContainer.style.left = '0px';
+ this.sidebarContainer.style.zIndex = '1';
+ this.formatContainer.style.right = '0px';
+ this.formatContainer.style.zIndex = '1';
+ this.diagramContainer.style.right = ((this.format != null) ? this.formatWidth : 0) + 'px';
+ this.footerContainer.style.left = '0px';
+ this.footerContainer.style.right = '0px';
+ this.footerContainer.style.bottom = '0px';
+ this.footerContainer.style.zIndex = mxPopupMenu.prototype.zIndex - 3;
+ this.hsplit.style.width = this.splitSize + 'px';
+ this.hsplit.style.zIndex = '1';
+
+ if (!this.editor.chromeless) {
+ this.tabContainer = this.createTabContainer();
+ }
+ else {
+ this.diagramContainer.style.border = 'none';
+ }
+};
+
+/**
+ * Hook for sidebar footer container. This implementation returns null.
+ */
+EditorUi.prototype.createSidebarContainer = function () {
+ var div = document.createElement('div');
+ div.className = 'geSidebarContainer';
+
+ return div;
+};
+
+/**
+ * Creates the required containers.
+ */
+EditorUi.prototype.createUi = function () {
+ // Creates menubar
+ this.menubar = (this.editor.chromeless) ? null : this.menus.createMenubar(this.createDiv('geMenubar'));
+
+ if (this.menubar != null) {
+ this.menubarContainer.appendChild(this.menubar.container);
+ }
+
+ // Adds status bar in menubar
+ if (this.menubar != null) {
+ this.statusContainer = this.createStatusContainer();
+
+ // Connects the status bar to the editor status
+ this.editor.addListener('statusChanged', mxUtils.bind(this, function () {
+ this.setStatusText(this.editor.getStatus());
+ }));
+
+ this.setStatusText(this.editor.getStatus());
+ this.menubar.container.appendChild(this.statusContainer);
+
+ // Inserts into DOM
+ this.container.appendChild(this.menubarContainer);
+ }
+
+ // Creates the sidebar
+ this.sidebar = (this.editor.chromeless) ? null : this.createSidebar(this.sidebarContainer);
+
+ if (this.sidebar != null) {
+ this.container.appendChild(this.sidebarContainer);
+ }
+
+ // Creates the format sidebar
+ this.format = (this.editor.chromeless || !this.formatEnabled) ? null : this.createFormat(this.formatContainer);
+
+ if (this.format != null) {
+ this.container.appendChild(this.formatContainer);
+ }
+
+ // Creates the footer
+ var footer = (this.editor.chromeless) ? null : this.createFooter();
+
+ if (footer != null) {
+ this.footerContainer.appendChild(footer);
+ this.container.appendChild(this.footerContainer);
+ }
+
+ this.container.appendChild(this.diagramContainer);
+
+ if (this.container != null && this.tabContainer != null) {
+ this.container.appendChild(this.tabContainer);
+ }
+
+ // Creates toolbar
+ this.toolbar = (this.editor.chromeless) ? null : this.createToolbar(this.createDiv('geToolbar'));
+
+ if (this.toolbar != null) {
+ this.toolbarContainer.appendChild(this.toolbar.container);
+ this.container.appendChild(this.toolbarContainer);
+ }
+
+ // HSplit
+ if (this.sidebar != null) {
+ this.container.appendChild(this.hsplit);
+
+ this.addSplitHandler(this.hsplit, true, 0, mxUtils.bind(this, function (value) {
+ this.hsplitPosition = value;
+ this.refresh();
+ }));
+ }
+};
+
+/**
+ * Creates a new toolbar for the given container.
+ */
+EditorUi.prototype.createStatusContainer = function () {
+ var container = document.createElement('a');
+ container.className = 'geItem geStatus';
+
+ // Handles data-action attribute
+ mxEvent.addListener(container, 'click', mxUtils.bind(this, function (evt) {
+ var elt = mxEvent.getSource(evt);
+
+ if (elt.nodeName != 'A') {
+ var name = elt.getAttribute('data-action');
+
+ // Make generic
+ if (name == 'statusFunction' && this.editor.statusFunction != null) {
+ this.editor.statusFunction();
+ }
+ else if (name != null) {
+ var action = this.actions.get(name);
+
+ if (action != null) {
+ action.funct();
+ }
+ }
+ else {
+ var title = elt.getAttribute('data-title');
+ var msg = elt.getAttribute('data-message');
+
+ if (title != null && msg != null) {
+ this.showError(title, msg);
+ }
+ else {
+ var link = elt.getAttribute('data-link');
+
+ if (link != null) {
+ this.editor.graph.openLink(link);
+ }
+ }
+ }
+
+ mxEvent.consume(evt);
+ }
+ }));
+
+ return container;
+};
+
+/**
+ * Creates a new toolbar for the given container.
+ */
+EditorUi.prototype.setStatusText = function (value) {
+ this.statusContainer.innerHTML = Graph.sanitizeHtml(value);
+
+ // Wraps simple status messages in a div for styling
+ if (this.statusContainer.getElementsByTagName('div').length == 0 &&
+ value != null && value.length > 0) {
+ this.statusContainer.innerText = '';
+ var div = this.createStatusDiv(value);
+ this.statusContainer.appendChild(div);
+ }
+
+ // Handles data-effect attribute
+ var spans = this.statusContainer.querySelectorAll('[data-effect="fade"]');
+
+ if (spans != null) {
+ for (var i = 0; i < spans.length; i++) {
+ (function (temp) {
+ mxUtils.setOpacity(temp, 0);
+ mxUtils.setPrefixedStyle(temp.style, 'transform', 'scaleX(0)');
+ mxUtils.setPrefixedStyle(temp.style, 'transition', 'all 0.2s ease');
+
+ window.setTimeout(mxUtils.bind(this, function () {
+ mxUtils.setOpacity(temp, 100);
+ mxUtils.setPrefixedStyle(temp.style, 'transform', 'scaleX(1)');
+ mxUtils.setPrefixedStyle(temp.style, 'transition', 'all 1s ease');
+
+ window.setTimeout(mxUtils.bind(this, function () {
+ mxUtils.setPrefixedStyle(temp.style, 'transform', 'scaleX(0)');
+ mxUtils.setOpacity(temp, 0);
+
+ window.setTimeout(mxUtils.bind(this, function () {
+ if (temp.parentNode != null) {
+ temp.parentNode.removeChild(temp);
+ }
+ }), 1000);
+ }), Editor.updateStatusInterval / 2);
+ }), 0);
+ })(spans[i]);
+ }
+ }
+};
+
+/**
+ * Creates a new toolbar for the given container.
+ */
+EditorUi.prototype.createStatusDiv = function (value) {
+ var div = document.createElement('div');
+ div.style.textOverflow = 'ellipsis';
+ div.style.display = 'inline-block';
+ div.style.whiteSpace = 'nowrap';
+ div.style.overflow = 'hidden';
+ div.style.minWidth = '0';
+
+ div.setAttribute('title', value);
+ div.innerHTML = Graph.sanitizeHtml(value);
+
+ return div;
+};
+
+/**
+ * Creates a new toolbar for the given container.
+ */
+EditorUi.prototype.createToolbar = function (container) {
+ return new Toolbar(this, container);
+};
+
+/**
+ * Creates a new sidebar for the given container.
+ */
+EditorUi.prototype.createSidebar = function (container) {
+ return new Sidebar(this, container);
+};
+
+/**
+ * Creates a new sidebar for the given container.
+ */
+EditorUi.prototype.createFormat = function (container) {
+ return new Format(this, container);
+};
+
+/**
+ * Creates and returns a new footer.
+ */
+EditorUi.prototype.createFooter = function () {
+ return this.createDiv('geFooter');
+};
+
+/**
+ * Creates the actual toolbar for the toolbar container.
+ */
+EditorUi.prototype.createDiv = function (classname) {
+ var elt = document.createElement('div');
+ elt.className = classname;
+
+ return elt;
+};
+
+/**
+ * Updates the states of the given undo/redo items.
+ */
+EditorUi.prototype.addSplitHandler = function (elt, horizontal, dx, onChange) {
+ var start = null;
+ var initial = null;
+ var ignoreClick = true;
+ var last = null;
+
+ // Disables built-in pan and zoom in IE10 and later
+ if (mxClient.IS_POINTER) {
+ elt.style.touchAction = 'none';
+ }
+
+ var getValue = mxUtils.bind(this, function () {
+ var result = parseInt(((horizontal) ? elt.style.left : elt.style.bottom));
+
+ // Takes into account hidden footer
+ if (!horizontal) {
+ result = result + dx - this.footerHeight;
+ }
+
+ return result;
+ });
+
+ function moveHandler(evt) {
+ if (start != null) {
+ var pt = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
+ onChange(Math.max(0, initial + ((horizontal) ? (pt.x - start.x) : (start.y - pt.y)) - dx));
+ mxEvent.consume(evt);
+
+ if (initial != getValue()) {
+ ignoreClick = true;
+ last = null;
+ }
+ }
+ };
+
+ function dropHandler(evt) {
+ moveHandler(evt);
+ initial = null;
+ start = null;
+ };
+
+ mxEvent.addGestureListeners(elt, function (evt) {
+ start = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
+ initial = getValue();
+ ignoreClick = false;
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(elt, 'click', mxUtils.bind(this, function (evt) {
+ if (!ignoreClick && this.hsplitClickEnabled) {
+ var next = (last != null) ? last - dx : 0;
+ last = getValue();
+ onChange(next);
+ mxEvent.consume(evt);
+ }
+ }));
+
+ mxEvent.addGestureListeners(document, null, moveHandler, dropHandler);
+
+ this.destroyFunctions.push(function () {
+ mxEvent.removeGestureListeners(document, null, moveHandler, dropHandler);
+ });
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.prompt = function (title, defaultValue, fn) {
+ var dlg = new FilenameDialog(this, defaultValue, mxResources.get('apply'), function (newValue) {
+ fn(parseFloat(newValue));
+ }, title);
+
+ this.showDialog(dlg.container, 300, 80, true, true);
+ dlg.init();
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.handleError = function (resp, title, fn, invokeFnOnClose, notFoundMessage) {
+ var e = (resp != null && resp.error != null) ? resp.error : resp;
+
+ if (e != null || title != null) {
+ var msg = mxUtils.htmlEntities(mxResources.get('unknownError'));
+ var btn = mxResources.get('ok');
+ title = (title != null) ? title : mxResources.get('error');
+
+ if (e != null && e.message != null) {
+ msg = mxUtils.htmlEntities(e.message);
+ }
+
+ this.showError(title, msg, btn, fn, null, null, null, null, null,
+ null, null, null, (invokeFnOnClose) ? fn : null);
+ }
+ else if (fn != null) {
+ fn();
+ }
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.showError = function (title, msg, btn, fn, retry, btn2, fn2, btn3, fn3, w, h, hide, onClose) {
+ var dlg = new ErrorDialog(this, title, msg, btn || mxResources.get('ok'),
+ fn, retry, btn2, fn2, hide, btn3, fn3);
+ var lines = Math.ceil((msg != null) ? msg.length / 50 : 1);
+ this.showDialog(dlg.container, w || 340, h || (100 + lines * 20), true, false, onClose);
+ dlg.init();
+};
+
+/**
+ * Displays a print dialog.
+ */
+EditorUi.prototype.showDialog = function (elt, w, h, modal, closable, onClose, noScroll, transparent, onResize, ignoreBgClick) {
+ this.editor.graph.tooltipHandler.resetTimer();
+ this.editor.graph.tooltipHandler.hideTooltip();
+
+ if (this.dialogs == null) {
+ this.dialogs = [];
+ }
+
+ this.dialog = new Dialog(this, elt, w, h, modal, closable, onClose, noScroll, transparent, onResize, ignoreBgClick);
+ this.dialogs.push(this.dialog);
+};
+
+/**
+ * Displays a print dialog.
+ */
+EditorUi.prototype.hideDialog = function (cancel, isEsc, matchContainer) {
+ if (this.dialogs != null && this.dialogs.length > 0) {
+ if (matchContainer != null && matchContainer != this.dialog.container.firstChild) {
+ return;
+ }
+
+ var dlg = this.dialogs.pop();
+
+ if (dlg.close(cancel, isEsc) == false) {
+ //add the dialog back if dialog closing is cancelled
+ this.dialogs.push(dlg);
+ return;
+ }
+
+ this.dialog = (this.dialogs.length > 0) ? this.dialogs[this.dialogs.length - 1] : null;
+ this.editor.fireEvent(new mxEventObject('hideDialog'));
+
+ if (this.dialog == null && this.editor.graph.container != null &&
+ this.editor.graph.container.style.visibility != 'hidden') {
+ window.setTimeout(mxUtils.bind(this, function () {
+ if (this.editor != null && (this.dialogs == null || this.dialogs.length == 0)) {
+ if (this.editor.graph.isEditing() && this.editor.graph.cellEditor.textarea != null) {
+ this.editor.graph.cellEditor.textarea.focus();
+ }
+ else {
+ mxUtils.clearSelection();
+ this.editor.graph.container.focus();
+ }
+ }
+ }), 0);
+ }
+ }
+};
+
+/**
+ * Handles ctrl+enter keystroke to clone cells.
+ */
+EditorUi.prototype.ctrlEnter = function () {
+ var graph = this.editor.graph;
+
+ if (graph.isEnabled()) {
+ try {
+ var cells = graph.getSelectionCells();
+ var lookup = new mxDictionary();
+ var newCells = [];
+
+ for (var i = 0; i < cells.length; i++) {
+ // Clones table rows instead of cells
+ var cell = (graph.isTableCell(cells[i])) ? graph.model.getParent(cells[i]) : cells[i];
+
+ if (cell != null && !lookup.get(cell)) {
+ lookup.put(cell, true);
+ newCells.push(cell);
+ }
+ }
+
+ graph.setSelectionCells(graph.duplicateCells(newCells, false));
+ }
+ catch (e) {
+ this.handleError(e);
+ }
+ }
+};
+
+/**
+ * Display a color dialog.
+ */
+EditorUi.prototype.pickColor = function (color, apply) {
+ var graph = this.editor.graph;
+ var selState = graph.cellEditor.saveSelection();
+ var h = 230 + ((Math.ceil(ColorDialog.prototype.presetColors.length / 12) +
+ Math.ceil(ColorDialog.prototype.defaultColors.length / 12)) * 17);
+
+ var dlg = new ColorDialog(this, mxUtils.rgba2hex(color) || 'none', function (color) {
+ graph.cellEditor.restoreSelection(selState);
+ apply(color);
+ }, function () {
+ graph.cellEditor.restoreSelection(selState);
+ });
+
+ this.showDialog(dlg.container, 230, h, true, false);
+ dlg.init();
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+EditorUi.prototype.openFile = function () {
+ // Closes dialog after open
+ window.openFile = new OpenFile(mxUtils.bind(this, function (cancel) {
+ this.hideDialog(cancel);
+ }));
+
+ // Removes openFile if dialog is closed
+ this.showDialog(new OpenDialog(this).container, (Editor.useLocalStorage) ? 640 : 320,
+ (Editor.useLocalStorage) ? 480 : 220, true, true, function () {
+ window.openFile = null;
+ });
+};
+
+/**
+ * Extracs the graph model from the given HTML data from a data transfer event.
+ */
+EditorUi.prototype.extractGraphModelFromHtml = function (data) {
+ var result = null;
+
+ try {
+ var idx = data.indexOf('<mxGraphModel ');
+
+ if (idx >= 0) {
+ var idx2 = data.lastIndexOf('</mxGraphModel>');
+
+ if (idx2 > idx) {
+ result = data.substring(idx, idx2 + 21).replace(/>/g, '>').
+ replace(/</g, '<').replace(/\\"/g, '"').replace(/\n/g, '');
+ }
+ }
+ }
+ catch (e) {
+ // ignore
+ }
+
+ return result;
+};
+
+/**
+ * Opens the given files in the editor.
+ */
+EditorUi.prototype.readGraphModelFromClipboard = function (fn) {
+ this.readGraphModelFromClipboardWithType(mxUtils.bind(this, function (xml) {
+ if (xml != null) {
+ fn(xml);
+ }
+ else {
+ this.readGraphModelFromClipboardWithType(mxUtils.bind(this, function (xml) {
+ if (xml != null) {
+ var tmp = decodeURIComponent(xml);
+
+ if (this.isCompatibleString(tmp)) {
+ xml = tmp;
+ }
+ }
+
+ fn(xml);
+ }), 'text');
+ }
+ }), 'html');
+};
+
+/**
+ * Opens the given files in the editor.
+ */
+EditorUi.prototype.readGraphModelFromClipboardWithType = function (fn, type) {
+ navigator.clipboard.read().then(mxUtils.bind(this, function (data) {
+ if (data != null && data.length > 0 && type == 'html' &&
+ mxUtils.indexOf(data[0].types, 'text/html') >= 0) {
+ data[0].getType('text/html').then(mxUtils.bind(this, function (blob) {
+ blob.text().then(mxUtils.bind(this, function (value) {
+ try {
+ var elt = this.parseHtmlData(value);
+ var asHtml = elt.getAttribute('data-type') != 'text/plain';
+
+ // KNOWN: Paste from IE11 to other browsers on Windows
+ // seems to paste the contents of index.html
+ var xml = (asHtml) ? elt.innerHTML :
+ mxUtils.trim((elt.innerText == null) ?
+ mxUtils.getTextContent(elt) : elt.innerText);
+
+ // Workaround for junk after XML in VM
+ try {
+ var idx = xml.lastIndexOf('%3E');
+
+ if (idx >= 0 && idx < xml.length - 3) {
+ xml = xml.substring(0, idx + 3);
+ }
+ }
+ catch (e) {
+ // ignore
+ }
+
+ // Checks for embedded XML content
+ try {
+ var spans = elt.getElementsByTagName('span');
+ var tmp = (spans != null && spans.length > 0) ?
+ mxUtils.trim(decodeURIComponent(spans[0].textContent)) :
+ decodeURIComponent(xml);
+
+ if (this.isCompatibleString(tmp)) {
+ xml = tmp;
+ }
+ }
+ catch (e) {
+ // ignore
+ }
+ }
+ catch (e) {
+ // ignore
+ }
+
+ fn(this.isCompatibleString(xml) ? xml : null);
+ }))['catch'](function (data) {
+ fn(null);
+ });
+ }))['catch'](function (data) {
+ fn(null);
+ });
+ }
+ else if (data != null && data.length > 0 && type == 'text' &&
+ mxUtils.indexOf(data[0].types, 'text/plain') >= 0) {
+ data[0].getType('text/plain').then(function (blob) {
+ blob.text().then(function (value) {
+ fn(value);
+ })['catch'](function () {
+ fn(null);
+ });
+ })['catch'](function () {
+ fn(null);
+ });
+ }
+ else {
+ fn(null);
+ }
+ }))['catch'](function (data) {
+ fn(null);
+ });
+};
+
+/**
+ * Parses the given HTML data and returns a DIV.
+ */
+EditorUi.prototype.parseHtmlData = function (data) {
+ var elt = null;
+
+ if (data != null && data.length > 0) {
+ var hasMeta = data.substring(0, 6) == '' : '') +
+ Graph.sanitizeHtml(data);
+ asHtml = true;
+
+ // Workaround for innerText not ignoring style elements in Chrome
+ var styles = elt.getElementsByTagName('style');
+
+ if (styles != null) {
+ while (styles.length > 0) {
+ styles[0].parentNode.removeChild(styles[0]);
+ }
+ }
+
+ // Special case of link pasting from Chrome
+ if (elt.firstChild != null && elt.firstChild.nodeType == mxConstants.NODETYPE_ELEMENT &&
+ elt.firstChild.nextSibling != null && elt.firstChild.nextSibling.nodeType == mxConstants.NODETYPE_ELEMENT &&
+ elt.firstChild.nodeName == 'META' && elt.firstChild.nextSibling.nodeName == 'A' &&
+ elt.firstChild.nextSibling.nextSibling == null) {
+ var temp = (elt.firstChild.nextSibling.innerText == null) ?
+ mxUtils.getTextContent(elt.firstChild.nextSibling) :
+ elt.firstChild.nextSibling.innerText;
+
+ if (temp == elt.firstChild.nextSibling.getAttribute('href')) {
+ mxUtils.setTextContent(elt, temp);
+ asHtml = false;
+ }
+ }
+
+ // Extracts single image source address with meta tag in markup
+ var img = (hasMeta && elt.firstChild != null) ? elt.firstChild.nextSibling : elt.firstChild;
+
+ if (img != null && img.nextSibling == null &&
+ img.nodeType == mxConstants.NODETYPE_ELEMENT &&
+ img.nodeName == 'IMG') {
+ var temp = img.getAttribute('src');
+
+ if (temp != null) {
+ if (Editor.isPngDataUrl(temp)) {
+ var xml = Editor.extractGraphModelFromPng(temp);
+
+ if (xml != null && xml.length > 0) {
+ temp = xml;
+ }
+ }
+
+ mxUtils.setTextContent(elt, temp);
+ asHtml = false;
+ }
+ }
+ else {
+ // Extracts embedded XML or image source address from single PNG image
+ var images = elt.getElementsByTagName('img');
+
+ if (images.length == 1) {
+ var img = images[0];
+ var temp = img.getAttribute('src');
+
+ if (temp != null && img.parentNode == elt && elt.children.length == 1) {
+ if (Editor.isPngDataUrl(temp)) {
+ var xml = Editor.extractGraphModelFromPng(temp);
+
+ if (xml != null && xml.length > 0) {
+ temp = xml;
+ }
+ }
+
+ mxUtils.setTextContent(elt, temp);
+ asHtml = false;
+ }
+ }
+ }
+
+ if (asHtml) {
+ Graph.removePasteFormatting(elt);
+ }
+ }
+
+ if (!asHtml) {
+ elt.setAttribute('data-type', 'text/plain');
+ }
+
+ return elt;
+};
+
+/**
+ * Opens the given files in the editor.
+ */
+EditorUi.prototype.extractGraphModelFromEvent = function (evt) {
+ var result = null;
+ var data = null;
+
+ if (evt != null) {
+ var provider = (evt.dataTransfer != null) ?
+ evt.dataTransfer : evt.clipboardData;
+
+ if (provider != null) {
+ if (document.documentMode == 10 || document.documentMode == 11) {
+ data = provider.getData('Text');
+ }
+ else {
+ data = (mxUtils.indexOf(provider.types, 'text/html') >= 0) ?
+ provider.getData('text/html') : null;
+
+ if (mxUtils.indexOf(provider.types, 'text/plain') >= 0 &&
+ (data == null || data.length == 0)) {
+ data = provider.getData('text/plain');
+ }
+ }
+
+ if (data != null) {
+ data = Graph.zapGremlins(mxUtils.trim(data));
+
+ // Tries parsing as HTML document with embedded XML
+ var xml = this.extractGraphModelFromHtml(data);
+
+ if (xml != null) {
+ data = xml;
+ }
+ }
+ }
+ }
+
+ if (data != null && this.isCompatibleString(data)) {
+ result = data;
+ }
+
+ return result;
+};
+
+/**
+ * Hook for subclassers to return true if event data is a supported format.
+ * This implementation always returns false.
+ */
+EditorUi.prototype.isCompatibleString = function (data) {
+ return false;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+EditorUi.prototype.saveFile = function (forceDialog) {
+ if (!forceDialog && this.editor.filename != null) {
+ this.save(this.editor.getOrCreateFilename());
+ }
+ else {
+ var dlg = new FilenameDialog(this, this.editor.getOrCreateFilename(), mxResources.get('save'), mxUtils.bind(this, function (name) {
+ this.save(name);
+ }), null, mxUtils.bind(this, function (name) {
+ if (name != null && name.length > 0) {
+ return true;
+ }
+
+ mxUtils.confirm(mxResources.get('invalidName'));
+
+ return false;
+ }));
+ this.showDialog(dlg.container, 300, 100, true, true);
+ dlg.init();
+ }
+};
+
+/**
+ * Saves the current graph under the given filename.
+ */
+EditorUi.prototype.save = function (name) {
+ if (name != null) {
+ if (this.editor.graph.isEditing()) {
+ this.editor.graph.stopEditing();
+ }
+
+ var xml = mxUtils.getXml(this.editor.getGraphXml());
+
+ try {
+ if (Editor.useLocalStorage) {
+ if (localStorage.getItem(name) != null &&
+ !mxUtils.confirm(mxResources.get('replaceIt', [name]))) {
+ return;
+ }
+
+ localStorage.setItem(name, xml);
+ this.editor.setStatus(mxUtils.htmlEntities(mxResources.get('saved')) + ' ' + new Date());
+ }
+ else {
+ if (xml.length < MAX_REQUEST_SIZE) {
+ new mxXmlRequest(SAVE_URL, 'filename=' + encodeURIComponent(name) +
+ '&xml=' + encodeURIComponent(xml)).simulate(document, '_blank');
+ }
+ else {
+ mxUtils.alert(mxResources.get('drawingTooLarge'));
+ mxUtils.popup(xml);
+
+ return;
+ }
+ }
+
+ this.editor.setModified(false);
+ this.editor.setFilename(name);
+ this.updateDocumentTitle();
+ }
+ catch (e) {
+ this.editor.setStatus(mxUtils.htmlEntities(mxResources.get('errorSavingFile')));
+ }
+ }
+};
+
+/**
+ * Executes the given array of graph layouts using executeLayout and
+ * calls done after the last layout has finished.
+ */
+EditorUi.prototype.executeLayouts = function (layouts, post) {
+ this.executeLayout(mxUtils.bind(this, function () {
+ var layout = new mxCompositeLayout(this.editor.graph, layouts);
+ var cells = this.editor.graph.getSelectionCells();
+
+ layout.execute(this.editor.graph.getDefaultParent(),
+ cells.length == 0 ? null : cells);
+ }), true, post);
+};
+
+/**
+ * Executes the given layout.
+ */
+EditorUi.prototype.executeLayout = function (exec, animate, post) {
+ var graph = this.editor.graph;
+ graph.getModel().beginUpdate();
+ try {
+ exec();
+ }
+ catch (e) {
+ throw e;
+ }
+ finally {
+ // Animates the changes in the graph model
+ if (this.allowAnimation && animate && graph.isEnabled()) {
+ // New API for animating graph layout results asynchronously
+ var morph = new mxMorphing(graph);
+ morph.addListener(mxEvent.DONE, mxUtils.bind(this, function () {
+ graph.getModel().endUpdate();
+
+ if (post != null) {
+ post();
+ }
+ }));
+
+ morph.startAnimation();
+ }
+ else {
+ graph.getModel().endUpdate();
+
+ if (post != null) {
+ post();
+ }
+ }
+ }
+};
+
+/**
+ * Hides the current menu.
+ */
+EditorUi.prototype.showImageDialog = function (title, value, fn, ignoreExisting) {
+ var cellEditor = this.editor.graph.cellEditor;
+ var selState = cellEditor.saveSelection();
+ var newValue = mxUtils.prompt(title, value);
+ cellEditor.restoreSelection(selState);
+
+ if (newValue != null && newValue.length > 0) {
+ var img = new Image();
+
+ img.onload = function () {
+ fn(newValue, img.width, img.height);
+ };
+ img.onerror = function () {
+ fn(null);
+ mxUtils.alert(mxResources.get('fileNotFound'));
+ };
+
+ img.src = newValue;
+ }
+ else {
+ fn(null);
+ }
+};
+
+/**
+ * Hides the current menu.
+ */
+EditorUi.prototype.showLinkDialog = function (value, btnLabel, fn) {
+ var dlg = new LinkDialog(this, value, btnLabel, fn);
+ this.showDialog(dlg.container, 420, 90, true, true);
+ dlg.init();
+};
+
+/**
+ * Hides the current menu.
+ */
+EditorUi.prototype.showDataDialog = function (cell) {
+ if (cell != null && typeof window.EditDataDialog !== 'undefined') {
+ var dlg = new EditDataDialog(this, cell);
+ this.showDialog(dlg.container, 480, 420, true, false, null, false);
+ dlg.init();
+ }
+};
+
+/**
+ * Hides the current menu.
+ */
+EditorUi.prototype.showBackgroundImageDialog = function (apply, img) {
+ apply = (apply != null) ? apply : mxUtils.bind(this, function (image) {
+ var change = new ChangePageSetup(this, null, image);
+ change.ignoreColor = true;
+
+ this.editor.graph.model.execute(change);
+ });
+
+ var newValue = mxUtils.prompt(mxResources.get('backgroundImage'), (img != null) ? img.src : '');
+
+ if (newValue != null && newValue.length > 0) {
+ var img = new Image();
+
+ img.onload = function () {
+ apply(new mxImage(newValue, img.width, img.height), false);
+ };
+ img.onerror = function () {
+ apply(null, true);
+ mxUtils.alert(mxResources.get('fileNotFound'));
+ };
+
+ img.src = newValue;
+ }
+ else {
+ apply(null);
+ }
+};
+
+/**
+ * Loads the stylesheet for this graph.
+ */
+EditorUi.prototype.setBackgroundImage = function (image) {
+ this.editor.graph.setBackgroundImage(image);
+ this.editor.graph.view.validateBackgroundImage();
+
+ this.fireEvent(new mxEventObject('backgroundImageChanged'));
+};
+
+/**
+ * Creates the keyboard event handler for the current graph and history.
+ */
+EditorUi.prototype.confirm = function (msg, okFn, cancelFn) {
+ if (mxUtils.confirm(msg)) {
+ if (okFn != null) {
+ okFn();
+ }
+ }
+ else if (cancelFn != null) {
+ cancelFn();
+ }
+};
+
+/**
+ * Creates the keyboard event handler for the current graph and history.
+ */
+EditorUi.prototype.createOutline = function (wnd) {
+ var outline = new mxOutline(this.editor.graph);
+
+ mxEvent.addListener(window, 'resize', function () {
+ outline.update(false);
+ });
+
+ return outline;
+};
+
+// Alt+Shift+Keycode mapping to action
+EditorUi.prototype.altShiftActions = {
+ 65: 'connectionArrows', // Alt+Shift+A
+ 82: 'clearWaypoints', // Alt+Shift+R
+ 76: 'editLink', // Alt+Shift+L
+ 79: 'connectionPoints', // Alt+Shift+O
+ 81: 'editConnectionPoints', // Alt+Shift+Q
+ 84: 'editTooltip', // Alt+Shift+T
+ 86: 'pasteSize', // Alt+Shift+V
+ 70: 'copySize', // Alt+Shift+F
+ 66: 'copyData', // Alt+Shift+B
+ 69: 'pasteData' // Alt+Shift+E
+};
+
+/**
+ * Creates the keyboard event handler for the current graph and history.
+ */
+EditorUi.prototype.createKeyHandler = function (editor) {
+ var editorUi = this;
+ var graph = this.editor.graph;
+ var keyHandler = new mxKeyHandler(graph);
+
+ var isEventIgnored = keyHandler.isEventIgnored;
+ keyHandler.isEventIgnored = function (evt) {
+ // Handles undo/redo/ctrl+./,/u via action and allows ctrl+b/i
+ // only if editing value is HTML (except for FF and Safari)
+ // 66, 73 are keycodes for editing actions like bold, italic
+ return !(mxEvent.isShiftDown(evt) && evt.keyCode == 9) &&
+ ((!this.isControlDown(evt) || mxEvent.isShiftDown(evt) ||
+ (evt.keyCode != 90 && evt.keyCode != 89 && evt.keyCode != 188 &&
+ evt.keyCode != 190 && evt.keyCode != 85)) && ((evt.keyCode != 66 && evt.keyCode != 73) ||
+ !this.isControlDown(evt) || (this.graph.cellEditor.isContentEditing() &&
+ !mxClient.IS_FF && !mxClient.IS_SF)) &&
+ ((evt.keyCode != 109 && evt.keyCode != 107) ||
+ (!this.isControlDown(evt) && !mxEvent.isShiftDown(evt)) ||
+ (!this.graph.cellEditor.isContentEditing() &&
+ !mxClient.IS_FF && !mxClient.IS_SF)) &&
+ isEventIgnored.apply(this, arguments));
+ };
+
+ // Ignores graph enabled state but not chromeless state
+ keyHandler.isEnabledForEvent = function (evt) {
+ return (!mxEvent.isConsumed(evt) && this.isGraphEvent(evt) && this.isEnabled() &&
+ (editorUi.dialogs == null || editorUi.dialogs.length == 0));
+ };
+
+ // Routes command-key to control-key on Mac
+ keyHandler.isControlDown = function (evt) {
+ return mxEvent.isControlDown(evt) || (mxClient.IS_MAC && evt.metaKey);
+ };
+
+ var thread = null;
+
+ // Helper function to move cells with the cursor keys
+ function nudge(keyCode, stepSize, resize) {
+ if (!graph.isSelectionEmpty() && graph.isEnabled()) {
+ stepSize = (stepSize != null) ? stepSize : 1;
+
+ var cells = graph.getCompositeParents(graph.getSelectionCells());
+ var cell = (cells.length > 0) ? cells[0] : null;
+
+ if (cell != null) {
+ if (resize) {
+ // Resizes all selected vertices
+ graph.getModel().beginUpdate();
+ try {
+ for (var i = 0; i < cells.length; i++) {
+ if (graph.getModel().isVertex(cells[i]) && graph.isCellResizable(cells[i])) {
+ var geo = graph.getCellGeometry(cells[i]);
+
+ if (geo != null) {
+ geo = geo.clone();
+
+ if (keyCode == 37) {
+ geo.width = Math.max(0, geo.width - stepSize);
+ }
+ else if (keyCode == 38) {
+ geo.height = Math.max(0, geo.height - stepSize);
+ }
+ else if (keyCode == 39) {
+ geo.width += stepSize;
+ }
+ else if (keyCode == 40) {
+ geo.height += stepSize;
+ }
+
+ graph.getModel().setGeometry(cells[i], geo);
+ }
+ }
+ }
+ }
+ finally {
+ graph.getModel().endUpdate();
+ }
+ }
+ else {
+ // Moves vertices up/down in a stack layout
+ var parent = graph.model.getParent(cell);
+ var scale = graph.getView().scale;
+ var layout = null;
+
+ if (graph.getSelectionCount() == 1 && graph.model.isVertex(cell) &&
+ graph.layoutManager != null && !graph.isCellLocked(cell)) {
+ layout = graph.layoutManager.getLayout(parent);
+ }
+
+ if (layout != null && layout.constructor == mxStackLayout) {
+ var index = parent.getIndex(cell);
+
+ if (keyCode == 37 || keyCode == 38) {
+ graph.model.add(parent, cell, Math.max(0, index - 1));
+ }
+ else if (keyCode == 39 || keyCode == 40) {
+ graph.model.add(parent, cell, Math.min(graph.model.getChildCount(parent), index + 1));
+ }
+ }
+ else {
+ var handler = graph.graphHandler;
+
+ if (handler != null) {
+ if (handler.first == null) {
+ handler.start(cell, 0, 0, graph.getMovableCells(cells));
+ }
+
+ if (handler.first != null) {
+ var dx = 0;
+ var dy = 0;
+
+ if (keyCode == 37) {
+ dx = -stepSize;
+ }
+ else if (keyCode == 38) {
+ dy = -stepSize;
+ }
+ else if (keyCode == 39) {
+ dx = stepSize;
+ }
+ else if (keyCode == 40) {
+ dy = stepSize;
+ }
+
+ handler.currentDx += dx * scale;
+ handler.currentDy += dy * scale;
+ handler.checkPreview();
+ handler.updatePreview();
+ }
+
+ // Groups move steps in undoable change
+ if (thread != null) {
+ window.clearTimeout(thread);
+ }
+
+ thread = window.setTimeout(function () {
+ if (handler.first != null) {
+ var dx = handler.roundLength(handler.currentDx / scale);
+ var dy = handler.roundLength(handler.currentDy / scale);
+ handler.moveCells(handler.cells, dx, dy);
+ handler.reset();
+ }
+ }, 400);
+ }
+ }
+ }
+ }
+ }
+ };
+
+ // Overridden to handle special alt+shift+cursor keyboard shortcuts
+ var directions = {
+ 37: mxConstants.DIRECTION_WEST, 38: mxConstants.DIRECTION_NORTH,
+ 39: mxConstants.DIRECTION_EAST, 40: mxConstants.DIRECTION_SOUTH
+ };
+ var keyHandlerGetFunction = keyHandler.getFunction;
+
+ mxKeyHandler.prototype.getFunction = function (evt) {
+ if (graph.isEnabled()) {
+ // TODO: Add alt modifier state in core API, here are some specific cases
+ if (mxEvent.isShiftDown(evt) && mxEvent.isAltDown(evt)) {
+ var action = editorUi.actions.get(editorUi.altShiftActions[evt.keyCode]);
+
+ if (action != null) {
+ return action.funct;
+ }
+ }
+
+ if (directions[evt.keyCode] != null && !graph.isSelectionEmpty()) {
+ // On macOS, Control+Cursor is used by Expose so allow for Alt+Control to resize
+ if (!this.isControlDown(evt) && mxEvent.isShiftDown(evt) && mxEvent.isAltDown(evt)) {
+ if (graph.model.isVertex(graph.getSelectionCell())) {
+ return function () {
+ var cells = graph.connectVertex(graph.getSelectionCell(), directions[evt.keyCode],
+ graph.defaultEdgeLength, evt, true);
+
+ if (cells != null && cells.length > 0) {
+ if (cells.length == 1 && graph.model.isEdge(cells[0])) {
+ graph.setSelectionCell(graph.model.getTerminal(cells[0], false));
+ }
+ else {
+ graph.setSelectionCell(cells[cells.length - 1]);
+ }
+
+ graph.scrollCellToVisible(graph.getSelectionCell());
+
+ if (editorUi.hoverIcons != null) {
+ editorUi.hoverIcons.update(graph.view.getState(graph.getSelectionCell()));
+ }
+ }
+ };
+ }
+ }
+ else {
+ // Avoids consuming event if no vertex is selected by returning null below
+ // Cursor keys move and resize (ctrl) cells
+ if (this.isControlDown(evt)) {
+ return function () {
+ nudge(evt.keyCode, (mxEvent.isShiftDown(evt)) ? graph.gridSize : null, true);
+ };
+ }
+ else {
+ return function () {
+ nudge(evt.keyCode, (mxEvent.isShiftDown(evt)) ? graph.gridSize : null);
+ };
+ }
+ }
+ }
+ }
+
+ return keyHandlerGetFunction.apply(this, arguments);
+ };
+
+ // Binds keystrokes to actions
+ keyHandler.bindAction = mxUtils.bind(this, function (code, control, key, shift) {
+ var action = this.actions.get(key);
+
+ if (action != null) {
+ var f = function () {
+ if (action.isEnabled()) {
+ action.funct.apply(this, arguments);
+ }
+ };
+
+ if (control) {
+ if (shift) {
+ keyHandler.bindControlShiftKey(code, f);
+ }
+ else {
+ keyHandler.bindControlKey(code, f);
+ }
+ }
+ else {
+ if (shift) {
+ keyHandler.bindShiftKey(code, f);
+ }
+ else {
+ keyHandler.bindKey(code, f);
+ }
+ }
+ }
+ });
+
+ var ui = this;
+ var keyHandlerEscape = keyHandler.escape;
+ keyHandler.escape = function (evt) {
+ keyHandlerEscape.apply(this, arguments);
+ };
+
+ // Ignores enter keystroke. Remove this line if you want the
+ // enter keystroke to stop editing. N, W, T are reserved.
+ keyHandler.enter = function () { };
+
+ keyHandler.bindControlShiftKey(36, function () { graph.exitGroup(); }); // Ctrl+Shift+Home
+ keyHandler.bindControlShiftKey(35, function () { graph.enterGroup(); }); // Ctrl+Shift+End
+ keyHandler.bindShiftKey(36, function () { graph.home(); }); // Ctrl+Shift+Home
+ keyHandler.bindKey(35, function () { graph.refresh(); }); // End
+ keyHandler.bindAction(107, true, 'zoomIn'); // Ctrl+Plus
+ keyHandler.bindAction(109, true, 'zoomOut'); // Ctrl+Minus
+ keyHandler.bindAction(80, true, 'print'); // Ctrl+P
+
+ if (!this.editor.chromeless || this.editor.editable) {
+ keyHandler.bindAction(79, true, 'outline', true); // Ctrl+Shift+O
+ keyHandler.bindControlKey(36, function () { if (graph.isEnabled()) { graph.foldCells(true); } }); // Ctrl+Home
+ keyHandler.bindControlKey(35, function () { if (graph.isEnabled()) { graph.foldCells(false); } }); // Ctrl+End
+ keyHandler.bindControlKey(13, function () { ui.ctrlEnter(); }); // Ctrl+Enter
+ keyHandler.bindAction(8, false, 'delete'); // Backspace
+ keyHandler.bindAction(8, true, 'deleteAll'); // Ctrl+Backspace
+ keyHandler.bindAction(8, false, 'deleteLabels', true); // Shift+Backspace
+ keyHandler.bindAction(46, false, 'delete'); // Delete
+ keyHandler.bindAction(46, true, 'deleteAll'); // Ctrl+Delete
+ keyHandler.bindAction(46, false, 'deleteLabels', true); // Shift+Delete
+ keyHandler.bindAction(36, false, 'resetView'); // Home
+ keyHandler.bindAction(72, true, 'fitWindow', true); // Ctrl+Shift+H
+ keyHandler.bindAction(74, true, 'fitPage'); // Ctrl+J
+ keyHandler.bindAction(74, true, 'fitTwoPages', true); // Ctrl+Shift+J
+ keyHandler.bindAction(48, true, 'customZoom'); // Ctrl+0
+ keyHandler.bindAction(82, true, 'turn'); // Ctrl+R
+ keyHandler.bindAction(82, true, 'clearDefaultStyle', true); // Ctrl+Shift+R
+ keyHandler.bindAction(83, true, 'save'); // Ctrl+S
+ keyHandler.bindAction(83, true, 'saveAs', true); // Ctrl+Shift+S
+ keyHandler.bindAction(65, true, 'selectAll'); // Ctrl+A
+ keyHandler.bindAction(65, true, 'selectNone', true); // Ctrl+A
+ keyHandler.bindAction(73, true, 'selectVertices', true); // Ctrl+Shift+I
+ keyHandler.bindAction(69, true, 'selectEdges', true); // Ctrl+Shift+E
+ keyHandler.bindAction(69, true, 'editStyle'); // Ctrl+E
+ keyHandler.bindAction(66, true, 'bold'); // Ctrl+B
+ keyHandler.bindAction(66, true, 'toBack', true); // Ctrl+Shift+B
+ keyHandler.bindAction(70, true, 'toFront', true); // Ctrl+Shift+F
+ keyHandler.bindAction(68, true, 'duplicate'); // Ctrl+D
+ keyHandler.bindAction(68, true, 'setAsDefaultStyle', true); // Ctrl+Shift+D
+ keyHandler.bindAction(90, true, 'undo'); // Ctrl+Z
+ keyHandler.bindAction(89, true, 'autosize', true); // Ctrl+Shift+Y
+ keyHandler.bindAction(88, true, 'cut'); // Ctrl+X
+ keyHandler.bindAction(67, true, 'copy'); // Ctrl+C
+ keyHandler.bindAction(86, true, 'paste'); // Ctrl+V
+ keyHandler.bindAction(71, true, 'group'); // Ctrl+G
+ keyHandler.bindAction(77, true, 'editData'); // Ctrl+M
+ keyHandler.bindAction(71, true, 'grid', true); // Ctrl+Shift+G
+ keyHandler.bindAction(73, true, 'italic'); // Ctrl+I
+ keyHandler.bindAction(76, true, 'lockUnlock'); // Ctrl+L
+ keyHandler.bindAction(76, true, 'layers', true); // Ctrl+Shift+L
+ keyHandler.bindAction(80, true, 'format', true); // Ctrl+Shift+P
+ keyHandler.bindAction(85, true, 'underline'); // Ctrl+U
+ keyHandler.bindAction(85, true, 'ungroup', true); // Ctrl+Shift+U
+ keyHandler.bindAction(109, true, 'decreaseFontSize', true); // Ctrl+Shift+Minus
+ keyHandler.bindAction(107, true, 'increaseFontSize', true); // Ctrl+Shift+Plus
+ keyHandler.bindAction(219, true, 'decreaseFontSize', true); // Ctrl+{
+ keyHandler.bindAction(221, true, 'increaseFontSize', true); // Ctrl+}
+ keyHandler.bindAction(190, true, 'superscript'); // Ctrl+.
+ keyHandler.bindAction(188, true, 'subscript'); // Ctrl+,
+ keyHandler.bindAction(13, false, 'keyPressEnter'); // Enter
+ keyHandler.bindKey(113, function () { if (graph.isEnabled()) { graph.startEditingAtCell(); } }); // F2
+ }
+
+ if (!mxClient.IS_WIN) {
+ keyHandler.bindAction(90, true, 'redo', true); // Ctrl+Shift+Z
+ }
+ else {
+ keyHandler.bindAction(89, true, 'redo'); // Ctrl+Y
+ }
+
+ return keyHandler;
+};
+
+/**
+ * Creates the keyboard event handler for the current graph and history.
+ */
+EditorUi.prototype.destroy = function () {
+ var graph = this.editor.graph;
+
+ if (graph != null && this.selectionStateListener != null) {
+ graph.getSelectionModel().removeListener(mxEvent.CHANGE, this.selectionStateListener);
+ graph.getModel().removeListener(mxEvent.CHANGE, this.selectionStateListener);
+ graph.removeListener(mxEvent.EDITING_STARTED, this.selectionStateListener);
+ graph.removeListener(mxEvent.EDITING_STOPPED, this.selectionStateListener);
+ graph.getView().removeListener('unitChanged', this.selectionStateListener);
+ this.selectionStateListener = null;
+ }
+
+ if (this.editor != null) {
+ this.editor.destroy();
+ this.editor = null;
+ }
+
+ if (this.menubar != null) {
+ this.menubar.destroy();
+ this.menubar = null;
+ }
+
+ if (this.toolbar != null) {
+ this.toolbar.destroy();
+ this.toolbar = null;
+ }
+
+ if (this.sidebar != null) {
+ this.sidebar.destroy();
+ this.sidebar = null;
+ }
+
+ if (this.keyHandler != null) {
+ this.keyHandler.destroy();
+ this.keyHandler = null;
+ }
+
+ if (this.keydownHandler != null) {
+ mxEvent.removeListener(document, 'keydown', this.keydownHandler);
+ this.keydownHandler = null;
+ }
+
+ if (this.keyupHandler != null) {
+ mxEvent.removeListener(document, 'keyup', this.keyupHandler);
+ this.keyupHandler = null;
+ }
+
+ if (this.resizeHandler != null) {
+ mxEvent.removeListener(window, 'resize', this.resizeHandler);
+ this.resizeHandler = null;
+ }
+
+ if (this.gestureHandler != null) {
+ mxEvent.removeGestureListeners(document, this.gestureHandler);
+ this.gestureHandler = null;
+ }
+
+ if (this.orientationChangeHandler != null) {
+ mxEvent.removeListener(window, 'orientationchange', this.orientationChangeHandler);
+ this.orientationChangeHandler = null;
+ }
+
+ if (this.scrollHandler != null) {
+ mxEvent.removeListener(window, 'scroll', this.scrollHandler);
+ this.scrollHandler = null;
+ }
+
+ if (this.destroyFunctions != null) {
+ for (var i = 0; i < this.destroyFunctions.length; i++) {
+ this.destroyFunctions[i]();
+ }
+
+ this.destroyFunctions = null;
+ }
+
+ var c = [this.menubarContainer, this.toolbarContainer, this.sidebarContainer,
+ this.formatContainer, this.diagramContainer, this.footerContainer,
+ this.chromelessToolbar, this.hsplit, this.layersDialog];
+
+ for (var i = 0; i < c.length; i++) {
+ if (c[i] != null && c[i].parentNode != null) {
+ c[i].parentNode.removeChild(c[i]);
+ }
+ }
+};
+
+EditorUi.prototype.exportImage = function (scale, transparentBackground, ignoreSelection, addShadow, editable, border, noCrop, format, exportHandler) {
+ format = (format != null) ? format : 'png';
+
+ var selectionEmpty = this.editor.graph.isSelectionEmpty();
+ ignoreSelection = (ignoreSelection != null) ? ignoreSelection : selectionEmpty;
+
+ // Caches images
+ if (this.thumbImageCache == null) {
+ this.thumbImageCache = new Object();
+ }
+
+ try {
+ this.exportToCanvas(mxUtils.bind(this, function (canvas) {
+
+ try {
+ this.saveCanvas(canvas, (editable) ? this.getFileData(true, null,
+ null, null, ignoreSelection) : null, format, exportHandler);
+ }
+ catch (e) {
+ this.handleError(e);
+ }
+ }), null, this.thumbImageCache, null, mxUtils.bind(this, function (e) {
+ this.handleError(e);
+ }), null, ignoreSelection, scale || 1, transparentBackground,
+ addShadow, null, null, border, noCrop);
+ }
+ catch (e) {
+ this.handleError(e);
+ }
+};
+
+EditorUi.prototype.handleError = function (error) {
+ throw error;
+}
+
+/**
+ *
+ */
+EditorUi.prototype.exportToCanvas = function (callback, width, imageCache, background, error, limitHeight,
+ ignoreSelection, scale, transparentBackground, addShadow, converter, graph, border, noCrop) {
+ limitHeight = (limitHeight != null) ? limitHeight : true;
+ ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
+ graph = (graph != null) ? graph : this.editor.graph;
+ border = (border != null) ? border : 0;
+
+ this.convertImages(graph.getSvg(null, null, null),
+ mxUtils.bind(this, function (svgRoot) {
+ var img = new Image();
+
+
+ img.onload = mxUtils.bind(this, function () {
+ try {
+ var canvas = document.createElement('canvas');
+ var w = parseInt(svgRoot.getAttribute('width'));
+ var h = parseInt(svgRoot.getAttribute('height'));
+ scale = (scale != null) ? scale : 1;
+
+ if (width != null) {
+ scale = (!limitHeight) ? width / w : Math.min(1, Math.min((width * 3) / (h * 4), width / w));
+ }
+
+ w = Math.ceil(scale * w) + 2 * border;
+ h = Math.ceil(scale * h) + 2 * border;
+
+ canvas.setAttribute('width', w);
+ canvas.setAttribute('height', h);
+ var ctx = canvas.getContext('2d');
+
+ ctx.scale(scale, scale);
+
+ // Workaround for broken data URI images in Safari on first export
+ if (mxClient.IS_SF) {
+ window.setTimeout(function () {
+ ctx.drawImage(img, border / scale, border / scale);
+ callback(canvas);
+ }, 0);
+ }
+ else {
+ ctx.drawImage(img, border / scale, border / scale);
+ callback(canvas);
+ }
+ }
+ catch (e) {
+ this.handleError(e);
+ }
+ });
+
+ img.onerror = function (e) {
+ this.handleError(e);
+ };
+
+ try {
+ if (addShadow) {
+ this.editor.graph.addSvgShadow(svgRoot);
+ }
+
+ var done = mxUtils.bind(this, function () {
+ if (this.editor.resolvedFontCss != null) {
+ var st = document.createElement('style');
+ st.setAttribute('type', 'text/css');
+ st.innerHTML = this.editor.resolvedFontCss;
+
+ // Must be in defs section for FF to work
+ var defs = svgRoot.getElementsByTagName('defs');
+ defs[0].appendChild(st);
+ }
+ img.src = this.createSvgDataUri(mxUtils.getXml(svgRoot));
+ });
+
+ this.loadFonts(done);
+ }
+ catch (e) {
+ //console.log('src', e, img.src);
+ this.handleError(e);
+ }
+ }), imageCache, converter);
+};
+
+/**
+ * Converts all images in the SVG output to data URIs for immediate rendering
+ */
+EditorUi.prototype.convertImages = function (svgRoot, callback, imageCache, converter) {
+ // Converts images to data URLs for immediate painting
+ if (converter == null) {
+ converter = this.createImageUrlConverter();
+ }
+
+ // Barrier for asynchronous image loading
+ var counter = 0;
+
+ function inc() {
+ counter++;
+ };
+
+ function dec() {
+ counter--;
+
+ if (counter == 0) {
+ callback(svgRoot);
+ }
+ };
+
+ var cache = imageCache || new Object();
+
+ var convertImages = mxUtils.bind(this, function (tagName, srcAttr) {
+ var images = svgRoot.getElementsByTagName(tagName);
+
+ for (var i = 0; i < images.length; i++) {
+ (mxUtils.bind(this, function (img) {
+ var src = converter.convert(img.getAttribute(srcAttr));
+
+ // Data URIs are pass-through
+ if (src != null && src.substring(0, 5) != 'data:') {
+ var tmp = cache[src];
+
+ if (tmp == null) {
+ inc();
+
+ this.convertImageToDataUri(src, function (uri) {
+ if (uri != null) {
+ cache[src] = uri;
+ img.setAttribute(srcAttr, uri);
+ }
+
+ dec();
+ });
+ }
+ else {
+ img.setAttribute(srcAttr, tmp);
+ }
+ }
+ else if (src != null) {
+ img.setAttribute(srcAttr, src);
+ }
+ }))(images[i]);
+ }
+ });
+
+ // Converts all known image tags in output
+ // LATER: Add support for images in CSS
+ convertImages('image', 'xlink:href');
+ convertImages('img', 'src');
+
+ // All from cache or no images
+ if (counter == 0) {
+ callback(svgRoot);
+ }
+};
+
+/**
+ * Converts all images in the SVG output to data URIs for immediate rendering
+ */
+EditorUi.prototype.createImageUrlConverter = function () {
+ var converter = new mxUrlConverter();
+ converter.updateBaseUrl();
+
+ // Extends convert to avoid CORS using an image proxy server where needed
+ var convert = converter.convert;
+ var self = this;
+
+ converter.convert = function (src) {
+ // if (src != null)
+ // {
+ // var remote = src.substring(0, 7) == 'http://' || src.substring(0, 8) == 'https://';
+
+ // if (remote && !navigator.onLine)
+ // {
+ // src = self.svgBrokenImage.src;
+ // }
+ // else if (remote && src.substring(0, converter.baseUrl.length) != converter.baseUrl &&
+ // (!self.crossOriginImages || !self.isCorsEnabledForUrl(src)))
+ // {
+ // src = PROXY_URL + '?url=' + encodeURIComponent(src);
+ // }
+ // else if (src.substring(0, 19) != 'chrome-extension://')
+ // {
+ // src = convert.apply(this, arguments);
+ // }
+ // }
+
+ return src;
+ };
+
+ return converter;
+};
+
+/**
+ * For the fontCSS to be applied when rendering images on canvas, the actual
+ * font data must be made available via a data URI encoding of the file.
+ */
+EditorUi.prototype.loadFonts = function (then) {
+ if (this.editor.fontCss != null && this.editor.resolvedFontCss == null) {
+ var parts = this.editor.fontCss.split('url(');
+ var waiting = 0;
+ var fonts = {};
+
+ // Strips leading and trailing quotes and spaces
+ function trimString(str) {
+ return str.replace(new RegExp("^[\\s\"']+", "g"), "").replace(new RegExp("[\\s\"']+$", "g"), "");
+ };
+
+ var finish = mxUtils.bind(this, function () {
+ if (waiting == 0) {
+ // Constructs string
+ var result = [parts[0]];
+
+ for (var j = 1; j < parts.length; j++) {
+ var idx = parts[j].indexOf(')');
+ result.push('url("');
+ result.push(fonts[trimString(parts[j].substring(0, idx))]);
+ result.push('"' + parts[j].substring(idx));
+ }
+
+ this.editor.resolvedFontCss = result.join('');
+ then();
+ }
+ });
+
+ if (parts.length > 0) {
+ for (var i = 1; i < parts.length; i++) {
+ var idx = parts[i].indexOf(')');
+ var format = null;
+
+ // Checks if there is a format directive
+ var fmtIdx = parts[i].indexOf('format(', idx);
+
+ if (fmtIdx > 0) {
+ format = trimString(parts[i].substring(fmtIdx + 7, parts[i].indexOf(')', fmtIdx)));
+ }
+
+ (mxUtils.bind(this, function (url) {
+ if (fonts[url] == null) {
+ // Mark font es being fetched and fetch it
+ fonts[url] = url;
+ waiting++;
+
+ var mime = 'application/x-font-ttf';
+
+ // See https://stackoverflow.com/questions/2871655/proper-mime-type-for-fonts
+ if (format == 'svg' || /(\.svg)($|\?)/i.test(url)) {
+ mime = 'image/svg+xml';
+ }
+ else if (format == 'otf' || format == 'embedded-opentype' || /(\.otf)($|\?)/i.test(url)) {
+ mime = 'application/x-font-opentype';
+ }
+ else if (format == 'woff' || /(\.woff)($|\?)/i.test(url)) {
+ mime = 'application/font-woff';
+ }
+ else if (format == 'woff2' || /(\.woff2)($|\?)/i.test(url)) {
+ mime = 'application/font-woff2';
+ }
+ else if (format == 'eot' || /(\.eot)($|\?)/i.test(url)) {
+ mime = 'application/vnd.ms-fontobject';
+ }
+ else if (format == 'sfnt' || /(\.sfnt)($|\?)/i.test(url)) {
+ mime = 'application/font-sfnt';
+ }
+
+ var realUrl = url;
+
+ if ((/^https?:\/\//.test(realUrl)) && !this.isCorsEnabledForUrl(realUrl)) {
+ realUrl = PROXY_URL + '?url=' + encodeURIComponent(url);
+ }
+
+ // LATER: Remove cache-control header
+ this.loadUrl(realUrl, mxUtils.bind(this, function (uri) {
+ fonts[url] = uri;
+ waiting--;
+ finish();
+ }), mxUtils.bind(this, function (err) {
+ // LATER: handle error
+ waiting--;
+ finish();
+ }), true, null, 'data:' + mime + ';charset=utf-8;base64,');
+ }
+ }))(trimString(parts[i].substring(0, idx)), format);
+ }
+ }
+ }
+ else {
+ then();
+ }
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.createSvgDataUri = function (svg) {
+ return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svg)));
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.getFileData = function (forceXml, forceSvg, forceHtml, embeddedCallback, ignoreSelection, currentPage, node, compact, file) {
+ ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
+ currentPage = (currentPage != null) ? currentPage : false;
+
+ node = this.editor.getGraphXml(ignoreSelection);
+ var graph = this.editor.graph;
+
+
+ var result = this.createFileData(node, graph, file, window.location.href,
+ forceXml, forceSvg, forceHtml, embeddedCallback, ignoreSelection, compact);
+
+ // Removes temporary graph from DOM
+ if (graph != this.editor.graph) {
+ graph.container.parentNode.removeChild(graph.container);
+ }
+
+ return result;
+};
+
+/**
+ * Translates this point by the given vector.
+ *
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+EditorUi.prototype.createFileData = function (node, graph, file, url, forceXml, forceSvg, forceHtml, embeddedCallback, ignoreSelection, compact) {
+ graph = (graph != null) ? graph : this.editor.graph;
+ forceXml = (forceXml != null) ? forceXml : false;
+ ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
+
+ var editLink = null;
+ var redirect = null;
+
+ if (file == null || file.getMode() == App.MODE_DEVICE || file.getMode() == App.MODE_BROWSER) {
+ editLink = '_blank';
+ }
+ else {
+ editLink = url;
+ redirect = editLink;
+ }
+
+ if (node == null) {
+ return '';
+ }
+ else {
+ var fileNode = node;
+
+ // Ignores case for possible HTML or XML nodes
+ if (fileNode.nodeName.toLowerCase() != 'mxfile') {
+ // Removes control chars in input for correct roundtrip check
+ var text = graph.zapGremlins(mxUtils.getXml(node));
+ var data = graph.compress(text);
+
+ // Fallback to plain XML for invalid compression
+ // TODO: Remove this fallback with active pages
+ if (graph.decompress(data) != text) {
+ return text;
+ }
+ else {
+ var diagramNode = node.ownerDocument.createElement('diagram');
+ diagramNode.setAttribute('id', 'tapd-' + Editor.guid());
+ mxUtils.setTextContent(diagramNode, data);
+
+ fileNode = node.ownerDocument.createElement('mxfile');
+ fileNode.appendChild(diagramNode);
+ }
+ }
+
+ if (!compact) {
+ // Removes old metadata
+ fileNode.removeAttribute('userAgent');
+ fileNode.removeAttribute('version');
+ fileNode.removeAttribute('editor');
+ fileNode.removeAttribute('type');
+
+ // Adds new metadata
+ fileNode.setAttribute('modified', new Date().toISOString());
+ fileNode.setAttribute('host', window.location.hostname);
+ fileNode.setAttribute('agent', navigator.userAgent);
+ fileNode.setAttribute('version', EditorUi.VERSION);
+ fileNode.setAttribute('etag', 'tapd-' + Editor.guid());
+
+ var md = (file != null) ? file.getMode() : this.mode;
+
+ if (md != null) {
+ fileNode.setAttribute('type', md);
+ }
+ }
+ else {
+ fileNode = fileNode.cloneNode(true);
+ fileNode.removeAttribute('userAgent');
+ fileNode.removeAttribute('version');
+ fileNode.removeAttribute('editor');
+ fileNode.removeAttribute('type');
+ }
+
+ var xml = mxUtils.getXml(fileNode);
+
+ return xml;
+ }
+};
+
+/**
+ *
+ */
+EditorUi.prototype.saveCanvas = function (canvas, xml, format, exportHandler) {
+ var ext = ((format == 'jpeg') ? 'jpg' : format);
+ var filename = this.getBaseFilename() + '.' + ext;
+ var data = this.createImageDataUri(canvas, xml, format);
+
+ if (exportHandler && typeof exportHandler === 'function') {
+ exportHandler(data, filename);
+ } else {
+ this.doDownloadFile(data.substring(data.lastIndexOf(',') + 1), filename, 'image/' + format, true, format);
+ }
+
+};
+
+
+EditorUi.prototype.getBaseFilename = function () {
+ return this.editor.getFilename();
+};
+
+
+EditorUi.prototype.createImageDataUri = function (canvas, xml, format) {
+ var data = canvas.toDataURL('image/' + format);
+
+ // Checks if output is invalid or empty
+ if (data.length <= 6 || data == canvas.cloneNode(false).toDataURL('image/' + format)) {
+ throw { message: 'Invalid image' };
+ }
+
+ if (xml != null) {
+ data = this.writeGraphModelToPng(data, 'zTXt', 'mxGraphModel', atob(this.editor.graph.compress(xml)));
+ }
+
+ return data;
+};
+
+/**
+ * Adds the given text to the compressed or non-compressed text chunk.
+ */
+EditorUi.prototype.writeGraphModelToPng = function (data, type, key, value, error) {
+ var base64 = data.substring(data.indexOf(',') + 1);
+ var f = (window.atob) ? atob(base64) : Base64.decode(base64, true);
+ var pos = 0;
+
+ function fread(d, count) {
+ var start = pos;
+ pos += count;
+
+ return d.substring(start, pos);
+ };
+
+ // Reads unsigned long 32 bit big endian
+ function _freadint(d) {
+ var bytes = fread(d, 4);
+
+ return bytes.charCodeAt(3) + (bytes.charCodeAt(2) << 8) +
+ (bytes.charCodeAt(1) << 16) + (bytes.charCodeAt(0) << 24);
+ };
+
+ function writeInt(num) {
+ return String.fromCharCode((num >> 24) & 0x000000ff, (num >> 16) & 0x000000ff,
+ (num >> 8) & 0x000000ff, num & 0x000000ff);
+ };
+
+ // Checks signature
+ if (fread(f, 8) != String.fromCharCode(137) + 'PNG' + String.fromCharCode(13, 10, 26, 10)) {
+ if (error != null) {
+ error();
+ }
+
+ return;
+ }
+
+ // Reads header chunk
+ fread(f, 4);
+
+ if (fread(f, 4) != 'IHDR') {
+ if (error != null) {
+ error();
+ }
+
+ return;
+ }
+
+ fread(f, 17);
+ var result = f.substring(0, pos);
+
+ do {
+ var n = _freadint(f);
+ var chunk = fread(f, 4);
+
+ if (chunk == 'IDAT') {
+ result = f.substring(0, pos - 8);
+
+ var chunkData = key + String.fromCharCode(0) +
+ ((type == 'zTXt') ? String.fromCharCode(0) : '') +
+ value;
+
+ // FIXME: Wrong crc
+ var crc = 0xffffffff;
+ crc = this.updateCRC(crc, type, 0, 4);
+ crc = this.updateCRC(crc, chunkData, 0, chunkData.length);
+
+ result += writeInt(chunkData.length) + type + chunkData + writeInt(crc ^ 0xffffffff);
+ result += f.substring(pos - 8, f.length);
+
+ break;
+ }
+
+ result += f.substring(pos - 8, pos - 4 + n);
+ fread(f, n);
+ fread(f, 4);
+ }
+ while (n);
+
+ return 'data:image/png;base64,' + ((window.btoa) ? btoa(result) : Base64.encode(result, true));
+};
+
+EditorUi.prototype.crcTable = [];
+
+for (var n = 0; n < 256; n++) {
+ var c = n;
+
+ for (var k = 0; k < 8; k++) {
+ if ((c & 1) == 1) {
+ c = 0xedb88320 ^ (c >>> 1);
+ }
+ else {
+ c >>>= 1;
+ }
+
+ EditorUi.prototype.crcTable[n] = c;
+ }
+}
+
+EditorUi.prototype.updateCRC = function (crc, data, off, len) {
+ var c = crc;
+
+ for (var n = 0; n < len; n++) {
+ c = EditorUi.prototype.crcTable[(c ^ data[off + n]) & 0xff] ^ (c >>> 8);
+ }
+
+ return c;
+};
diff --git a/static/cherry/drawio_demo/Format.js b/static/cherry/drawio_demo/Format.js
new file mode 100644
index 000000000..e3ad09763
--- /dev/null
+++ b/static/cherry/drawio_demo/Format.js
@@ -0,0 +1,8103 @@
+/**
+ * Copyright (c) 2006-2012, JGraph Ltd
+ */
+Format = function(editorUi, container)
+{
+ this.editorUi = editorUi;
+ this.container = container;
+};
+
+/**
+ * Background color for inactive tabs.
+ */
+Format.inactiveTabBackgroundColor = '#e4e4e4';
+
+/**
+ * Icons for markers (24x16).
+ */
+Format.classicFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.classicThinFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.openFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.openThinFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.openAsyncFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.blockFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.blockThinFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.asyncFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ovalFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.diamondFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.diamondThinFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.classicMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.classicThinMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.blockMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.blockThinMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.asyncMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ovalMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.diamondMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.diamondThinMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.boxMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.halfCircleMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.dashMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.crossMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.circlePlusMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.circleMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ERmandOneMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ERmanyMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ERoneToManyMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ERzeroToOneMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.ERzeroToManyMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.EROneMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.baseDashMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.doubleBlockMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+Format.doubleBlockFilledMarkerImage = Graph.createSvgImage(20, 22, '', 32, 20);
+
+/**
+ * Adds a style change item to the given menu.
+ */
+Format.processMenuIcon = function(elt, transform)
+{
+ var imgs = elt.getElementsByTagName('img');
+
+ if (imgs.length > 0)
+ {
+ imgs[0].className = 'geIcon geAdaptiveAsset';
+ imgs[0].style.padding = '0px';
+ imgs[0].style.margin = '0 0 0 2px';
+
+ if (transform != null)
+ {
+ mxUtils.setPrefixedStyle(imgs[0].style, 'transform', transform);
+ }
+ }
+
+ return elt;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+Format.prototype.labelIndex = 0;
+
+/**
+ * Returns information about the current selection.
+ */
+Format.prototype.diagramIndex = 0;
+
+/**
+ * Returns information about the current selection.
+ */
+Format.prototype.currentIndex = 0;
+
+/**
+ * Returns information about the current selection.
+ */
+Format.prototype.showCloseButton = true;
+
+/**
+ * Returns information about the current selection.
+ */
+Format.prototype.rounded = false;
+
+/**
+ * Returns information about the current selection.
+ */
+Format.prototype.curved = false;
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+Format.prototype.init = function()
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ this.update = mxUtils.bind(this, function(sender, evt)
+ {
+ this.refresh();
+ });
+
+ graph.getSelectionModel().addListener(mxEvent.CHANGE, this.update);
+ graph.getModel().addListener(mxEvent.CHANGE, this.update);
+ graph.addListener(mxEvent.EDITING_STARTED, this.update);
+ graph.addListener(mxEvent.EDITING_STOPPED, this.update);
+ graph.getView().addListener('unitChanged', this.update);
+ editor.addListener('autosaveChanged', this.update);
+ graph.addListener(mxEvent.ROOT, this.update);
+ ui.addListener('styleChanged', this.update);
+ ui.addListener('darkModeChanged', this.update);
+
+ this.refresh();
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+Format.prototype.clear = function()
+{
+ this.container.innerText = '';
+
+ // Destroy existing panels
+ if (this.panels != null)
+ {
+ for (var i = 0; i < this.panels.length; i++)
+ {
+ this.panels[i].destroy();
+ }
+ }
+
+ this.panels = [];
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+Format.prototype.refresh = function()
+{
+ if (this.pendingRefresh != null)
+ {
+ window.clearTimeout(this.pendingRefresh);
+ this.pendingRefresh = null;
+ }
+
+ this.pendingRefresh = window.setTimeout(mxUtils.bind(this, function()
+ {
+ this.immediateRefresh();
+ }));
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+Format.prototype.immediateRefresh = function()
+{
+ // Performance tweak: No refresh needed if not visible
+ if (this.container.style.width == '0px')
+ {
+ return;
+ }
+
+ this.clear();
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+
+ var div = document.createElement('div');
+ div.style.whiteSpace = 'nowrap';
+ div.style.color = 'rgb(112, 112, 112)';
+ div.style.textAlign = 'left';
+ div.style.cursor = 'default';
+
+ var label = document.createElement('div');
+ label.className = 'geFormatSection';
+ label.style.textAlign = 'center';
+ label.style.fontWeight = 'bold';
+ label.style.paddingTop = '8px';
+ label.style.fontSize = '13px';
+ label.style.borderWidth = '0px 0px 1px 1px';
+ label.style.borderStyle = 'solid';
+ label.style.display = 'inline-block';
+ label.style.height = '25px';
+ label.style.overflow = 'hidden';
+ label.style.width = '100%';
+ this.container.appendChild(div);
+
+ // Prevents text selection
+ mxEvent.addListener(label, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
+ mxUtils.bind(this, function(evt)
+ {
+ evt.preventDefault();
+ }));
+
+ var ss = ui.getSelectionState();
+ var containsLabel = ss.containsLabel;
+ var currentLabel = null;
+ var currentPanel = null;
+
+ var addClickHandler = mxUtils.bind(this, function(elt, panel, index, lastEntry)
+ {
+ var clickHandler = mxUtils.bind(this, function(evt)
+ {
+ if (currentLabel != elt)
+ {
+ if (containsLabel)
+ {
+ this.labelIndex = index;
+ }
+ else if (graph.isSelectionEmpty())
+ {
+ this.diagramIndex = index;
+ }
+ else
+ {
+ this.currentIndex = index;
+ }
+
+ if (currentLabel != null)
+ {
+ currentLabel.style.backgroundColor = Format.inactiveTabBackgroundColor;
+ currentLabel.style.borderBottomWidth = '1px';
+ }
+
+ currentLabel = elt;
+ currentLabel.style.backgroundColor = '';
+ currentLabel.style.borderBottomWidth = '0px';
+
+ if (currentPanel != panel)
+ {
+ if (currentPanel != null)
+ {
+ currentPanel.style.display = 'none';
+ }
+
+ currentPanel = panel;
+ currentPanel.style.display = '';
+ }
+ }
+ });
+
+ mxEvent.addListener(elt, 'click', clickHandler);
+
+ // Prevents text selection
+ mxEvent.addListener(elt, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
+ mxUtils.bind(this, function(evt)
+ {
+ evt.preventDefault();
+ }));
+
+ if ((lastEntry && currentLabel == null) ||
+ (index == ((containsLabel) ? this.labelIndex : ((graph.isSelectionEmpty()) ?
+ this.diagramIndex : this.currentIndex))))
+ {
+ // Invokes handler directly as a workaround for no click on DIV in KHTML.
+ clickHandler();
+ }
+ });
+
+ var idx = 0;
+
+ if (graph.isSelectionEmpty())
+ {
+ mxUtils.write(label, mxResources.get('diagram'));
+ label.style.borderLeftWidth = '0px';
+
+ div.appendChild(label);
+ var diagramPanel = div.cloneNode(false);
+ this.panels.push(new DiagramFormatPanel(this, ui, diagramPanel));
+ this.container.appendChild(diagramPanel);
+
+ if (Editor.styles != null)
+ {
+ diagramPanel.style.display = 'none';
+ label.style.width = (this.showCloseButton) ? '106px' : '50%';
+ label.style.cursor = 'pointer';
+ label.style.backgroundColor = Format.inactiveTabBackgroundColor;
+
+ var label2 = label.cloneNode(false);
+ label2.style.borderLeftWidth = '1px';
+ label2.style.borderRightWidth = '1px';
+ label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
+
+ addClickHandler(label, diagramPanel, idx++);
+
+ var stylePanel = div.cloneNode(false);
+ stylePanel.style.display = 'none';
+ mxUtils.write(label2, mxResources.get('style'));
+ div.appendChild(label2);
+ this.panels.push(new DiagramStylePanel(this, ui, stylePanel));
+ this.container.appendChild(stylePanel);
+
+ addClickHandler(label2, stylePanel, idx++);
+ }
+
+ // Adds button to hide the format panel since
+ // people don't seem to find the toolbar button
+ // and the menu item in the format menu
+ if (this.showCloseButton)
+ {
+ var label2 = label.cloneNode(false);
+ label2.style.borderLeftWidth = '1px';
+ label2.style.borderRightWidth = '1px';
+ label2.style.borderBottomWidth = '1px';
+ label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
+ label2.style.position = 'absolute';
+ label2.style.right = '0px';
+ label2.style.top = '0px';
+ label2.style.width = '25px';
+
+ var img = document.createElement('img');
+ img.setAttribute('border', '0');
+ img.setAttribute('src', Dialog.prototype.closeImage);
+ img.setAttribute('title', mxResources.get('hide'));
+ img.style.position = 'absolute';
+ img.style.display = 'block';
+ img.style.right = '0px';
+ img.style.top = '8px';
+ img.style.cursor = 'pointer';
+ img.style.marginTop = '1px';
+ img.style.marginRight = '6px';
+ img.style.border = '1px solid transparent';
+ img.style.padding = '1px';
+ img.style.opacity = 0.5;
+ label2.appendChild(img)
+
+ mxEvent.addListener(img, 'click', function()
+ {
+ ui.actions.get('format').funct();
+ });
+
+ div.appendChild(label2);
+ }
+ }
+ else if (graph.isEditing())
+ {
+ mxUtils.write(label, mxResources.get('text'));
+ div.appendChild(label);
+ label.style.borderLeftStyle = 'none';
+ this.panels.push(new TextFormatPanel(this, ui, div));
+ }
+ else
+ {
+ label.style.backgroundColor = Format.inactiveTabBackgroundColor;
+ label.style.borderLeftWidth = '1px';
+ label.style.cursor = 'pointer';
+ label.style.width = ss.cells.length == 0 ? '100%' :
+ (containsLabel ? '50%' : '33.3%');
+ var label2 = label.cloneNode(false);
+ var label3 = label2.cloneNode(false);
+
+ // Workaround for ignored background in IE
+ label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
+ label3.style.backgroundColor = Format.inactiveTabBackgroundColor;
+
+ // Style
+ if (containsLabel)
+ {
+ label2.style.borderLeftWidth = '0px';
+ }
+ else if (ss.cells.length > 0)
+ {
+ label.style.borderLeftWidth = '0px';
+ mxUtils.write(label, mxResources.get('style'));
+ div.appendChild(label);
+
+ var stylePanel = div.cloneNode(false);
+ stylePanel.style.display = 'none';
+ this.panels.push(new StyleFormatPanel(this, ui, stylePanel));
+ this.container.appendChild(stylePanel);
+
+ addClickHandler(label, stylePanel, idx++);
+ }
+
+ // Text
+ mxUtils.write(label2, mxResources.get('text'));
+ div.appendChild(label2);
+
+ var textPanel = div.cloneNode(false);
+ textPanel.style.display = 'none';
+ this.panels.push(new TextFormatPanel(this, ui, textPanel));
+ this.container.appendChild(textPanel);
+
+ // Arrange
+ mxUtils.write(label3, mxResources.get('arrange'));
+ div.appendChild(label3);
+
+ var arrangePanel = div.cloneNode(false);
+ arrangePanel.style.display = 'none';
+ this.panels.push(new ArrangePanel(this, ui, arrangePanel));
+ this.container.appendChild(arrangePanel);
+
+ if (ss.cells.length > 0)
+ {
+ addClickHandler(label2, textPanel, idx + 1);
+ }
+ else
+ {
+ label2.style.display = 'none';
+ }
+
+ addClickHandler(label3, arrangePanel, idx++, true);
+ }
+};
+
+/**
+ * Base class for format panels.
+ */
+BaseFormatPanel = function(format, editorUi, container)
+{
+ this.format = format;
+ this.editorUi = editorUi;
+ this.container = container;
+ this.listeners = [];
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.buttonBackgroundColor = 'transparent';
+
+/**
+ * Install input handler.
+ */
+BaseFormatPanel.prototype.installInputHandler = function(input, key, defaultValue, min, max, unit, textEditFallback, isFloat)
+{
+ unit = (unit != null) ? unit : '';
+ isFloat = (isFloat != null) ? isFloat : false;
+
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+
+ min = (min != null) ? min : 1;
+ max = (max != null) ? max : 999;
+
+ var selState = null;
+ var updating = false;
+
+ var update = mxUtils.bind(this, function(evt)
+ {
+ var value = (isFloat) ? parseFloat(input.value) : parseInt(input.value);
+
+ // Special case: angle mod 360
+ if (!isNaN(value) && key == mxConstants.STYLE_ROTATION)
+ {
+ // Workaround for decimal rounding errors in floats is to
+ // use integer and round all numbers to two decimal point
+ value = mxUtils.mod(Math.round(value * 100), 36000) / 100;
+ }
+
+ value = Math.min(max, Math.max(min, (isNaN(value)) ? defaultValue : value));
+
+ if (graph.cellEditor.isContentEditing() && textEditFallback)
+ {
+ if (!updating)
+ {
+ updating = true;
+
+ if (selState != null)
+ {
+ graph.cellEditor.restoreSelection(selState);
+ selState = null;
+ }
+
+ textEditFallback(value);
+ input.value = value + unit;
+
+ // Restore focus and selection in input
+ updating = false;
+ }
+ }
+ else if (value != mxUtils.getValue(ui.getSelectionState().style, key, defaultValue))
+ {
+ if (graph.isEditing())
+ {
+ graph.stopEditing(true);
+ }
+
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = ui.getSelectionState().cells;
+ graph.setCellStyles(key, value, cells);
+
+ // Handles special case for fontSize where HTML labels are parsed and updated
+ if (key == mxConstants.STYLE_FONTSIZE)
+ {
+ graph.updateLabelElements(cells, function(elt)
+ {
+ elt.style.fontSize = value + 'px';
+ elt.removeAttribute('size');
+ });
+ }
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (graph.model.getChildCount(cells[i]) == 0)
+ {
+ graph.autoSizeCell(cells[i], false);
+ }
+ }
+
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [key],
+ 'values', [value], 'cells', cells));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+
+ input.value = value + unit;
+ mxEvent.consume(evt);
+ });
+
+ if (textEditFallback && graph.cellEditor.isContentEditing())
+ {
+ // KNOWN: Arrow up/down clear selection text in quirks/IE 8
+ // Text size via arrow button limits to 16 in IE11. Why?
+ mxEvent.addListener(input, 'mousedown', function()
+ {
+ if (document.activeElement == graph.cellEditor.textarea)
+ {
+ selState = graph.cellEditor.saveSelection();
+ }
+ });
+
+ mxEvent.addListener(input, 'touchstart', function()
+ {
+ if (document.activeElement == graph.cellEditor.textarea)
+ {
+ selState = graph.cellEditor.saveSelection();
+ }
+ });
+ }
+
+ mxEvent.addListener(input, 'change', update);
+ mxEvent.addListener(input, 'blur', update);
+
+ return update;
+};
+
+/**
+ * Adds the given option.
+ */
+BaseFormatPanel.prototype.createPanel = function()
+{
+ var div = document.createElement('div');
+ div.className = 'geFormatSection';
+ div.style.padding = '12px 0px 8px 14px';
+
+ return div;
+};
+
+/**
+ * Adds the given option.
+ */
+BaseFormatPanel.prototype.createTitle = function(title)
+{
+ var div = document.createElement('div');
+ div.style.padding = '0px 0px 6px 0px';
+ div.style.whiteSpace = 'nowrap';
+ div.style.overflow = 'hidden';
+ div.style.width = '200px';
+ div.style.fontWeight = 'bold';
+ mxUtils.write(div, title);
+
+ return div;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addAction = function(div, name)
+{
+ var action = this.editorUi.actions.get(name);
+ var btn = null;
+
+ if (action != null && action.isEnabled())
+ {
+ btn = mxUtils.button(action.label, mxUtils.bind(this, function(evt)
+ {
+ try
+ {
+ action.funct(evt, evt);
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }));
+
+ var short = (action.shortcut != null) ? ' (' + action.shortcut + ')' : '';
+ btn.setAttribute('title', action.label + short);
+ btn.style.marginBottom = '2px';
+ btn.style.width = '210px';
+ div.appendChild(btn);
+ result = true;
+ }
+
+ return btn;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addActions = function(div, names)
+{
+ var lastBr = null;
+ var last = null;
+ var count = 0;
+
+ for (var i = 0; i < names.length; i++)
+ {
+ var btn = this.addAction(div, names[i]);
+
+ if (btn != null)
+ {
+ count++;
+
+ if (mxUtils.mod(count, 2) == 0)
+ {
+ last.style.marginRight = '2px';
+ last.style.width = '104px';
+ btn.style.width = '104px';
+ lastBr.parentNode.removeChild(lastBr);
+ }
+
+ lastBr = mxUtils.br(div);
+ last = btn;
+ }
+ }
+
+ return count;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.createStepper = function(input, update, step, height, disableFocus, defaultValue, isFloat)
+{
+ step = (step != null) ? step : 1;
+ height = (height != null) ? height : 9;
+ var bigStep = 10 * step;
+
+ var stepper = document.createElement('div');
+ stepper.className = 'geBtnStepper';
+ stepper.style.position = 'absolute';
+
+ var up = document.createElement('div');
+ up.style.position = 'relative';
+ up.style.height = height + 'px';
+ up.style.width = '10px';
+ up.className = 'geBtnUp';
+ stepper.appendChild(up);
+
+ var down = up.cloneNode(false);
+ down.style.border = 'none';
+ down.style.height = height + 'px';
+ down.className = 'geBtnDown';
+ stepper.appendChild(down);
+
+ mxEvent.addGestureListeners(down, function(evt)
+ {
+ // Stops text selection on shift+click
+ mxEvent.consume(evt);
+ }, null, function(evt)
+ {
+ if (input.value == '')
+ {
+ input.value = defaultValue || '2';
+ }
+
+ var val = isFloat? parseFloat(input.value) : parseInt(input.value);
+
+ if (!isNaN(val))
+ {
+ input.value = val - (mxEvent.isShiftDown(evt) ? bigStep : step);
+
+ if (update != null)
+ {
+ update(evt);
+ }
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addGestureListeners(up, function(evt)
+ {
+ // Stops text selection on shift+click
+ mxEvent.consume(evt);
+ }, null, function(evt)
+ {
+ if (input.value == '')
+ {
+ input.value = defaultValue || '0';
+ }
+
+ var val = isFloat? parseFloat(input.value) : parseInt(input.value);
+
+ if (!isNaN(val))
+ {
+ input.value = val + (mxEvent.isShiftDown(evt) ? bigStep : step);
+
+ if (update != null)
+ {
+ update(evt);
+ }
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ // Disables transfer of focus to DIV but also :active CSS
+ // so it's only used for fontSize where the focus should
+ // stay on the selected text, but not for any other input.
+ if (disableFocus)
+ {
+ var currentSelection = null;
+
+ mxEvent.addGestureListeners(stepper,
+ function(evt)
+ {
+ mxEvent.consume(evt);
+ },
+ null,
+ function(evt)
+ {
+ // Workaround for lost current selection in page because of focus in IE
+ if (currentSelection != null)
+ {
+ try
+ {
+ currentSelection.select();
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ currentSelection = null;
+ mxEvent.consume(evt);
+ }
+ }
+ );
+ }
+ else
+ {
+ // Stops propagation on checkbox labels
+ mxEvent.addListener(stepper, 'click', function(evt)
+ {
+ mxEvent.consume(evt);
+ });
+ }
+
+ return stepper;
+};
+
+/**
+ * Adds the given option.
+ */
+BaseFormatPanel.prototype.createOption = function(label, isCheckedFn, setCheckedFn, listener, fn)
+{
+ var div = document.createElement('div');
+ div.style.display = 'flex';
+ div.style.alignItems = 'center';
+ div.style.padding = '3px 0px 3px 0px';
+ div.style.height = '18px';
+
+ var cb = document.createElement('input');
+ cb.setAttribute('type', 'checkbox');
+ cb.style.margin = '1px 6px 0px 0px';
+ cb.style.verticalAlign = 'top';
+ div.appendChild(cb);
+
+ var elt = document.createElement('div');
+ elt.style.display = 'inline-block';
+ elt.style.whiteSpace = 'nowrap';
+ elt.style.textOverflow = 'ellipsis';
+ elt.style.overflow = 'hidden';
+ elt.style.maxWidth = '160px';
+ elt.style.maxWidth = '160px';
+ elt.style.userSelect = 'none';
+ mxUtils.write(elt, label);
+ div.appendChild(elt);
+
+ var applying = false;
+ var value = isCheckedFn();
+
+ var apply = function(newValue, evt)
+ {
+ if (!applying)
+ {
+ applying = true;
+
+ if (newValue)
+ {
+ cb.setAttribute('checked', 'checked');
+ cb.defaultChecked = true;
+ cb.checked = true;
+ }
+ else
+ {
+ cb.removeAttribute('checked');
+ cb.defaultChecked = false;
+ cb.checked = false;
+ }
+
+ if (value != newValue)
+ {
+ value = newValue;
+
+ // Checks if the color value needs to be updated in the model
+ if (isCheckedFn() != value)
+ {
+ setCheckedFn(value, evt);
+ }
+ }
+
+ applying = false;
+ }
+ };
+
+ mxEvent.addListener(div, 'click', function(evt)
+ {
+ if (cb.getAttribute('disabled') != 'disabled')
+ {
+ // Toggles checkbox state for click on label
+ var source = mxEvent.getSource(evt);
+
+ if (source == div || source == elt)
+ {
+ cb.checked = !cb.checked;
+ }
+
+ apply(cb.checked, evt);
+ }
+ });
+
+ apply(value);
+
+ if (listener != null)
+ {
+ listener.install(apply);
+ this.listeners.push(listener);
+ }
+
+ if (fn != null)
+ {
+ fn(div);
+ }
+
+ return div;
+};
+
+/**
+ * The string 'null' means use null in values.
+ */
+BaseFormatPanel.prototype.createCellOption = function(label, key, defaultValue, enabledValue, disabledValue, fn, action, stopEditing, cells)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ enabledValue = (enabledValue != null) ? ((enabledValue == 'null') ? null : enabledValue) : 1;
+ disabledValue = (disabledValue != null) ? ((disabledValue == 'null') ? null : disabledValue) : 0;
+
+ var style = (cells != null) ? graph.getCommonStyle(cells) : ui.getSelectionState().style;
+
+ return this.createOption(label, function()
+ {
+ return mxUtils.getValue(style, key, defaultValue) != disabledValue;
+ }, function(checked)
+ {
+ if (stopEditing)
+ {
+ graph.stopEditing();
+ }
+
+ if (action != null)
+ {
+ action.funct();
+ }
+ else
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var temp = (cells != null) ? cells : ui.getSelectionState().cells;
+ var value = (checked) ? enabledValue : disabledValue;
+ graph.setCellStyles(key, value, temp);
+
+ if (fn != null)
+ {
+ fn(temp, value);
+ }
+
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys',
+ [key], 'values', [value], 'cells', temp));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(mxUtils.getValue(style, key, defaultValue) != disabledValue);
+ };
+
+ graph.getModel().addListener(mxEvent.CHANGE, this.listener);
+ },
+ destroy: function()
+ {
+ graph.getModel().removeListener(this.listener);
+ }
+ });
+};
+
+/**
+ * Adds the given color option.
+ */
+BaseFormatPanel.prototype.createColorOption = function(label, getColorFn, setColorFn,
+ defaultColor, listener, callbackFn, hideCheckbox, defaultColorValue)
+{
+ var graph = this.editorUi.editor.graph;
+
+ var div = document.createElement('div');
+ div.style.padding = '3px 0px 3px 0px';
+ div.style.whiteSpace = 'nowrap';
+ div.style.overflow = 'hidden';
+ div.style.width = '200px';
+ div.style.height = '18px';
+
+ var cb = document.createElement('input');
+ cb.setAttribute('type', 'checkbox');
+ cb.style.margin = '1px 6px 0px 0px';
+ cb.style.verticalAlign = 'top';
+
+ if (!hideCheckbox)
+ {
+ div.appendChild(cb);
+ }
+
+ var span = document.createElement('span');
+ span.style.verticalAlign = 'top';
+ mxUtils.write(span, label);
+ div.appendChild(span);
+
+ var value = getColorFn();
+ var applying = false;
+ var dropper = null;
+ var btn = null;
+
+ var clrInput = document.createElement('input');
+ clrInput.setAttribute('type', 'color');
+ clrInput.style.position = 'relative';
+ clrInput.style.visibility = 'hidden';
+ clrInput.style.top = '10px';
+ clrInput.style.width = '0px';
+ clrInput.style.height = '0px';
+ clrInput.style.border = 'none';
+
+ // Adds native color dialog
+ if (!mxClient.IS_IE && !mxClient.IS_IE11 && !mxClient.IS_TOUCH)
+ {
+ dropper = document.createElement('img');
+ dropper.src = Editor.colorDropperImage;
+ dropper.className = 'geColorDropper geAdaptiveAsset';
+ dropper.style.position = 'relative';
+ dropper.style.right = '-20px';
+ dropper.style.top = '-1px';
+ dropper.style.width = 'auto';
+ dropper.style.height = '14px';
+
+ mxEvent.addListener(dropper, 'click', function(evt)
+ {
+ var color = value;
+
+ if (color == 'default')
+ {
+ color = defaultColorValue;
+ }
+
+ clrInput.value = color;
+ clrInput.click();
+
+ mxEvent.consume(evt);
+ });
+ }
+
+ var apply = function(color, disableUpdate, forceUpdate)
+ {
+ if (!applying)
+ {
+ var defaultValue = (defaultColor == 'null') ? null : defaultColor;
+
+ applying = true;
+ color = (/(^#?[a-zA-Z0-9]*$)/.test(color)) ? color : defaultValue;
+ var tempColor = (color != null && color != mxConstants.NONE) ? color : defaultValue;
+
+ var div = document.createElement('div');
+ div.style.width = '21px';
+ div.style.height = '12px';
+ div.style.margin = '2px 18px 2px 3px';
+ div.style.border = '1px solid black';
+ div.style.backgroundColor = (tempColor == 'default') ? defaultColorValue : tempColor;
+ btn.innerText = '';
+ btn.appendChild(div);
+
+ if (dropper != null)
+ {
+ div.style.width = '21px';
+ div.style.margin = '2px 18px 2px 3px';
+ div.appendChild(dropper);
+ }
+ else
+ {
+ div.style.width = '36px';
+ div.style.margin = '3px';
+ }
+
+ if (color != null && color != mxConstants.NONE && color.length > 1 && typeof color === 'string')
+ {
+ var clr = (color.charAt(0) == '#') ? color.substring(1).toUpperCase() : color;
+ var name = ColorDialog.prototype.colorNames[clr];
+
+ if (name != null)
+ {
+ btn.setAttribute('title', name);
+ }
+ }
+
+ if (color != null && color != mxConstants.NONE &&
+ !graph.isSpecialColor(color))
+ {
+ cb.setAttribute('checked', 'checked');
+ cb.defaultChecked = true;
+ cb.checked = true;
+ }
+ else
+ {
+ cb.removeAttribute('checked');
+ cb.defaultChecked = false;
+ cb.checked = false;
+ }
+
+ btn.style.display = (cb.checked || hideCheckbox) ? '' : 'none';
+
+ if (callbackFn != null)
+ {
+ callbackFn(color == 'null' ? null : color);
+ }
+
+ value = color;
+
+ if (!disableUpdate)
+ {
+ // Checks if the color value needs to be updated in the model
+ if (forceUpdate || hideCheckbox || getColorFn() != value)
+ {
+ setColorFn(value == 'null' ? null : value, value);
+ }
+ }
+
+ applying = false;
+ }
+ };
+
+ div.appendChild(clrInput);
+
+ mxEvent.addListener(clrInput, 'change', function()
+ {
+ apply(clrInput.value, null, true);
+ });
+
+ btn = mxUtils.button('', mxUtils.bind(this, function(evt)
+ {
+ var color = value;
+
+ if (color == 'default')
+ {
+ color = defaultColorValue;
+ }
+
+ this.editorUi.pickColor(color, function(newColor)
+ {
+ apply(newColor, null, true);
+ }, defaultColorValue);
+
+ mxEvent.consume(evt);
+ }));
+
+ btn.style.position = 'absolute';
+ btn.style.marginTop = '-3px';
+ btn.style.left = '178px';
+ btn.style.height = '22px';
+ btn.className = 'geColorBtn';
+ btn.style.display = (cb.checked || hideCheckbox) ? '' : 'none';
+ div.appendChild(btn);
+
+ var clr = (value != null && typeof value === 'string' && value.charAt(0) == '#') ? value.substring(1).toUpperCase() : value;
+ var name = ColorDialog.prototype.colorNames[clr];
+
+ if (name != null)
+ {
+ btn.setAttribute('title', name);
+ }
+
+ mxEvent.addListener(div, 'click', function(evt)
+ {
+ var source = mxEvent.getSource(evt);
+
+ if (source == cb || source.nodeName != 'INPUT')
+ {
+ // Toggles checkbox state for click on label
+ if (source != cb)
+ {
+ cb.checked = !cb.checked;
+ }
+
+ // Overrides default value with current value to make it easier
+ // to restore previous value if the checkbox is clicked twice
+ if (!cb.checked && value != null && value != mxConstants.NONE &&
+ defaultColor != mxConstants.NONE)
+ {
+ defaultColor = value;
+ }
+
+ apply((cb.checked) ? defaultColor : mxConstants.NONE);
+ }
+ });
+
+ apply(value, true);
+
+ if (listener != null)
+ {
+ listener.install(apply);
+ this.listeners.push(listener);
+ }
+
+ return div;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.createCellColorOption = function(label, colorKey, defaultColor, callbackFn, setStyleFn, defaultColorValue)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ return this.createColorOption(label, function()
+ {
+ // Seems to be null sometimes, not sure why...
+ var state = graph.view.getState(ui.getSelectionState().cells[0]);
+
+ if (state != null)
+ {
+ return mxUtils.getValue(state.style, colorKey, null);
+ }
+
+ return null;
+ }, function(color)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = ui.getSelectionState().cells;
+ graph.setCellStyles(colorKey, color, cells);
+
+ if (setStyleFn != null)
+ {
+ setStyleFn(color);
+ }
+
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [colorKey],
+ 'values', [color], 'cells', cells));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }, defaultColor || mxConstants.NONE,
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ // Seems to be null sometimes, not sure why...
+ var state = graph.view.getState(ui.getSelectionState().cells[0]);
+
+ if (state != null)
+ {
+ apply(mxUtils.getValue(state.style, colorKey, null), true);
+ }
+ };
+
+ graph.getModel().addListener(mxEvent.CHANGE, this.listener);
+ },
+ destroy: function()
+ {
+ graph.getModel().removeListener(this.listener);
+ }
+ }, callbackFn, null, defaultColorValue);
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addArrow = function(elt)
+{
+ elt.className = 'geColorBtn';
+ elt.style.display = 'inline-flex';
+ elt.style.alignItems = 'top';
+ elt.style.boxSizing = 'border-box';
+ elt.style.width = '64px';
+ elt.style.height = '22px';
+ elt.style.borderWidth = '1px';
+ elt.style.borderStyle = 'solid';
+ elt.style.margin = '2px 2px 2px 3px';
+
+ var arrow = document.createElement('div');
+ arrow.className = 'geAdaptiveAsset';
+ arrow.style.display = 'inline-block';
+ arrow.style.backgroundImage = 'url(' + Editor.thinExpandImage + ')';
+ arrow.style.backgroundRepeat = 'no-repeat';
+ arrow.style.backgroundPosition = '-2px 1px';
+ arrow.style.backgroundSize = '18px 18px';
+ arrow.style.opacity = '0.5';
+ arrow.style.height = '100%';
+ arrow.style.width = '14px';
+
+ elt.appendChild(arrow);
+
+ var symbol = elt.getElementsByTagName('div')[0];
+
+ if (symbol != null)
+ {
+ symbol.style.display = 'inline-block';
+ symbol.style.backgroundPositionX = 'center';
+ symbol.style.textAlign = 'center';
+ symbol.style.height = '100%';
+ symbol.style.flexGrow = '1';
+ symbol.style.opacity = '0.6';
+ }
+
+ return symbol;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addUnitInput = function(container, unit, right, width, update, step, marginTop, disableFocus, isFloat)
+{
+ marginTop = (marginTop != null) ? marginTop : 0;
+
+ var input = document.createElement('input');
+ input.style.position = 'absolute';
+ input.style.textAlign = 'right';
+ input.style.marginTop = '-2px';
+ input.style.left = (228 - right - width) + 'px';
+ input.style.width = width + 'px';
+ input.style.height = '21px';
+ input.style.borderWidth = '1px';
+ input.style.borderStyle = 'solid';
+ input.style.boxSizing = 'border-box';
+
+ container.appendChild(input);
+
+ var stepper = this.createStepper(input, update, step, null, disableFocus, null, isFloat);
+ stepper.style.marginTop = (marginTop - 2) + 'px';
+ stepper.style.left = (228 - right) + 'px';
+ container.appendChild(stepper);
+
+ return input;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addGenericInput = function(container, unit, left, width, readFn, writeFn)
+{
+ var graph = this.editorUi.editor.graph;
+
+ var update = function()
+ {
+ writeFn(input.value);
+ };
+
+ var input = this.addUnitInput(container, unit, left, width, update);
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ if (force || input != document.activeElement)
+ {
+ input.value = readFn() + unit;
+ }
+ });
+
+ mxEvent.addListener(input, 'keydown', function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ graph.container.focus();
+ mxEvent.consume(e);
+ }
+ else if (e.keyCode == 27)
+ {
+ listener(null, null, true);
+ graph.container.focus();
+ mxEvent.consume(e);
+ }
+ });
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+
+ mxEvent.addListener(input, 'blur', update);
+ mxEvent.addListener(input, 'change', update);
+
+ return input;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.createRelativeOption = function(label, key, width, handler, init)
+{
+ width = (width != null) ? width : 52;
+
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var div = this.createPanel();
+ div.style.paddingTop = '10px';
+ div.style.paddingBottom = '12px';
+ mxUtils.write(div, label);
+ div.style.fontWeight = 'bold';
+
+ var update = mxUtils.bind(this, function(evt)
+ {
+ if (handler != null)
+ {
+ handler(input);
+ }
+ else
+ {
+ var value = parseInt(input.value);
+ value = Math.min(100, Math.max(0, (isNaN(value)) ? 100 : value));
+ var state = graph.view.getState(ui.getSelectionState().cells[0]);
+
+ if (state != null && value != mxUtils.getValue(state.style, key, 100))
+ {
+ // Removes entry in style (assumes 100 is default for relative values)
+ if (value == 100)
+ {
+ value = null;
+ }
+
+ var cells = ui.getSelectionState().cells;
+ graph.setCellStyles(key, value, cells);
+ this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [key],
+ 'values', [value], 'cells', cells));
+ }
+
+ input.value = ((value != null) ? value : '100') + ' %';
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ var input = this.addUnitInput(div, '%', 16, width, update, 10,
+ (mxClient.IS_MAC && mxClient.IS_GC) ? -14 :
+ ((mxClient.IS_WIN) ? -16 : -15), handler != null);
+
+ if (key != null)
+ {
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ if (force || input != document.activeElement)
+ {
+ var ss = ui.getSelectionState();
+ var tmp = parseInt(mxUtils.getValue(ss.style, key, 100));
+ input.value = (isNaN(tmp)) ? '' : tmp + ' %';
+ }
+ });
+
+ mxEvent.addListener(input, 'keydown', function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ graph.container.focus();
+ mxEvent.consume(e);
+ }
+ else if (e.keyCode == 27)
+ {
+ listener(null, null, true);
+ graph.container.focus();
+ mxEvent.consume(e);
+ }
+ });
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+ }
+
+ mxEvent.addListener(input, 'blur', update);
+ mxEvent.addListener(input, 'change', update);
+
+ if (init != null)
+ {
+ init(input);
+ }
+
+ return div;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addLabel = function(div, title, right, width)
+{
+ width = (width != null) ? width : 61;
+
+ var label = document.createElement('div');
+ mxUtils.write(label, title);
+ label.style.position = 'absolute';
+ label.style.left = (240 - right - width) + 'px';
+ label.style.width = width + 'px';
+ label.style.marginTop = '6px';
+ label.style.display = 'flex';
+ label.style.justifyContent = 'center';
+ div.appendChild(label);
+
+ return label;
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.addKeyHandler = function(input, listener)
+{
+ mxEvent.addListener(input, 'keydown', mxUtils.bind(this, function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ this.editorUi.editor.graph.container.focus();
+ mxEvent.consume(e);
+ }
+ else if (e.keyCode == 27)
+ {
+ if (listener != null)
+ {
+ listener(null, null, true);
+ }
+
+ this.editorUi.editor.graph.container.focus();
+ mxEvent.consume(e);
+ }
+ }));
+};
+
+/**
+ *
+ */
+BaseFormatPanel.prototype.styleButtons = function(elts)
+{
+ for (var i = 0; i < elts.length; i++)
+ {
+ mxUtils.setPrefixedStyle(elts[i].style, 'borderRadius', '3px');
+ mxUtils.setOpacity(elts[i], 100);
+ elts[i].style.border = '1px solid #a0a0a0';
+ elts[i].style.padding = '4px';
+ elts[i].style.paddingTop = '3px';
+ elts[i].style.paddingRight = '1px';
+ elts[i].style.margin = '1px';
+ elts[i].style.marginRight = '2px';
+ elts[i].style.width = '24px';
+ elts[i].style.height = '20px';
+ elts[i].className += ' geColorBtn';
+ }
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+BaseFormatPanel.prototype.destroy = function()
+{
+ if (this.listeners != null)
+ {
+ for (var i = 0; i < this.listeners.length; i++)
+ {
+ this.listeners[i].destroy();
+ }
+
+ this.listeners = null;
+ }
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+ArrangePanel = function(format, editorUi, container)
+{
+ BaseFormatPanel.call(this, format, editorUi, container);
+ this.init();
+};
+
+mxUtils.extend(ArrangePanel, BaseFormatPanel);
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+ArrangePanel.prototype.init = function()
+{
+ var ss = this.editorUi.getSelectionState();
+
+ if (ss.cells.length > 0)
+ {
+ this.container.appendChild(this.addLayerOps(this.createPanel()));
+
+ // Special case that adds two panels
+ this.addGeometry(this.container);
+ this.addEdgeGeometry(this.container);
+
+ if (!ss.containsLabel || ss.edges.length == 0)
+ {
+ this.container.appendChild(this.addAngle(this.createPanel()));
+ }
+
+ if (!ss.containsLabel)
+ {
+ this.container.appendChild(this.addFlip(this.createPanel()));
+ }
+
+ this.container.appendChild(this.addAlign(this.createPanel()));
+
+ if (ss.vertices.length > 1 && !ss.cell && !ss.row)
+ {
+ this.container.appendChild(this.addDistribute(this.createPanel()));
+ }
+
+ this.container.appendChild(this.addTable(this.createPanel()));
+ }
+
+ // Allows to lock/unload button to be added
+ this.container.appendChild(this.addGroupOps(this.createPanel()));
+
+ if (ss.containsLabel)
+ {
+ // Adds functions from hidden style format panel
+ var span = document.createElement('div');
+ span.style.width = '100%';
+ span.style.marginTop = '0px';
+ span.style.fontWeight = 'bold';
+ span.style.padding = '10px 0 0 14px';
+ mxUtils.write(span, mxResources.get('style'));
+ this.container.appendChild(span);
+
+ new StyleFormatPanel(this.format, this.editorUi, this.container);
+ }
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addTable = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var ss = ui.getSelectionState();
+ div.style.paddingTop = '6px';
+ div.style.paddingBottom = '10px';
+
+ var span = document.createElement('div');
+ span.style.marginTop = '0px';
+ span.style.marginBottom = '6px';
+ span.style.fontWeight = 'bold';
+ mxUtils.write(span, mxResources.get('table'));
+ div.appendChild(span);
+
+ var panel = document.createElement('div');
+ panel.style.position = 'relative';
+ panel.style.paddingLeft = '0px';
+ panel.style.borderWidth = '0px';
+ panel.style.width = '220px';
+ panel.className = 'geToolbarContainer';
+
+ var cell = ss.vertices[0];
+
+ if (graph.getSelectionCount() > 1)
+ {
+ if (graph.isTableCell(cell))
+ {
+ cell = graph.model.getParent(cell);
+ }
+
+ if (graph.isTableRow(cell))
+ {
+ cell = graph.model.getParent(cell);
+ }
+ }
+
+ var isTable = ss.table || ss.row || ss.cell;
+ var isStack = graph.isStack(cell) ||
+ graph.isStackChild(cell);
+
+ var showCols = isTable;
+ var showRows = isTable;
+
+ if (isStack)
+ {
+ var style = (graph.isStack(cell)) ? ss.style :
+ graph.getCellStyle(graph.model.getParent(cell));
+
+ showRows = style['horizontalStack'] == '0';
+ showCols = !showRows;
+ }
+
+ var btns = [];
+
+ if (showCols)
+ {
+ btns = btns.concat([
+ ui.toolbar.addButton('geSprite-insertcolumnbefore', mxResources.get('insertColumnBefore'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (isStack)
+ {
+ graph.insertLane(cell, true);
+ }
+ else
+ {
+ graph.insertTableColumn(cell, true);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }), panel),
+ ui.toolbar.addButton('geSprite-insertcolumnafter', mxResources.get('insertColumnAfter'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (isStack)
+ {
+ graph.insertLane(cell, false);
+ }
+ else
+ {
+ graph.insertTableColumn(cell, false);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }), panel),
+ ui.toolbar.addButton('geSprite-deletecolumn', mxResources.get('deleteColumn'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (isStack)
+ {
+ graph.deleteLane(cell);
+ }
+ else
+ {
+ graph.deleteTableColumn(cell);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }), panel)]);
+ }
+
+ if (showRows)
+ {
+ btns = btns.concat([ui.toolbar.addButton('geSprite-insertrowbefore', mxResources.get('insertRowBefore'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (isStack)
+ {
+ graph.insertLane(cell, true);
+ }
+ else
+ {
+ graph.insertTableRow(cell, true);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }), panel),
+ ui.toolbar.addButton('geSprite-insertrowafter', mxResources.get('insertRowAfter'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (isStack)
+ {
+ graph.insertLane(cell, false);
+ }
+ else
+ {
+ graph.insertTableRow(cell, false);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }), panel),
+ ui.toolbar.addButton('geSprite-deleterow', mxResources.get('deleteRow'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (isStack)
+ {
+ graph.deleteLane(cell);
+ }
+ else
+ {
+ graph.deleteTableRow(cell);
+ }
+ }
+ catch (e)
+ {
+ ui.handleError(e);
+ }
+ }), panel)]);
+ }
+
+ if (btns.length > 0)
+ {
+ this.styleButtons(btns);
+ div.appendChild(panel);
+
+ if (btns.length > 3)
+ {
+ btns[2].style.marginRight = '10px';
+ }
+
+ var count = 0;
+
+ if (ss.mergeCell != null)
+ {
+ count += this.addActions(div, ['mergeCells']);
+ }
+ else if (ss.style['colspan'] > 1 || ss.style['rowspan'] > 1)
+ {
+ count += this.addActions(div, ['unmergeCells']);
+ }
+
+ if (count > 0)
+ {
+ panel.style.paddingBottom = '2px';
+ }
+ }
+ else
+ {
+ div.style.display = 'none';
+ }
+
+ return div;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addLayerOps = function(div)
+{
+ this.addActions(div, ['toFront', 'toBack']);
+ this.addActions(div, ['bringForward', 'sendBackward']);
+
+ return div;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addGroupOps = function(div)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var ss = ui.getSelectionState();
+
+ div.style.paddingTop = '8px';
+ div.style.paddingBottom = '6px';
+
+ var count = 0;
+
+ if (!ss.cell && !ss.row)
+ {
+ count += this.addActions(div, ['group', 'ungroup', 'copySize', 'pasteSize']) +
+ this.addActions(div, ['removeFromGroup']);
+ }
+
+ var clearWaypoints = this.addAction(div, 'clearWaypoints');
+
+ if (clearWaypoints != null)
+ {
+ mxUtils.br(div);
+ clearWaypoints.setAttribute('title', mxResources.get('clearWaypoints') +
+ ' (' + this.editorUi.actions.get('clearWaypoints').shortcut + ')' +
+ ' Shift+Click to Clear Anchor Points');
+ count++;
+ }
+
+ count += this.addActions(div, ['lockUnlock']);
+
+ if (count == 0)
+ {
+ div.style.display = 'none';
+ }
+
+ return div;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addAlign = function(div)
+{
+ var ss = this.editorUi.getSelectionState();
+ var graph = this.editorUi.editor.graph;
+ div.style.paddingTop = '6px';
+ div.style.paddingBottom = '8px';
+ div.appendChild(this.createTitle(mxResources.get('align')));
+
+ var stylePanel = document.createElement('div');
+ stylePanel.style.position = 'relative';
+ stylePanel.style.whiteSpace = 'nowrap';
+ stylePanel.style.paddingLeft = '0px';
+ stylePanel.style.paddingBottom = '2px';
+ stylePanel.style.borderWidth = '0px';
+ stylePanel.style.width = '220px';
+ stylePanel.className = 'geToolbarContainer';
+
+ if (ss.vertices.length > 1)
+ {
+ var left = this.editorUi.toolbar.addButton('geSprite-alignleft', mxResources.get('left'),
+ function() { graph.alignCells(mxConstants.ALIGN_LEFT); }, stylePanel);
+ var center = this.editorUi.toolbar.addButton('geSprite-aligncenter', mxResources.get('center'),
+ function() { graph.alignCells(mxConstants.ALIGN_CENTER); }, stylePanel);
+ var right = this.editorUi.toolbar.addButton('geSprite-alignright', mxResources.get('right'),
+ function() { graph.alignCells(mxConstants.ALIGN_RIGHT); }, stylePanel);
+
+ var top = this.editorUi.toolbar.addButton('geSprite-aligntop', mxResources.get('top'),
+ function() { graph.alignCells(mxConstants.ALIGN_TOP); }, stylePanel);
+ var middle = this.editorUi.toolbar.addButton('geSprite-alignmiddle', mxResources.get('middle'),
+ function() { graph.alignCells(mxConstants.ALIGN_MIDDLE); }, stylePanel);
+ var bottom = this.editorUi.toolbar.addButton('geSprite-alignbottom', mxResources.get('bottom'),
+ function() { graph.alignCells(mxConstants.ALIGN_BOTTOM); }, stylePanel);
+
+ this.styleButtons([left, center, right, top, middle, bottom]);
+ right.style.marginRight = '10px';
+ }
+
+ div.appendChild(stylePanel);
+ this.addActions(div, ['snapToGrid']);
+
+ return div;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addFlip = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ div.style.paddingTop = '6px';
+ div.style.paddingBottom = '10px';
+ var ss = this.editorUi.getSelectionState();
+
+ var span = document.createElement('div');
+ span.style.marginTop = '2px';
+ span.style.marginBottom = '8px';
+ span.style.fontWeight = 'bold';
+ mxUtils.write(span, mxResources.get('flip'));
+ div.appendChild(span);
+
+ var btn = mxUtils.button(mxResources.get('horizontal'), function(evt)
+ {
+ graph.flipCells(ss.cells, true);
+ })
+
+ btn.setAttribute('title', mxResources.get('horizontal'));
+ btn.style.width = '104px';
+ btn.style.marginRight = '2px';
+ div.appendChild(btn);
+
+ var btn = mxUtils.button(mxResources.get('vertical'), function(evt)
+ {
+ graph.flipCells(ss.cells, false);
+ })
+
+ btn.setAttribute('title', mxResources.get('vertical'));
+ btn.style.width = '104px';
+ div.appendChild(btn);
+
+ return div;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addDistribute = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ div.style.paddingTop = '6px';
+ div.style.paddingBottom = '8px';
+
+ div.appendChild(this.createTitle(mxResources.get('distribute')));
+
+ var btn = mxUtils.button(mxResources.get('horizontal'), function(evt)
+ {
+ graph.distributeCells(true, null, cb.checked);
+ })
+
+ btn.setAttribute('title', mxResources.get('horizontal'));
+ btn.style.width = '104px';
+ btn.style.marginRight = '2px';
+ div.appendChild(btn);
+
+ var btn = mxUtils.button(mxResources.get('vertical'), function(evt)
+ {
+ graph.distributeCells(false, null, cb.checked);
+ })
+
+ btn.setAttribute('title', mxResources.get('vertical'));
+ btn.style.width = '104px';
+ div.appendChild(btn);
+
+ mxUtils.br(div);
+
+ var panel = document.createElement('div');
+ panel.style.margin = '6px 0 0 0';
+ panel.style.display = 'flex';
+ panel.style.justifyContent = 'center';
+ panel.style.alignItems = 'center';
+
+ var cb = document.createElement('input');
+ cb.setAttribute('type', 'checkbox');
+ cb.setAttribute('id', 'spacingCheckbox');
+ cb.style.margin = '0 6px 0 0';
+ panel.appendChild(cb);
+
+ var label = document.createElement('label');
+ label.style.verticalAlign = 'top';
+ label.setAttribute('for', 'spacingCheckbox');
+ label.style.userSelect = 'none';
+ mxUtils.write(label, mxResources.get('spacing'));
+ panel.appendChild(label);
+ div.appendChild(panel);
+
+ return div;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addAngle = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var ss = ui.getSelectionState();
+
+ div.style.paddingBottom = '12px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ span.style.fontWeight = 'bold';
+
+ var input = null;
+ var update = null;
+ var btn = null;
+
+ if (ss.rotatable && !ss.table && !ss.row && !ss.cell)
+ {
+ mxUtils.write(span, mxResources.get('angle'));
+ div.appendChild(span);
+
+ input = this.addUnitInput(div, '°', 16, 52, function()
+ {
+ update.apply(this, arguments);
+ });
+
+ mxUtils.br(div);
+ div.style.paddingTop = '10px';
+ }
+ else
+ {
+ div.style.paddingTop = '8px';
+ }
+
+ if (!ss.containsLabel)
+ {
+ var label = mxResources.get('reverse');
+
+ if (ss.vertices.length > 0 && ss.edges.length > 0)
+ {
+ label = mxResources.get('turn') + ' / ' + label;
+ }
+ else if (ss.vertices.length > 0)
+ {
+ label = mxResources.get('turn');
+ }
+
+ btn = mxUtils.button(label, function(evt)
+ {
+ ui.actions.get('turn').funct(evt);
+ })
+
+ btn.setAttribute('title', label + ' (' + this.editorUi.actions.get('turn').shortcut + ')');
+ btn.style.width = '210px';
+ div.appendChild(btn);
+
+ if (input != null)
+ {
+ btn.style.marginTop = '8px';
+ }
+ }
+
+ if (input != null)
+ {
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ if (force || document.activeElement != input)
+ {
+ ss = ui.getSelectionState();
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_ROTATION, 0));
+ input.value = (isNaN(tmp)) ? '' : tmp + '°';
+ }
+ });
+
+ update = this.installInputHandler(input, mxConstants.STYLE_ROTATION, 0, 0, 360, '°', null, true);
+ this.addKeyHandler(input, listener);
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+ }
+
+ return div;
+};
+
+BaseFormatPanel.prototype.getUnit = function()
+{
+ var unit = this.editorUi.editor.graph.view.unit;
+
+ switch(unit)
+ {
+ case mxConstants.POINTS:
+ return 'pt';
+ case mxConstants.INCHES:
+ return '"';
+ case mxConstants.MILLIMETERS:
+ return 'mm';
+ case mxConstants.METERS:
+ return 'm';
+ }
+};
+
+BaseFormatPanel.prototype.inUnit = function(pixels)
+{
+ return this.editorUi.editor.graph.view.formatUnitText(pixels);
+};
+
+BaseFormatPanel.prototype.fromUnit = function(value)
+{
+ var unit = this.editorUi.editor.graph.view.unit;
+
+ switch(unit)
+ {
+ case mxConstants.POINTS:
+ return value;
+ case mxConstants.INCHES:
+ return value * mxConstants.PIXELS_PER_INCH;
+ case mxConstants.MILLIMETERS:
+ return value * mxConstants.PIXELS_PER_MM;
+ case mxConstants.METERS:
+ return value * mxConstants.PIXELS_PER_MM * 1000;
+ }
+};
+
+BaseFormatPanel.prototype.isFloatUnit = function()
+{
+ return this.editorUi.editor.graph.view.unit != mxConstants.POINTS;
+};
+
+BaseFormatPanel.prototype.getUnitStep = function()
+{
+ var unit = this.editorUi.editor.graph.view.unit;
+
+ switch(unit)
+ {
+ case mxConstants.POINTS:
+ return 1;
+ case mxConstants.INCHES:
+ return 0.1;
+ case mxConstants.MILLIMETERS:
+ return 0.5;
+ case mxConstants.METERS:
+ return 0.001;
+ }
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addGeometry = function(container)
+{
+ var panel = this;
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var model = graph.getModel();
+ var rect = ui.getSelectionState();
+
+ var div = this.createPanel();
+ div.style.paddingBottom = '8px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '50px';
+ span.style.marginTop = '0px';
+ span.style.fontWeight = 'bold';
+ mxUtils.write(span, mxResources.get('size'));
+ div.appendChild(span);
+
+ var widthUpdate, heightUpdate, leftUpdate, topUpdate;
+ var width = this.addUnitInput(div, this.getUnit(), 87, 52, function()
+ {
+ widthUpdate.apply(this, arguments);
+ }, this.getUnitStep(), null, null, this.isFloatUnit());
+ var height = this.addUnitInput(div, this.getUnit(), 16, 52, function()
+ {
+ heightUpdate.apply(this, arguments);
+ }, this.getUnitStep(), null, null, this.isFloatUnit());
+
+ var autosizeBtn = document.createElement('div');
+ autosizeBtn.className = 'geSprite geSprite-fit';
+ autosizeBtn.setAttribute('title', mxResources.get('autosize') + ' (' + this.editorUi.actions.get('autosize').shortcut + ')');
+ autosizeBtn.style.position = 'relative';
+ autosizeBtn.style.cursor = 'pointer';
+ autosizeBtn.style.marginTop = '-3px';
+ autosizeBtn.style.border = '0px';
+ autosizeBtn.style.left = '42px';
+ mxUtils.setOpacity(autosizeBtn, 50);
+
+ mxEvent.addListener(autosizeBtn, 'mouseenter', function()
+ {
+ mxUtils.setOpacity(autosizeBtn, 100);
+ });
+
+ mxEvent.addListener(autosizeBtn, 'mouseleave', function()
+ {
+ mxUtils.setOpacity(autosizeBtn, 50);
+ });
+
+ mxEvent.addListener(autosizeBtn, 'click', function()
+ {
+ ui.actions.get('autosize').funct();
+ });
+
+ div.appendChild(autosizeBtn);
+
+ if (rect.row)
+ {
+ width.style.visibility = 'hidden';
+ width.nextSibling.style.visibility = 'hidden';
+ }
+ else
+ {
+ this.addLabel(div, mxResources.get('width'), 87, 64);
+ }
+
+ this.addLabel(div, mxResources.get('height'), 16, 64);
+ mxUtils.br(div);
+
+ var wrapper = document.createElement('div');
+ wrapper.style.paddingTop = '8px';
+ wrapper.style.paddingRight = '20px';
+ wrapper.style.whiteSpace = 'nowrap';
+ wrapper.style.textAlign = 'right';
+ var opt = this.createCellOption(mxResources.get('constrainProportions'),
+ mxConstants.STYLE_ASPECT, null, 'fixed', 'null');
+ opt.style.width = '210px';
+ wrapper.appendChild(opt);
+
+ if (!rect.cell && !rect.row)
+ {
+ div.appendChild(wrapper);
+ }
+ else
+ {
+ autosizeBtn.style.visibility = 'hidden';
+ }
+
+ var constrainCheckbox = opt.getElementsByTagName('input')[0];
+ this.addKeyHandler(width, listener);
+ this.addKeyHandler(height, listener);
+
+ widthUpdate = this.addGeometryHandler(width, function(geo, value, cell)
+ {
+ if (graph.isTableCell(cell))
+ {
+ graph.setTableColumnWidth(cell, value - geo.width, true);
+
+ // Blocks processing in caller
+ return true;
+ }
+ else if (geo.width > 0)
+ {
+ var value = Math.max(1, panel.fromUnit(value));
+
+ if (constrainCheckbox.checked)
+ {
+ geo.height = Math.round((geo.height * value * 100) / geo.width) / 100;
+ }
+
+ geo.width = value;
+ }
+ });
+ heightUpdate = this.addGeometryHandler(height, function(geo, value, cell)
+ {
+ if (graph.isTableCell(cell))
+ {
+ cell = model.getParent(cell);
+ }
+
+ if (graph.isTableRow(cell))
+ {
+ graph.setTableRowHeight(cell, value - geo.height);
+
+ // Blocks processing in caller
+ return true;
+ }
+ else if (geo.height > 0)
+ {
+ var value = Math.max(1, panel.fromUnit(value));
+
+ if (constrainCheckbox.checked)
+ {
+ geo.width = Math.round((geo.width * value * 100) / geo.height) / 100;
+ }
+
+ geo.height = value;
+ }
+ });
+
+ if (rect.resizable || rect.row || rect.cell)
+ {
+ container.appendChild(div);
+ }
+
+ var div2 = this.createPanel();
+ div2.style.paddingBottom = '30px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ span.style.fontWeight = 'bold';
+ mxUtils.write(span, mxResources.get('position'));
+ div2.appendChild(span);
+
+ var left = this.addUnitInput(div2, this.getUnit(), 87, 52, function()
+ {
+ leftUpdate.apply(this, arguments);
+ }, this.getUnitStep(), null, null, this.isFloatUnit());
+ var top = this.addUnitInput(div2, this.getUnit(), 16, 52, function()
+ {
+ topUpdate.apply(this, arguments);
+ }, this.getUnitStep(), null, null, this.isFloatUnit());
+
+ mxUtils.br(div2);
+
+ var coordinateLabels = true;
+ var dx = null;
+ var dy = null;
+
+ if (rect.movable)
+ {
+ if (rect.edges.length == 0 && rect.vertices.length == 1)
+ {
+ var geo = graph.getCellGeometry(rect.vertices[0]);
+
+ if (geo != null && geo.relative)
+ {
+ mxUtils.br(div2);
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ mxUtils.write(span, mxResources.get('relative'));
+ div2.appendChild(span);
+
+ dx = this.addGenericInput(div2, ' %', 87, 52, function()
+ {
+ return (Math.round(geo.x * 1000) / 10);
+ }, function(value)
+ {
+ value = parseFloat(value);
+
+ if (!isNaN(value))
+ {
+ model.beginUpdate();
+ try
+ {
+ geo = geo.clone();
+ geo.x = parseFloat(value) / 100;
+ model.setGeometry(rect.vertices[0], geo);
+ }
+ finally
+ {
+ model.endUpdate();
+ }
+ }
+ });
+
+ if (model.isEdge(model.getParent(rect.vertices[0])))
+ {
+ coordinateLabels = false;
+ var dyUpdate = null;
+
+ dy = this.addUnitInput(div2, this.getUnit(), 16, 52, function()
+ {
+ dyUpdate.apply(this, arguments);
+ });
+
+ dyUpdate = this.addGeometryHandler(dy, function(geo, value)
+ {
+ console.log('value', value);
+
+ geo.y = panel.fromUnit(value);
+ });
+ }
+ else
+ {
+ dy = this.addGenericInput(div2, ' %', 16, 52, function()
+ {
+ return (Math.round(geo.y * 1000) / 10);
+ }, function(value)
+ {
+ value = parseFloat(value);
+
+ if (!isNaN(value))
+ {
+ model.beginUpdate();
+ try
+ {
+ geo = geo.clone();
+ geo.y = parseFloat(value) / 100;
+ model.setGeometry(rect.vertices[0], geo);
+ }
+ finally
+ {
+ model.endUpdate();
+ }
+ }
+ });
+ }
+
+ mxUtils.br(div2);
+ }
+ }
+ container.appendChild(div2);
+ }
+
+ this.addLabel(div2, mxResources.get(coordinateLabels ? 'left' : 'line'), 87, 64).style.marginTop = '8px';
+ this.addLabel(div2, mxResources.get(coordinateLabels ? 'top' : 'orthogonal'), 16, 64).style.marginTop = '8px';
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ rect = ui.getSelectionState();
+
+ if (!rect.containsLabel && rect.vertices.length == graph.getSelectionCount() &&
+ rect.width != null && rect.height != null)
+ {
+ div.style.display = '';
+
+ if (force || document.activeElement != width)
+ {
+ width.value = this.inUnit(rect.width) + ' ' + this.getUnit();
+ }
+
+ if (force || document.activeElement != height)
+ {
+ height.value = this.inUnit(rect.height) + ' ' + this.getUnit();
+ }
+ }
+ else
+ {
+ div.style.display = 'none';
+ }
+
+ if (rect.vertices.length == graph.getSelectionCount() &&
+ rect.vertices.length > 0 && rect.x != null &&
+ rect.y != null)
+ {
+ var geo = graph.getCellGeometry(rect.vertices[0]);
+ div2.style.display = '';
+
+ if (force || document.activeElement != left)
+ {
+ left.value = this.inUnit(rect.x) + ' ' + this.getUnit();
+ }
+
+ if (force || document.activeElement != top)
+ {
+ top.value = this.inUnit(rect.y) + ' ' + this.getUnit();
+ }
+
+ if (geo != null && geo.relative)
+ {
+ if (dx != null && (force || document.activeElement != dx))
+ {
+ dx.value = (Math.round(geo.x * 1000) / 10) + ' %';
+ }
+
+ if (dy != null && (force || document.activeElement != dy))
+ {
+ if (model.isEdge(model.getParent(rect.vertices[0])))
+ {
+ dy.value = this.inUnit(geo.y) + ' ' + this.getUnit();
+ }
+ else
+ {
+ dy.value = (Math.round(geo.y * 1000) / 10) + ' %';
+ }
+ }
+ }
+ }
+ else
+ {
+ div2.style.display = 'none';
+ }
+ });
+
+ this.listeners.push({destroy: function() { model.removeListener(listener); }});
+ model.addListener(mxEvent.CHANGE, listener);
+ this.addKeyHandler(left, listener);
+ this.addKeyHandler(top, listener);
+ listener();
+
+ leftUpdate = this.addGeometryHandler(left, function(geo, value)
+ {
+ value = panel.fromUnit(value);
+
+ if (geo.relative)
+ {
+ geo.offset.x = value;
+ }
+ else
+ {
+ geo.x = value;
+ }
+ });
+ topUpdate = this.addGeometryHandler(top, function(geo, value)
+ {
+ value = panel.fromUnit(value);
+
+ if (geo.relative)
+ {
+ geo.offset.y = value;
+ }
+ else
+ {
+ geo.y = value;
+ }
+ });
+
+ if (rect.movable)
+ {
+ if (rect.edges.length == 0 && rect.vertices.length == 1 &&
+ model.isEdge(model.getParent(rect.vertices[0])))
+ {
+ var geo = graph.getCellGeometry(rect.vertices[0]);
+
+ if (geo != null && geo.relative)
+ {
+ var btn = mxUtils.button(mxResources.get('center'), mxUtils.bind(this, function(evt)
+ {
+ model.beginUpdate();
+ try
+ {
+ geo = geo.clone();
+ geo.x = 0;
+ geo.y = 0;
+ geo.offset = new mxPoint();
+ model.setGeometry(rect.vertices[0], geo);
+ }
+ finally
+ {
+ model.endUpdate();
+ }
+ }));
+
+ btn.setAttribute('title', mxResources.get('center'));
+ btn.style.width = '134px';
+ btn.style.left = '89px';
+ btn.style.position = 'absolute';
+ mxUtils.br(div2);
+ mxUtils.br(div2);
+ div2.appendChild(btn);
+ }
+ }
+ container.appendChild(div2);
+ }
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addGeometryHandler = function(input, fn)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var initialValue = null;
+ var panel = this;
+
+ function update(evt)
+ {
+ if (input.value != '')
+ {
+ var value = parseFloat(input.value);
+
+ if (isNaN(value))
+ {
+ input.value = initialValue + ' ' + panel.getUnit();
+ }
+ else if (value != initialValue)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = ui.getSelectionState().cells;
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (graph.getModel().isVertex(cells[i]))
+ {
+ var geo = graph.getCellGeometry(cells[i]);
+
+ if (geo != null)
+ {
+ geo = geo.clone();
+
+ if (!fn(geo, value, cells[i]))
+ {
+ var state = graph.view.getState(cells[i]);
+
+ if (state != null && graph.isRecursiveVertexResize(state))
+ {
+ graph.resizeChildCells(cells[i], geo);
+ }
+
+ graph.getModel().setGeometry(cells[i], geo);
+ graph.constrainChildCells(cells[i]);
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ initialValue = value;
+ input.value = value + ' ' + panel.getUnit();
+ }
+ }
+
+ mxEvent.consume(evt);
+ };
+
+ mxEvent.addListener(input, 'blur', update);
+ mxEvent.addListener(input, 'change', update);
+ mxEvent.addListener(input, 'focus', function()
+ {
+ initialValue = input.value;
+ });
+
+ return update;
+};
+
+ArrangePanel.prototype.addEdgeGeometryHandler = function(input, fn)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var initialValue = null;
+
+ function update(evt)
+ {
+ if (input.value != '')
+ {
+ var value = parseFloat(input.value);
+
+ if (isNaN(value))
+ {
+ input.value = initialValue + ' pt';
+ }
+ else if (value != initialValue)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = ui.getSelectionState().cells;
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ if (graph.getModel().isEdge(cells[i]))
+ {
+ var geo = graph.getCellGeometry(cells[i]);
+
+ if (geo != null)
+ {
+ geo = geo.clone();
+ fn(geo, value);
+
+ graph.getModel().setGeometry(cells[i], geo);
+ }
+ }
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ initialValue = value;
+ input.value = value + ' pt';
+ }
+ }
+
+ mxEvent.consume(evt);
+ };
+
+ mxEvent.addListener(input, 'blur', update);
+ mxEvent.addListener(input, 'change', update);
+ mxEvent.addListener(input, 'focus', function()
+ {
+ initialValue = input.value;
+ });
+
+ return update;
+};
+
+/**
+ *
+ */
+ArrangePanel.prototype.addEdgeGeometry = function(container)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var rect = ui.getSelectionState();
+ var div = this.createPanel();
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ span.style.fontWeight = 'bold';
+ mxUtils.write(span, mxResources.get('width'));
+ div.appendChild(span);
+
+ var widthUpdate, xtUpdate, ytUpdate, xsUpdate, ysUpdate;
+ var width = this.addUnitInput(div, 'pt', 12, 44, function()
+ {
+ widthUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(div);
+ this.addKeyHandler(width, listener);
+
+ var widthUpdate = mxUtils.bind(this, function(evt)
+ {
+ // Maximum stroke width is 999
+ var value = parseInt(width.value);
+ value = Math.min(999, Math.max(1, (isNaN(value)) ? 1 : value));
+
+ if (value != mxUtils.getValue(rect.style, 'width', mxCellRenderer.defaultShapes['flexArrow'].prototype.defaultWidth))
+ {
+ var cells = ui.getSelectionState().cells;
+ graph.setCellStyles('width', value, cells);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['width'],
+ 'values', [value], 'cells', cells));
+ }
+
+ width.value = value + ' pt';
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(width, 'blur', widthUpdate);
+ mxEvent.addListener(width, 'change', widthUpdate);
+
+ container.appendChild(div);
+
+ var divs = this.createPanel();
+ divs.style.paddingBottom = '30px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ mxUtils.write(span, mxResources.get('linestart'));
+ divs.appendChild(span);
+
+ var xs = this.addUnitInput(divs, 'pt', 87, 52, function()
+ {
+ xsUpdate.apply(this, arguments);
+ });
+ var ys = this.addUnitInput(divs, 'pt', 16, 52, function()
+ {
+ ysUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(divs);
+ this.addLabel(divs, mxResources.get('left'), 87, 64);
+ this.addLabel(divs, mxResources.get('top'), 16, 64);
+ container.appendChild(divs);
+ this.addKeyHandler(xs, listener);
+ this.addKeyHandler(ys, listener);
+
+ var divt = this.createPanel();
+ divt.style.paddingBottom = '30px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ mxUtils.write(span, mxResources.get('lineend'));
+ divt.appendChild(span);
+
+ var xt = this.addUnitInput(divt, 'pt', 87, 52, function()
+ {
+ xtUpdate.apply(this, arguments);
+ });
+ var yt = this.addUnitInput(divt, 'pt', 16, 52, function()
+ {
+ ytUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(divt);
+ this.addLabel(divt, mxResources.get('left'), 87, 64);
+ this.addLabel(divt, mxResources.get('top'), 16, 64);
+ container.appendChild(divt);
+ this.addKeyHandler(xt, listener);
+ this.addKeyHandler(yt, listener);
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ rect = ui.getSelectionState();
+ var cell = rect.cells[0];
+
+ if (rect.style.shape == 'link' || rect.style.shape == 'flexArrow')
+ {
+ div.style.display = '';
+
+ if (force || document.activeElement != width)
+ {
+ var value = mxUtils.getValue(rect.style, 'width',
+ mxCellRenderer.defaultShapes['flexArrow'].prototype.defaultWidth);
+ width.value = value + ' pt';
+ }
+ }
+ else
+ {
+ div.style.display = 'none';
+ }
+
+ if (rect.cells.length == 1 && graph.model.isEdge(cell))
+ {
+ var geo = graph.model.getGeometry(cell);
+
+ if (geo != null && geo.sourcePoint != null &&
+ graph.model.getTerminal(cell, true) == null)
+ {
+ xs.value = geo.sourcePoint.x;
+ ys.value = geo.sourcePoint.y;
+ }
+ else
+ {
+ divs.style.display = 'none';
+ }
+
+ if (geo != null && geo.targetPoint != null &&
+ graph.model.getTerminal(cell, false) == null)
+ {
+ xt.value = geo.targetPoint.x;
+ yt.value = geo.targetPoint.y;
+ }
+ else
+ {
+ divt.style.display = 'none';
+ }
+ }
+ else
+ {
+ divs.style.display = 'none';
+ divt.style.display = 'none';
+ }
+ });
+
+ xsUpdate = this.addEdgeGeometryHandler(xs, function(geo, value)
+ {
+ geo.sourcePoint.x = value;
+ });
+
+ ysUpdate = this.addEdgeGeometryHandler(ys, function(geo, value)
+ {
+ geo.sourcePoint.y = value;
+ });
+
+ xtUpdate = this.addEdgeGeometryHandler(xt, function(geo, value)
+ {
+ geo.targetPoint.x = value;
+ });
+
+ ytUpdate = this.addEdgeGeometryHandler(yt, function(geo, value)
+ {
+ geo.targetPoint.y = value;
+ });
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+TextFormatPanel = function(format, editorUi, container)
+{
+ BaseFormatPanel.call(this, format, editorUi, container);
+ this.init();
+};
+
+mxUtils.extend(TextFormatPanel, BaseFormatPanel);
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+TextFormatPanel.prototype.init = function()
+{
+ this.container.style.borderBottom = 'none';
+ this.addFont(this.container);
+
+ // Allows to lock/unload button to be added
+ this.container.appendChild(this.addFontOps(this.createPanel()));
+};
+
+
+/**
+ *
+ */
+TextFormatPanel.prototype.addFontOps = function(div)
+{
+ var ui = this.editorUi;
+ div.style.paddingTop = '8px';
+ div.style.paddingBottom = '6px';
+
+ var count = this.addActions(div, ['removeFormat']);
+
+ if (count == 0)
+ {
+ div.style.display = 'none';
+ }
+
+ return div;
+};
+
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+TextFormatPanel.prototype.addFont = function(container)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var ss = ui.getSelectionState();
+
+ var title = this.createTitle(mxResources.get('font'));
+ title.style.paddingLeft = '14px';
+ title.style.paddingTop = '10px';
+ title.style.paddingBottom = '6px';
+ container.appendChild(title);
+
+ var stylePanel = this.createPanel();
+ stylePanel.style.paddingTop = '2px';
+ stylePanel.style.paddingBottom = '2px';
+ stylePanel.style.position = 'relative';
+ stylePanel.style.marginLeft = '-2px';
+ stylePanel.style.borderWidth = '0px';
+ stylePanel.className = 'geToolbarContainer';
+
+ if (graph.cellEditor.isContentEditing())
+ {
+ var cssPanel = stylePanel.cloneNode();
+
+ var cssMenu = this.editorUi.toolbar.addMenu(mxResources.get('style'),
+ mxResources.get('style'), true, 'formatBlock', cssPanel, null, true);
+ this.addArrow(cssMenu);
+ cssMenu.style.width = '211px';
+ cssMenu.style.alignItems = 'center';
+ cssMenu.style.justifyContent = 'center';
+ cssMenu.style.whiteSpace = 'nowrap';
+ cssMenu.style.overflow = 'hidden';
+ cssMenu.style.margin = '0px';
+ cssMenu.style.position = 'relative';
+
+ var arrow = cssMenu.getElementsByTagName('div')[0];
+ arrow.style.position = 'absolute';
+ arrow.style.right = '2px';
+ container.appendChild(cssPanel);
+ }
+
+ container.appendChild(stylePanel);
+
+ var colorPanel = this.createPanel();
+ colorPanel.style.marginTop = '8px';
+ colorPanel.style.borderWidth = '1px';
+ colorPanel.style.borderStyle = 'solid';
+ colorPanel.style.paddingTop = '6px';
+ colorPanel.style.paddingBottom = '2px';
+
+ var fontMenu = this.editorUi.toolbar.addMenu('Helvetica', mxResources.get('fontFamily'),
+ true, 'fontFamily', stylePanel, null, true);
+
+ this.addArrow(fontMenu);
+ fontMenu.style.width = '211px';
+ fontMenu.style.alignItems = 'center';
+ fontMenu.style.justifyContent = 'center';
+ fontMenu.style.whiteSpace = 'nowrap';
+ fontMenu.style.overflow = 'hidden';
+ fontMenu.style.margin = '0px';
+ fontMenu.style.position = 'relative';
+
+ var arrow = fontMenu.getElementsByTagName('div')[0];
+ arrow.style.position = 'absolute';
+ arrow.style.right = '2px';
+
+ var stylePanel2 = stylePanel.cloneNode(false);
+ stylePanel2.style.marginLeft = '-3px';
+ var fontStyleItems = this.editorUi.toolbar.addItems(['bold', 'italic', 'underline'], stylePanel2, true);
+ fontStyleItems[0].setAttribute('title', mxResources.get('bold') + ' (' + this.editorUi.actions.get('bold').shortcut + ')');
+ fontStyleItems[1].setAttribute('title', mxResources.get('italic') + ' (' + this.editorUi.actions.get('italic').shortcut + ')');
+ fontStyleItems[2].setAttribute('title', mxResources.get('underline') + ' (' + this.editorUi.actions.get('underline').shortcut + ')');
+
+ var verticalItem = this.editorUi.toolbar.addItems(['vertical'], stylePanel2, true)[0];
+
+ container.appendChild(stylePanel2);
+
+ this.styleButtons(fontStyleItems);
+ this.styleButtons([verticalItem]);
+
+ var stylePanel3 = stylePanel.cloneNode(false);
+ stylePanel3.style.marginLeft = '-3px';
+ stylePanel3.style.paddingBottom = '0px';
+
+ // Helper function to return a wrapper function does not pass any arguments
+ var callFn = function(fn)
+ {
+ return function()
+ {
+ return fn();
+ };
+ };
+
+ var left = this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'),
+ (graph.cellEditor.isContentEditing()) ?
+ function(evt)
+ {
+ graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt);
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_ALIGN],
+ 'values', [mxConstants.ALIGN_LEFT],
+ 'cells', ss.cells));
+ } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_LEFT])), stylePanel3);
+ var center = this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'),
+ (graph.cellEditor.isContentEditing()) ?
+ function(evt)
+ {
+ graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt);
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_ALIGN],
+ 'values', [mxConstants.ALIGN_CENTER],
+ 'cells', ss.cells));
+ } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_CENTER])), stylePanel3);
+ var right = this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'),
+ (graph.cellEditor.isContentEditing()) ?
+ function(evt)
+ {
+ graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt);
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_ALIGN],
+ 'values', [mxConstants.ALIGN_RIGHT],
+ 'cells', ss.cells));
+ } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_RIGHT])), stylePanel3);
+
+ this.styleButtons([left, center, right]);
+
+ // Quick hack for strikethrough
+ // TODO: Add translations and toggle state
+ if (graph.cellEditor.isContentEditing())
+ {
+ var strike = this.editorUi.toolbar.addButton('geSprite-removeformat', mxResources.get('strikethrough'),
+ function()
+ {
+ document.execCommand('strikeThrough', false, null);
+ }, stylePanel2);
+ this.styleButtons([strike]);
+
+ strike.firstChild.style.background = 'url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjR2MjRIMFYweiIvPjwvZGVmcz48Y2xpcFBhdGggaWQ9ImIiPjx1c2UgeGxpbms6aHJlZj0iI2EiIG92ZXJmbG93PSJ2aXNpYmxlIi8+PC9jbGlwUGF0aD48cGF0aCBjbGlwLXBhdGg9InVybCgjYikiIGZpbGw9IiMwMTAxMDEiIGQ9Ik03LjI0IDguNzVjLS4yNi0uNDgtLjM5LTEuMDMtLjM5LTEuNjcgMC0uNjEuMTMtMS4xNi40LTEuNjcuMjYtLjUuNjMtLjkzIDEuMTEtMS4yOS40OC0uMzUgMS4wNS0uNjMgMS43LS44My42Ni0uMTkgMS4zOS0uMjkgMi4xOC0uMjkuODEgMCAxLjU0LjExIDIuMjEuMzQuNjYuMjIgMS4yMy41NCAxLjY5Ljk0LjQ3LjQuODMuODggMS4wOCAxLjQzLjI1LjU1LjM4IDEuMTUuMzggMS44MWgtMy4wMWMwLS4zMS0uMDUtLjU5LS4xNS0uODUtLjA5LS4yNy0uMjQtLjQ5LS40NC0uNjgtLjItLjE5LS40NS0uMzMtLjc1LS40NC0uMy0uMS0uNjYtLjE2LTEuMDYtLjE2LS4zOSAwLS43NC4wNC0xLjAzLjEzLS4yOS4wOS0uNTMuMjEtLjcyLjM2LS4xOS4xNi0uMzQuMzQtLjQ0LjU1LS4xLjIxLS4xNS40My0uMTUuNjYgMCAuNDguMjUuODguNzQgMS4yMS4zOC4yNS43Ny40OCAxLjQxLjdINy4zOWMtLjA1LS4wOC0uMTEtLjE3LS4xNS0uMjV6TTIxIDEydi0ySDN2Mmg5LjYyYy4xOC4wNy40LjE0LjU1LjIuMzcuMTcuNjYuMzQuODcuNTEuMjEuMTcuMzUuMzYuNDMuNTcuMDcuMi4xMS40My4xMS42OSAwIC4yMy0uMDUuNDUtLjE0LjY2LS4wOS4yLS4yMy4zOC0uNDIuNTMtLjE5LjE1LS40Mi4yNi0uNzEuMzUtLjI5LjA4LS42My4xMy0xLjAxLjEzLS40MyAwLS44My0uMDQtMS4xOC0uMTNzLS42Ni0uMjMtLjkxLS40MmMtLjI1LS4xOS0uNDUtLjQ0LS41OS0uNzUtLjE0LS4zMS0uMjUtLjc2LS4yNS0xLjIxSDYuNGMwIC41NS4wOCAxLjEzLjI0IDEuNTguMTYuNDUuMzcuODUuNjUgMS4yMS4yOC4zNS42LjY2Ljk4LjkyLjM3LjI2Ljc4LjQ4IDEuMjIuNjUuNDQuMTcuOS4zIDEuMzguMzkuNDguMDguOTYuMTMgMS40NC4xMy44IDAgMS41My0uMDkgMi4xOC0uMjhzMS4yMS0uNDUgMS42Ny0uNzljLjQ2LS4zNC44Mi0uNzcgMS4wNy0xLjI3cy4zOC0xLjA3LjM4LTEuNzFjMC0uNi0uMS0xLjE0LS4zMS0xLjYxLS4wNS0uMTEtLjExLS4yMy0uMTctLjMzSDIxeiIvPjwvc3ZnPg==)';
+ strike.firstChild.style.backgroundPosition = '2px 2px';
+ strike.firstChild.style.backgroundSize = '18px 18px';
+
+ this.styleButtons([strike]);
+ }
+
+ var top = this.editorUi.toolbar.addButton('geSprite-top', mxResources.get('top'),
+ callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN],
+ [mxConstants.ALIGN_TOP])), stylePanel3);
+ var middle = this.editorUi.toolbar.addButton('geSprite-middle', mxResources.get('middle'),
+ callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN],
+ [mxConstants.ALIGN_MIDDLE])), stylePanel3);
+ var bottom = this.editorUi.toolbar.addButton('geSprite-bottom', mxResources.get('bottom'),
+ callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN],
+ [mxConstants.ALIGN_BOTTOM])), stylePanel3);
+
+ this.styleButtons([top, middle, bottom]);
+
+ container.appendChild(stylePanel3);
+
+ // Hack for updating UI state below based on current text selection
+ // currentTable is the current selected DOM table updated below
+ var sub, sup, full, tableWrapper, currentTable, tableCell, tableRow;
+
+ if (graph.cellEditor.isContentEditing())
+ {
+ top.style.display = 'none';
+ middle.style.display = 'none';
+ bottom.style.display = 'none';
+ verticalItem.style.display = 'none';
+
+ full = this.editorUi.toolbar.addButton('geSprite-justifyfull', mxResources.get('block'),
+ function()
+ {
+ if (full.style.opacity == 1)
+ {
+ document.execCommand('justifyfull', false, null);
+ }
+ }, stylePanel3);
+ full.style.marginRight = '9px';
+ full.style.opacity = 1;
+
+ this.styleButtons([full,
+ sub = this.editorUi.toolbar.addButton('geSprite-subscript',
+ mxResources.get('subscript') + ' (' + Editor.ctrlKey + '+,)',
+ function()
+ {
+ document.execCommand('subscript', false, null);
+ }, stylePanel3), sup = this.editorUi.toolbar.addButton('geSprite-superscript',
+ mxResources.get('superscript') + ' (' + Editor.ctrlKey + '+.)',
+ function()
+ {
+ document.execCommand('superscript', false, null);
+ }, stylePanel3)]);
+ sub.style.marginLeft = '10px';
+
+ var tmp = stylePanel3.cloneNode(false);
+ tmp.style.paddingTop = '4px';
+ var btns = [this.editorUi.toolbar.addButton('geSprite-orderedlist', mxResources.get('numberedList'),
+ function()
+ {
+ document.execCommand('insertorderedlist', false, null);
+ }, tmp),
+ this.editorUi.toolbar.addButton('geSprite-unorderedlist', mxResources.get('bulletedList'),
+ function()
+ {
+ document.execCommand('insertunorderedlist', false, null);
+ }, tmp),
+ this.editorUi.toolbar.addButton('geSprite-outdent', mxResources.get('decreaseIndent'),
+ function()
+ {
+ document.execCommand('outdent', false, null);
+ }, tmp),
+ this.editorUi.toolbar.addButton('geSprite-indent', mxResources.get('increaseIndent'),
+ function()
+ {
+ document.execCommand('indent', false, null);
+ }, tmp),
+ this.editorUi.toolbar.addButton('geSprite-removeformat', mxResources.get('removeFormat'),
+ function()
+ {
+ document.execCommand('removeformat', false, null);
+ }, tmp),
+ this.editorUi.toolbar.addButton('geSprite-code', mxResources.get('html'),
+ function()
+ {
+ graph.cellEditor.toggleViewMode();
+ }, tmp)];
+ this.styleButtons(btns);
+ btns[btns.length - 2].style.marginLeft = '10px';
+
+ container.appendChild(tmp);
+ }
+ else
+ {
+ fontStyleItems[2].style.marginRight = '12px';
+ right.style.marginRight = '12px';
+ }
+
+ // Label position
+ var stylePanel4 = stylePanel.cloneNode(false);
+ stylePanel4.removeAttribute('class');
+ stylePanel4.style.marginLeft = '0px';
+ stylePanel4.style.paddingTop = '8px';
+ stylePanel4.style.paddingBottom = '4px';
+ stylePanel4.style.fontWeight = 'normal';
+
+ mxUtils.write(stylePanel4, mxResources.get('position'));
+
+ // Adds label position options
+ var positionSelect = document.createElement('select');
+ positionSelect.style.position = 'absolute';
+ positionSelect.style.left = '126px';
+ positionSelect.style.width = '98px';
+ positionSelect.style.borderWidth = '1px';
+ positionSelect.style.borderStyle = 'solid';
+ positionSelect.style.marginTop = '-3px';
+
+ var directions = ['topLeft', 'top', 'topRight', 'left', 'center', 'right', 'bottomLeft', 'bottom', 'bottomRight'];
+ var lset = {'topLeft': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_TOP, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_BOTTOM],
+ 'top': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_TOP, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_BOTTOM],
+ 'topRight': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_TOP, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM],
+ 'left': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_MIDDLE],
+ 'center': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE],
+ 'right': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE],
+ 'bottomLeft': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_TOP],
+ 'bottom': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_TOP],
+ 'bottomRight': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_TOP]};
+
+ for (var i = 0; i < directions.length; i++)
+ {
+ var positionOption = document.createElement('option');
+ positionOption.setAttribute('value', directions[i]);
+ mxUtils.write(positionOption, mxResources.get(directions[i]));
+ positionSelect.appendChild(positionOption);
+ }
+
+ stylePanel4.appendChild(positionSelect);
+
+ // Writing direction
+ var stylePanel5 = stylePanel.cloneNode(false);
+ stylePanel5.removeAttribute('class');
+ stylePanel5.style.marginLeft = '0px';
+ stylePanel5.style.paddingTop = '4px';
+ stylePanel5.style.paddingBottom = '4px';
+ stylePanel5.style.fontWeight = 'normal';
+
+ mxUtils.write(stylePanel5, mxResources.get('writingDirection'));
+
+ // Adds writing direction options
+ // LATER: Handle reselect of same option in all selects (change event
+ // is not fired for same option so have opened state on click) and
+ // handle multiple different styles for current selection
+ var dirSelect = document.createElement('select');
+ dirSelect.style.position = 'absolute';
+ dirSelect.style.borderWidth = '1px';
+ dirSelect.style.borderStyle = 'solid';
+ dirSelect.style.left = '126px';
+ dirSelect.style.width = '98px';
+ dirSelect.style.marginTop = '-3px';
+
+ // NOTE: For automatic we use the value null since automatic
+ // requires the text to be non formatted and non-wrapped
+ var dirs = ['automatic', 'leftToRight', 'rightToLeft'];
+ var dirSet = {'automatic': null,
+ 'leftToRight': mxConstants.TEXT_DIRECTION_LTR,
+ 'rightToLeft': mxConstants.TEXT_DIRECTION_RTL};
+
+ for (var i = 0; i < dirs.length; i++)
+ {
+ var dirOption = document.createElement('option');
+ dirOption.setAttribute('value', dirs[i]);
+ mxUtils.write(dirOption, mxResources.get(dirs[i]));
+ dirSelect.appendChild(dirOption);
+ }
+
+ stylePanel5.appendChild(dirSelect);
+
+ if (!graph.isEditing())
+ {
+ container.appendChild(stylePanel4);
+
+ mxEvent.addListener(positionSelect, 'change', function(evt)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var vals = lset[positionSelect.value];
+
+ if (vals != null)
+ {
+ graph.setCellStyles(mxConstants.STYLE_LABEL_POSITION, vals[0], ss.cells);
+ graph.setCellStyles(mxConstants.STYLE_VERTICAL_LABEL_POSITION, vals[1], ss.cells);
+ graph.setCellStyles(mxConstants.STYLE_ALIGN, vals[2], ss.cells);
+ graph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, vals[3], ss.cells);
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ // LATER: Update dir in text editor while editing and update style with label
+ // NOTE: The tricky part is handling and passing on the auto value
+ container.appendChild(stylePanel5);
+
+ mxEvent.addListener(dirSelect, 'change', function(evt)
+ {
+ graph.setCellStyles(mxConstants.STYLE_TEXT_DIRECTION, dirSet[dirSelect.value], ss.cells);
+ mxEvent.consume(evt);
+ });
+ }
+
+ // Fontsize
+ var input = document.createElement('input');
+ input.style.position = 'absolute';
+ input.style.borderWidth = '1px';
+ input.style.borderStyle = 'solid';
+ input.style.textAlign = 'right';
+ input.style.marginTop = '4px';
+ input.style.left = '161px';
+ input.style.width = '53px';
+ input.style.height = '23px';
+ input.style.boxSizing = 'border-box';
+ stylePanel2.appendChild(input);
+
+ // Workaround for font size 4 if no text is selected is update font size below
+ // after first character was entered (as the font element is lazy created)
+ var pendingFontSize = null;
+
+ var inputUpdate = this.installInputHandler(input, mxConstants.STYLE_FONTSIZE, Menus.prototype.defaultFontSize, 1, 999, ' pt',
+ function(fontSize)
+ {
+ // IE does not support containsNode
+ // KNOWN: Fixes font size issues but bypasses undo
+ if (window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11)
+ {
+ var selection = window.getSelection();
+ var container = (selection.rangeCount > 0) ? selection.getRangeAt(0).commonAncestorContainer :
+ graph.cellEditor.textarea;
+
+ function updateSize(elt, ignoreContains)
+ {
+ if (graph.cellEditor.textarea != null && elt != graph.cellEditor.textarea &&
+ graph.cellEditor.textarea.contains(elt) &&
+ (ignoreContains || selection.containsNode(elt, true)))
+ {
+ if (elt.nodeName == 'FONT')
+ {
+ elt.removeAttribute('size');
+ elt.style.fontSize = fontSize + 'px';
+ }
+ else
+ {
+ var css = mxUtils.getCurrentStyle(elt);
+
+ if (css.fontSize != fontSize + 'px')
+ {
+ if (mxUtils.getCurrentStyle(elt.parentNode).fontSize != fontSize + 'px')
+ {
+ elt.style.fontSize = fontSize + 'px';
+ }
+ else
+ {
+ elt.style.fontSize = '';
+ }
+ }
+ }
+ }
+
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_FONTSIZE],
+ 'values', [fontSize], 'cells', ss.cells));
+ };
+
+ // Wraps text node or mixed selection with leading text in a font element
+ if (container == graph.cellEditor.textarea ||
+ container.nodeType != mxConstants.NODETYPE_ELEMENT)
+ {
+ document.execCommand('fontSize', false, '1');
+ }
+
+ if (container != graph.cellEditor.textarea)
+ {
+ container = container.parentNode;
+ }
+
+ if (container != null && container.nodeType == mxConstants.NODETYPE_ELEMENT)
+ {
+ var elts = container.getElementsByTagName('*');
+ updateSize(container);
+
+ for (var i = 0; i < elts.length; i++)
+ {
+ updateSize(elts[i]);
+ }
+ }
+
+ input.value = fontSize + ' pt';
+ }
+ else if (window.getSelection || document.selection)
+ {
+ // Checks selection
+ var par = null;
+
+ if (document.selection)
+ {
+ par = document.selection.createRange().parentElement();
+ }
+ else
+ {
+ var selection = window.getSelection();
+
+ if (selection.rangeCount > 0)
+ {
+ par = selection.getRangeAt(0).commonAncestorContainer;
+ }
+ }
+
+ // Node.contains does not work for text nodes in IE11
+ function isOrContains(container, node)
+ {
+ while (node != null)
+ {
+ if (node === container)
+ {
+ return true;
+ }
+
+ node = node.parentNode;
+ }
+
+ return false;
+ };
+
+ if (par != null && isOrContains(graph.cellEditor.textarea, par))
+ {
+ pendingFontSize = fontSize;
+
+ // Workaround for can't set font size in px is to change font size afterwards
+ document.execCommand('fontSize', false, '4');
+ var elts = graph.cellEditor.textarea.getElementsByTagName('font');
+
+ for (var i = 0; i < elts.length; i++)
+ {
+ if (elts[i].getAttribute('size') == '4')
+ {
+ elts[i].removeAttribute('size');
+ elts[i].style.fontSize = pendingFontSize + 'px';
+
+ // Overrides fontSize in input with the one just assigned as a workaround
+ // for potential fontSize values of parent elements that don't match
+ window.setTimeout(function()
+ {
+ input.value = pendingFontSize + ' pt';
+ pendingFontSize = null;
+ }, 0);
+
+ break;
+ }
+ }
+ }
+ }
+ }, true);
+
+ var stepper = this.createStepper(input, inputUpdate, 1, 10, true, Menus.prototype.defaultFontSize);
+ stepper.style.display = input.style.display;
+ stepper.style.marginTop = '4px';
+ stepper.style.left = '214px';
+
+ stylePanel2.appendChild(stepper);
+
+ var arrow = fontMenu.getElementsByTagName('div')[0];
+ arrow.style.cssFloat = 'right';
+
+ var bgColorApply = null;
+ var currentBgColor = graph.shapeBackgroundColor;
+
+ var fontColorApply = null;
+ var currentFontColor = graph.shapeForegroundColor;
+
+ var bgPanel = (graph.cellEditor.isContentEditing()) ? this.createColorOption(mxResources.get('backgroundColor'), function()
+ {
+ return currentBgColor;
+ }, function(color)
+ {
+ document.execCommand('backcolor', false, (color != mxConstants.NONE) ? color : 'transparent');
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR],
+ 'values', [color], 'cells', ss.cells));
+ }, graph.shapeBackgroundColor,
+ {
+ install: function(apply) { bgColorApply = apply; },
+ destroy: function() { bgColorApply = null; }
+ }, null, true) : this.createCellColorOption(mxResources.get('backgroundColor'),
+ mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, 'default', null, function(color)
+ {
+ graph.updateLabelElements(ss.cells, function(elt)
+ {
+ elt.style.backgroundColor = null;
+ });
+ }, graph.shapeBackgroundColor);
+ bgPanel.style.fontWeight = 'bold';
+
+ var borderPanel = this.createCellColorOption(mxResources.get('borderColor'),
+ mxConstants.STYLE_LABEL_BORDERCOLOR, 'default', null, null,
+ graph.shapeForegroundColor);
+ borderPanel.style.fontWeight = 'bold';
+
+ var defs = (ss.vertices.length >= 1) ?
+ graph.stylesheet.getDefaultVertexStyle() :
+ graph.stylesheet.getDefaultEdgeStyle();
+
+ var panel = (graph.cellEditor.isContentEditing()) ? this.createColorOption(mxResources.get('fontColor'), function()
+ {
+ return currentFontColor;
+ }, function(color)
+ {
+ if (mxClient.IS_FF)
+ {
+ // Workaround for Firefox that adds the font element around
+ // anchor elements which ignore inherited colors is to move
+ // the font element inside anchor elements
+ var tmp = graph.cellEditor.textarea.getElementsByTagName('font');
+ var oldFonts = [];
+
+ for (var i = 0; i < tmp.length; i++)
+ {
+ oldFonts.push(
+ {
+ node: tmp[i],
+ color: tmp[i].getAttribute('color')
+ });
+ }
+
+ document.execCommand('forecolor', false, (color != mxConstants.NONE) ?
+ color : 'transparent');
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_FONTCOLOR],
+ 'values', [color], 'cells', ss.cells));
+
+ // Finds the new or changed font element
+ var newFonts = graph.cellEditor.textarea.getElementsByTagName('font');
+
+ for (var i = 0; i < newFonts.length; i++)
+ {
+ if (i >= oldFonts.length || newFonts[i] != oldFonts[i].node ||
+ (newFonts[i] == oldFonts[i].node &&
+ newFonts[i].getAttribute('color') != oldFonts[i].color))
+ {
+ var child = newFonts[i].firstChild;
+
+ // Moves the font element to inside the anchor element and adopts all children
+ if (child != null && child.nodeName == 'A' && child.nextSibling == null &&
+ child.firstChild != null)
+ {
+ var parent = newFonts[i].parentNode;
+ parent.insertBefore(child, newFonts[i]);
+ var tmp = child.firstChild;
+
+ while (tmp != null)
+ {
+ var next = tmp.nextSibling;
+ newFonts[i].appendChild(tmp);
+ tmp = next;
+ }
+
+ child.appendChild(newFonts[i]);
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ document.execCommand('forecolor', false, (color != mxConstants.NONE) ?
+ color : 'transparent');
+ ui.fireEvent(new mxEventObject('styleChanged',
+ 'keys', [mxConstants.STYLE_FONTCOLOR],
+ 'values', [color], 'cells', ss.cells));
+ }
+ }, (defs[mxConstants.STYLE_FONTCOLOR] != null) ? defs[mxConstants.STYLE_FONTCOLOR] : graph.shapeForegroundColor,
+ {
+ install: function(apply) { fontColorApply = apply; },
+ destroy: function() { fontColorApply = null; }
+ }, null, true) : this.createCellColorOption(mxResources.get('fontColor'),
+ mxConstants.STYLE_FONTCOLOR, 'default', function(color)
+ {
+ if (color == mxConstants.NONE)
+ {
+ bgPanel.style.display = 'none';
+ }
+ else
+ {
+ bgPanel.style.display = '';
+ }
+
+ borderPanel.style.display = bgPanel.style.display;
+ }, function(color)
+ {
+ if (color == mxConstants.NONE)
+ {
+ graph.setCellStyles(mxConstants.STYLE_NOLABEL, '1', ss.cells);
+ }
+ else
+ {
+ graph.setCellStyles(mxConstants.STYLE_NOLABEL, null, ss.cells);
+ }
+
+ graph.setCellStyles(mxConstants.STYLE_FONTCOLOR, color, ss.cells);
+
+ graph.updateLabelElements(ss.cells, function(elt)
+ {
+ elt.removeAttribute('color');
+ elt.style.color = null;
+ });
+ }, graph.shapeForegroundColor);
+ panel.style.fontWeight = 'bold';
+
+ colorPanel.appendChild(panel);
+ colorPanel.appendChild(bgPanel);
+
+ if (!graph.cellEditor.isContentEditing())
+ {
+ colorPanel.appendChild(borderPanel);
+ }
+
+ container.appendChild(colorPanel);
+
+ var extraPanel = this.createPanel();
+ extraPanel.style.paddingTop = '2px';
+ extraPanel.style.paddingBottom = '4px';
+
+ var wwCells = graph.filterSelectionCells(mxUtils.bind(this, function(cell)
+ {
+ var state = graph.view.getState(cell);
+
+ return state == null || graph.isAutoSizeState(state) ||
+ graph.getModel().isEdge(cell) || (!graph.isTableRow(cell) &&
+ !graph.isTableCell(cell) && !graph.isCellResizable(cell));
+ }));
+
+ var wwOpt = this.createCellOption(mxResources.get('wordWrap'), mxConstants.STYLE_WHITE_SPACE,
+ null, 'wrap', 'null', null, null, true, wwCells);
+ wwOpt.style.fontWeight = 'bold';
+
+ // Word wrap in edge labels only supported via labelWidth style
+ if (wwCells.length > 0)
+ {
+ extraPanel.appendChild(wwOpt);
+ }
+
+ // Delegates switch of style to formattedText action as it also convertes newlines
+ var htmlOpt = this.createCellOption(mxResources.get('formattedText'), 'html', 0,
+ null, null, null, ui.actions.get('formattedText'));
+ htmlOpt.style.fontWeight = 'bold';
+ extraPanel.appendChild(htmlOpt);
+
+ var spacingPanel = this.createPanel();
+ spacingPanel.style.paddingTop = '10px';
+ spacingPanel.style.paddingBottom = '28px';
+ spacingPanel.style.fontWeight = 'normal';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.width = '70px';
+ span.style.marginTop = '0px';
+ span.style.fontWeight = 'bold';
+ mxUtils.write(span, mxResources.get('spacing'));
+ spacingPanel.appendChild(span);
+
+ var topUpdate, globalUpdate, leftUpdate, bottomUpdate, rightUpdate;
+ var topSpacing = this.addUnitInput(spacingPanel, 'pt', 87, 52, function()
+ {
+ topUpdate.apply(this, arguments);
+ });
+ var globalSpacing = this.addUnitInput(spacingPanel, 'pt', 16, 52, function()
+ {
+ globalUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(spacingPanel);
+ this.addLabel(spacingPanel, mxResources.get('top'), 87, 64);
+ this.addLabel(spacingPanel, mxResources.get('global'), 16, 64);
+ mxUtils.br(spacingPanel);
+ mxUtils.br(spacingPanel);
+
+ var leftSpacing = this.addUnitInput(spacingPanel, 'pt', 158, 52, function()
+ {
+ leftUpdate.apply(this, arguments);
+ });
+ var bottomSpacing = this.addUnitInput(spacingPanel, 'pt', 87, 52, function()
+ {
+ bottomUpdate.apply(this, arguments);
+ });
+ var rightSpacing = this.addUnitInput(spacingPanel, 'pt', 16, 52, function()
+ {
+ rightUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(spacingPanel);
+ this.addLabel(spacingPanel, mxResources.get('left'), 158, 64);
+ this.addLabel(spacingPanel, mxResources.get('bottom'), 87, 64);
+ this.addLabel(spacingPanel, mxResources.get('right'), 16, 64);
+
+ if (!graph.cellEditor.isContentEditing())
+ {
+ container.appendChild(extraPanel);
+ container.appendChild(this.createRelativeOption(mxResources.get('opacity'), mxConstants.STYLE_TEXT_OPACITY));
+ container.appendChild(spacingPanel);
+ }
+ else
+ {
+ var selState = null;
+ var lineHeightInput = null;
+
+ container.appendChild(this.createRelativeOption(mxResources.get('lineheight'), null, null, function(input)
+ {
+ var value = (input.value == '') ? 120 : parseInt(input.value);
+ value = Math.max(0, (isNaN(value)) ? 120 : value);
+
+ if (selState != null)
+ {
+ graph.cellEditor.restoreSelection(selState);
+ selState = null;
+ }
+
+ var blocks = graph.getSelectedTextBlocks();
+
+ // Adds paragraph tags if no block element is selected
+ if (blocks.length == 0 && graph.cellEditor.textarea != null &&
+ graph.cellEditor.textarea.firstChild != null)
+ {
+ if (graph.cellEditor.textarea.firstChild.nodeName != 'P')
+ {
+ graph.cellEditor.textarea.innerHTML = '' + graph.cellEditor.textarea.innerHTML + '
';
+ }
+
+ blocks = [graph.cellEditor.textarea.firstChild];
+ }
+
+ for (var i = 0; i < blocks.length; i++)
+ {
+ blocks[i].style.lineHeight = value + '%';
+ }
+
+ input.value = value + ' %';
+ }, function(input)
+ {
+ // Used in CSS handler to update current value
+ lineHeightInput = input;
+
+ // KNOWN: Arrow up/down clear selection text in quirks/IE 8
+ // Text size via arrow button limits to 16 in IE11. Why?
+ mxEvent.addListener(input, 'mousedown', function()
+ {
+ if (document.activeElement == graph.cellEditor.textarea)
+ {
+ selState = graph.cellEditor.saveSelection();
+ }
+ });
+
+ mxEvent.addListener(input, 'touchstart', function()
+ {
+ if (document.activeElement == graph.cellEditor.textarea)
+ {
+ selState = graph.cellEditor.saveSelection();
+ }
+ });
+
+ input.value = '120 %';
+ }));
+
+ var insertPanel = stylePanel.cloneNode(false);
+ insertPanel.style.paddingLeft = '0px';
+ var insertBtns = this.editorUi.toolbar.addItems(['link', 'image'], insertPanel, true);
+
+ var btns = [
+ this.editorUi.toolbar.addButton('geSprite-horizontalrule', mxResources.get('insertHorizontalRule'),
+ function()
+ {
+ document.execCommand('inserthorizontalrule', false);
+ }, insertPanel),
+ this.editorUi.toolbar.addMenuFunctionInContainer(insertPanel, 'geSprite-table', mxResources.get('table'), false, mxUtils.bind(this, function(menu)
+ {
+ this.editorUi.menus.addInsertTableItem(menu, null, null, false);
+ }))];
+ this.styleButtons(insertBtns);
+ this.styleButtons(btns);
+
+ var wrapper2 = this.createPanel();
+ wrapper2.style.paddingTop = '10px';
+ wrapper2.style.paddingBottom = '10px';
+ wrapper2.appendChild(this.createTitle(mxResources.get('insert')));
+ wrapper2.appendChild(insertPanel);
+ container.appendChild(wrapper2);
+
+ var tablePanel = stylePanel.cloneNode(false);
+ tablePanel.style.paddingLeft = '0px';
+
+ var btns = [
+ this.editorUi.toolbar.addButton('geSprite-insertcolumnbefore', mxResources.get('insertColumnBefore'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (currentTable != null)
+ {
+ graph.insertColumn(currentTable, (tableCell != null) ? tableCell.cellIndex : 0);
+ }
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }), tablePanel),
+ this.editorUi.toolbar.addButton('geSprite-insertcolumnafter', mxResources.get('insertColumnAfter'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (currentTable != null)
+ {
+ graph.insertColumn(currentTable, (tableCell != null) ? tableCell.cellIndex + 1 : -1);
+ }
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }), tablePanel),
+ this.editorUi.toolbar.addButton('geSprite-deletecolumn', mxResources.get('deleteColumn'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (currentTable != null && tableCell != null)
+ {
+ graph.deleteColumn(currentTable, tableCell.cellIndex);
+ }
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }), tablePanel),
+ this.editorUi.toolbar.addButton('geSprite-insertrowbefore', mxResources.get('insertRowBefore'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (currentTable != null && tableRow != null)
+ {
+ graph.insertRow(currentTable, tableRow.sectionRowIndex);
+ }
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }), tablePanel),
+ this.editorUi.toolbar.addButton('geSprite-insertrowafter', mxResources.get('insertRowAfter'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (currentTable != null && tableRow != null)
+ {
+ graph.insertRow(currentTable, tableRow.sectionRowIndex + 1);
+ }
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }), tablePanel),
+ this.editorUi.toolbar.addButton('geSprite-deleterow', mxResources.get('deleteRow'),
+ mxUtils.bind(this, function()
+ {
+ try
+ {
+ if (currentTable != null && tableRow != null)
+ {
+ graph.deleteRow(currentTable, tableRow.sectionRowIndex);
+ }
+ }
+ catch (e)
+ {
+ this.editorUi.handleError(e);
+ }
+ }), tablePanel)];
+ this.styleButtons(btns);
+ btns[2].style.marginRight = '10px';
+
+ var wrapper3 = this.createPanel();
+ wrapper3.style.paddingTop = '10px';
+ wrapper3.style.paddingBottom = '10px';
+ wrapper3.appendChild(this.createTitle(mxResources.get('table')));
+ wrapper3.appendChild(tablePanel);
+
+ var tablePanel2 = stylePanel.cloneNode(false);
+ tablePanel2.style.paddingLeft = '0px';
+
+ var btns = [
+ this.editorUi.toolbar.addButton('geSprite-strokecolor', mxResources.get('borderColor'),
+ mxUtils.bind(this, function(evt)
+ {
+ if (currentTable != null)
+ {
+ // Converts rgb(r,g,b) values
+ var color = currentTable.style.borderColor.replace(
+ /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
+ function($0, $1, $2, $3) {
+ return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2);
+ });
+ this.editorUi.pickColor(color, function(newColor)
+ {
+ var targetElt = (tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))) ? tableCell : currentTable;
+
+ graph.processElements(targetElt, function(elt)
+ {
+ elt.style.border = null;
+ });
+
+ if (newColor == null || newColor == mxConstants.NONE)
+ {
+ targetElt.removeAttribute('border');
+ targetElt.style.border = '';
+ targetElt.style.borderCollapse = '';
+ }
+ else
+ {
+ targetElt.setAttribute('border', '1');
+ targetElt.style.border = '1px solid ' + newColor;
+ targetElt.style.borderCollapse = 'collapse';
+ }
+ });
+ }
+ }), tablePanel2),
+ this.editorUi.toolbar.addButton('geSprite-fillcolor', mxResources.get('backgroundColor'),
+ mxUtils.bind(this, function(evt)
+ {
+ // Converts rgb(r,g,b) values
+ if (currentTable != null)
+ {
+ var color = currentTable.style.backgroundColor.replace(
+ /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
+ function($0, $1, $2, $3) {
+ return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2);
+ });
+ this.editorUi.pickColor(color, function(newColor)
+ {
+ var targetElt = (tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))) ? tableCell : currentTable;
+
+ graph.processElements(targetElt, function(elt)
+ {
+ elt.style.backgroundColor = null;
+ });
+
+ if (newColor == null || newColor == mxConstants.NONE)
+ {
+ targetElt.style.backgroundColor = '';
+ }
+ else
+ {
+ targetElt.style.backgroundColor = newColor;
+ }
+ });
+ }
+ }), tablePanel2),
+ this.editorUi.toolbar.addButton('geSprite-fit', mxResources.get('spacing'),
+ function()
+ {
+ if (currentTable != null)
+ {
+ var value = currentTable.getAttribute('cellPadding') || 0;
+
+ var dlg = new FilenameDialog(ui, value, mxResources.get('apply'), mxUtils.bind(this, function(newValue)
+ {
+ if (newValue != null && newValue.length > 0)
+ {
+ currentTable.setAttribute('cellPadding', newValue);
+ }
+ else
+ {
+ currentTable.removeAttribute('cellPadding');
+ }
+ }), mxResources.get('spacing'));
+ ui.showDialog(dlg.container, 300, 80, true, true);
+ dlg.init();
+ }
+ }, tablePanel2),
+ this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'),
+ function()
+ {
+ if (currentTable != null)
+ {
+ currentTable.setAttribute('align', 'left');
+ }
+ }, tablePanel2),
+ this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'),
+ function()
+ {
+ if (currentTable != null)
+ {
+ currentTable.setAttribute('align', 'center');
+ }
+ }, tablePanel2),
+ this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'),
+ function()
+ {
+ if (currentTable != null)
+ {
+ currentTable.setAttribute('align', 'right');
+ }
+ }, tablePanel2)];
+ this.styleButtons(btns);
+ btns[2].style.marginRight = '10px';
+
+ wrapper3.appendChild(tablePanel2);
+ container.appendChild(wrapper3);
+
+ tableWrapper = wrapper3;
+ }
+
+ function setSelected(elt, selected)
+ {
+ elt.style.backgroundImage = (selected) ? (Editor.isDarkMode() ?
+ 'linear-gradient(rgb(0 161 241) 0px, rgb(0, 97, 146) 100%)':
+ 'linear-gradient(#c5ecff 0px,#87d4fb 100%)') : '';
+ };
+
+ // Updates font style state before typing
+ for (var i = 0; i < 3; i++)
+ {
+ (function(index)
+ {
+ mxEvent.addListener(fontStyleItems[index], 'click', function()
+ {
+ setSelected(fontStyleItems[index], fontStyleItems[index].style.backgroundImage == '');
+ });
+ })(i);
+ }
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ ss = ui.getSelectionState();
+ var fontStyle = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSTYLE, 0);
+ setSelected(fontStyleItems[0], (fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD);
+ setSelected(fontStyleItems[1], (fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC);
+ setSelected(fontStyleItems[2], (fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE);
+ fontMenu.firstChild.nodeValue = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTFAMILY, Menus.prototype.defaultFont);
+
+ setSelected(verticalItem, mxUtils.getValue(ss.style, mxConstants.STYLE_HORIZONTAL, '1') == '0');
+
+ if (force || document.activeElement != input)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSIZE, Menus.prototype.defaultFontSize));
+ input.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ var align = mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
+ setSelected(left, align == mxConstants.ALIGN_LEFT);
+ setSelected(center, align == mxConstants.ALIGN_CENTER);
+ setSelected(right, align == mxConstants.ALIGN_RIGHT);
+
+ var valign = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
+ setSelected(top, valign == mxConstants.ALIGN_TOP);
+ setSelected(middle, valign == mxConstants.ALIGN_MIDDLE);
+ setSelected(bottom, valign == mxConstants.ALIGN_BOTTOM);
+
+ var pos = mxUtils.getValue(ss.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
+ var vpos = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
+
+ if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_TOP)
+ {
+ positionSelect.value = 'topLeft';
+ }
+ else if (pos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_TOP)
+ {
+ positionSelect.value = 'top';
+ }
+ else if (pos == mxConstants.ALIGN_RIGHT && vpos == mxConstants.ALIGN_TOP)
+ {
+ positionSelect.value = 'topRight';
+ }
+ else if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_BOTTOM)
+ {
+ positionSelect.value = 'bottomLeft';
+ }
+ else if (pos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_BOTTOM)
+ {
+ positionSelect.value = 'bottom';
+ }
+ else if (pos == mxConstants.ALIGN_RIGHT && vpos == mxConstants.ALIGN_BOTTOM)
+ {
+ positionSelect.value = 'bottomRight';
+ }
+ else if (pos == mxConstants.ALIGN_LEFT)
+ {
+ positionSelect.value = 'left';
+ }
+ else if (pos == mxConstants.ALIGN_RIGHT)
+ {
+ positionSelect.value = 'right';
+ }
+ else
+ {
+ positionSelect.value = 'center';
+ }
+
+ var dir = mxUtils.getValue(ss.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
+
+ if (dir == mxConstants.TEXT_DIRECTION_RTL)
+ {
+ dirSelect.value = 'rightToLeft';
+ }
+ else if (dir == mxConstants.TEXT_DIRECTION_LTR)
+ {
+ dirSelect.value = 'leftToRight';
+ }
+ else if (dir == mxConstants.TEXT_DIRECTION_AUTO)
+ {
+ dirSelect.value = 'automatic';
+ }
+
+ if (force || document.activeElement != globalSpacing)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING, 2));
+ globalSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != topSpacing)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_TOP, 0));
+ topSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != rightSpacing)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_RIGHT, 0));
+ rightSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != bottomSpacing)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_BOTTOM, 0));
+ bottomSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != leftSpacing)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_LEFT, 0));
+ leftSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+ });
+
+ globalUpdate = this.installInputHandler(globalSpacing, mxConstants.STYLE_SPACING, 2, -999, 999, ' pt');
+ topUpdate = this.installInputHandler(topSpacing, mxConstants.STYLE_SPACING_TOP, 0, -999, 999, ' pt');
+ rightUpdate = this.installInputHandler(rightSpacing, mxConstants.STYLE_SPACING_RIGHT, 0, -999, 999, ' pt');
+ bottomUpdate = this.installInputHandler(bottomSpacing, mxConstants.STYLE_SPACING_BOTTOM, 0, -999, 999, ' pt');
+ leftUpdate = this.installInputHandler(leftSpacing, mxConstants.STYLE_SPACING_LEFT, 0, -999, 999, ' pt');
+
+ this.addKeyHandler(input, listener);
+ this.addKeyHandler(globalSpacing, listener);
+ this.addKeyHandler(topSpacing, listener);
+ this.addKeyHandler(rightSpacing, listener);
+ this.addKeyHandler(bottomSpacing, listener);
+ this.addKeyHandler(leftSpacing, listener);
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+
+ if (graph.cellEditor.isContentEditing())
+ {
+ var updating = false;
+
+ var updateCssHandler = function()
+ {
+ if (!updating)
+ {
+ updating = true;
+
+ window.setTimeout(function()
+ {
+ var node = graph.getSelectedEditingElement();
+
+ if (node != null)
+ {
+ function getRelativeLineHeight(fontSize, css, elt)
+ {
+ if (elt.style != null && css != null)
+ {
+ var lineHeight = css.lineHeight
+
+ if (elt.style.lineHeight != null && elt.style.lineHeight.substring(elt.style.lineHeight.length - 1) == '%')
+ {
+ return parseInt(elt.style.lineHeight) / 100;
+ }
+ else
+ {
+ return (lineHeight.substring(lineHeight.length - 2) == 'px') ?
+ parseFloat(lineHeight) / fontSize : parseInt(lineHeight);
+ }
+ }
+ else
+ {
+ return '';
+ }
+ };
+
+ function getAbsoluteFontSize(css)
+ {
+ var fontSize = (css != null) ? css.fontSize : null;
+
+ if (fontSize != null && fontSize.substring(fontSize.length - 2) == 'px')
+ {
+ return parseFloat(fontSize);
+ }
+ else
+ {
+ return mxConstants.DEFAULT_FONTSIZE;
+ }
+ };
+
+ var css = mxUtils.getCurrentStyle(node);
+ var fontSize = getAbsoluteFontSize(css);
+ var lineHeight = getRelativeLineHeight(fontSize, css, node);
+
+ // Finds common font size
+ var elts = node.getElementsByTagName('*');
+
+ // IE does not support containsNode
+ if (elts.length > 0 && window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11)
+ {
+ var selection = window.getSelection();
+
+ for (var i = 0; i < elts.length; i++)
+ {
+ if (selection.containsNode(elts[i], true))
+ {
+ temp = mxUtils.getCurrentStyle(elts[i]);
+ fontSize = Math.max(getAbsoluteFontSize(temp), fontSize);
+ var lh = getRelativeLineHeight(fontSize, temp, elts[i]);
+
+ if (lh != lineHeight || isNaN(lh))
+ {
+ lineHeight = '';
+ }
+ }
+ }
+ }
+
+ function hasParentOrOnlyChild(name)
+ {
+ if (graph.getParentByName(node, name, graph.cellEditor.textarea) != null)
+ {
+ return true;
+ }
+ else
+ {
+ var child = node;
+
+ while (child != null && child.childNodes.length == 1)
+ {
+ child = child.childNodes[0];
+
+ if (child.nodeName == name)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ function isEqualOrPrefixed(str, value)
+ {
+ if (str != null && value != null)
+ {
+ if (str == value)
+ {
+ return true;
+ }
+ else if (str.length > value.length + 1)
+ {
+ return str.substring(str.length - value.length - 1, str.length) == '-' + value;
+ }
+ }
+
+ return false;
+ };
+
+ if (css != null)
+ {
+ setSelected(fontStyleItems[0], css.fontWeight == 'bold' ||
+ css.fontWeight > 400 || hasParentOrOnlyChild('B') ||
+ hasParentOrOnlyChild('STRONG'));
+ setSelected(fontStyleItems[1], css.fontStyle == 'italic' ||
+ hasParentOrOnlyChild('I') || hasParentOrOnlyChild('EM'));
+ setSelected(fontStyleItems[2], hasParentOrOnlyChild('U'));
+ setSelected(sup, hasParentOrOnlyChild('SUP'));
+ setSelected(sub, hasParentOrOnlyChild('SUB'));
+
+ if (!graph.cellEditor.isTableSelected())
+ {
+ var align = graph.cellEditor.align || mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
+
+ if (isEqualOrPrefixed(css.textAlign, 'justify'))
+ {
+ setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify'));
+ setSelected(left, false);
+ setSelected(center, false);
+ setSelected(right, false);
+ }
+ else
+ {
+ setSelected(full, false);
+ setSelected(left, align == mxConstants.ALIGN_LEFT);
+ setSelected(center, align == mxConstants.ALIGN_CENTER);
+ setSelected(right, align == mxConstants.ALIGN_RIGHT);
+ }
+ }
+ else
+ {
+ setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify'));
+ setSelected(left, isEqualOrPrefixed(css.textAlign, 'left'));
+ setSelected(center, isEqualOrPrefixed(css.textAlign, 'center'));
+ setSelected(right, isEqualOrPrefixed(css.textAlign, 'right'));
+ }
+
+ currentTable = graph.getParentByName(node, 'TABLE', graph.cellEditor.textarea);
+ tableRow = (currentTable == null) ? null : graph.getParentByName(node, 'TR', currentTable);
+ tableCell = (currentTable == null) ? null : graph.getParentByNames(node, ['TD', 'TH'], currentTable);
+ tableWrapper.style.display = (currentTable != null) ? '' : 'none';
+
+ if (document.activeElement != input)
+ {
+ if (node.nodeName == 'FONT' && node.getAttribute('size') == '4' &&
+ pendingFontSize != null)
+ {
+ node.removeAttribute('size');
+ node.style.fontSize = pendingFontSize + ' pt';
+ pendingFontSize = null;
+ }
+ else
+ {
+ input.value = (isNaN(fontSize)) ? '' : fontSize + ' pt';
+ }
+
+ var lh = parseFloat(lineHeight);
+
+ if (!isNaN(lh))
+ {
+ lineHeightInput.value = Math.round(lh * 100) + ' %';
+ }
+ else
+ {
+ lineHeightInput.value = '100 %';
+ }
+ }
+
+ // Updates the color picker for the current font
+ if (fontColorApply != null)
+ {
+ if (css.color == 'rgba(0, 0, 0, 0)' ||
+ css.color == 'transparent')
+ {
+ currentFontColor = mxConstants.NONE;
+ }
+ else
+ {
+ currentFontColor = mxUtils.rgba2hex(css.color)
+ }
+
+ fontColorApply(currentFontColor, true);
+ }
+
+ if (bgColorApply != null)
+ {
+ if (css.backgroundColor == 'rgba(0, 0, 0, 0)' ||
+ css.backgroundColor == 'transparent')
+ {
+ currentBgColor = mxConstants.NONE;
+ }
+ else
+ {
+ currentBgColor = mxUtils.rgba2hex(css.backgroundColor);
+ }
+
+ bgColorApply(currentBgColor, true);
+ }
+
+ // Workaround for firstChild is null or not an object
+ // in the log which seems to be IE8- only / 29.01.15
+ if (fontMenu.firstChild != null)
+ {
+ fontMenu.firstChild.nodeValue = Graph.stripQuotes(css.fontFamily);
+ }
+ }
+ }
+
+ updating = false;
+ }, 0);
+ }
+ };
+
+ if (mxClient.IS_FF || mxClient.IS_EDGE || mxClient.IS_IE || mxClient.IS_IE11)
+ {
+ mxEvent.addListener(graph.cellEditor.textarea, 'DOMSubtreeModified', updateCssHandler);
+ }
+
+ mxEvent.addListener(graph.cellEditor.textarea, 'input', updateCssHandler);
+ mxEvent.addListener(graph.cellEditor.textarea, 'touchend', updateCssHandler);
+ mxEvent.addListener(graph.cellEditor.textarea, 'mouseup', updateCssHandler);
+ mxEvent.addListener(graph.cellEditor.textarea, 'keyup', updateCssHandler);
+ this.listeners.push({destroy: function()
+ {
+ // No need to remove listener since textarea is destroyed after edit
+ }});
+ updateCssHandler();
+ }
+
+ return container;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel = function(format, editorUi, container)
+{
+ BaseFormatPanel.call(this, format, editorUi, container);
+ this.init();
+};
+
+mxUtils.extend(StyleFormatPanel, BaseFormatPanel);
+
+/**
+ *
+ */
+StyleFormatPanel.prototype.defaultStrokeColor = 'black';
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.init = function()
+{
+ var ui = this.editorUi;
+ var ss = ui.getSelectionState();
+
+ if (!ss.containsLabel && ss.cells.length > 0)
+ {
+ if (ss.containsImage && ss.vertices.length == 1 && ss.style.shape == 'image' &&
+ ss.style.image != null && ss.style.image.substring(0, 19) == 'data:image/svg+xml;')
+ {
+ this.container.appendChild(this.addSvgStyles(this.createPanel()));
+ }
+
+ if (ss.fill)
+ {
+ this.container.appendChild(this.addFill(this.createPanel()));
+ }
+
+ this.container.appendChild(this.addStroke(this.createPanel()));
+ this.container.appendChild(this.addLineJumps(this.createPanel()));
+ var opacityPanel = this.createRelativeOption(mxResources.get('opacity'), mxConstants.STYLE_OPACITY);
+ opacityPanel.style.paddingTop = '8px';
+ opacityPanel.style.paddingBottom = '10px';
+ this.container.appendChild(opacityPanel);
+ this.container.appendChild(this.addEffects(this.createPanel()));
+ }
+
+ var opsPanel = this.createPanel();
+ opsPanel.style.paddingTop = '8px';
+
+ if (ss.cells.length == 1)
+ {
+ this.addEditOps(opsPanel);
+
+ if (opsPanel.firstChild != null)
+ {
+ mxUtils.br(opsPanel);
+ }
+ }
+
+ if (ss.cells.length >= 1)
+ {
+ this.addStyleOps(opsPanel);
+ }
+
+ if (opsPanel.firstChild != null)
+ {
+ this.container.appendChild(opsPanel);
+ }
+};
+
+/**
+ * Use browser for parsing CSS.
+ */
+StyleFormatPanel.prototype.getCssRules = function(css)
+{
+ var doc = document.implementation.createHTMLDocument('');
+ var styleElement = document.createElement('style');
+
+ mxUtils.setTextContent(styleElement, css);
+ doc.body.appendChild(styleElement);
+
+ return styleElement.sheet.cssRules;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addSvgStyles = function(container)
+{
+ var ui = this.editorUi;
+ var ss = ui.getSelectionState();
+ container.style.paddingTop = '6px';
+ container.style.paddingBottom = '6px';
+ container.style.fontWeight = 'bold';
+ container.style.display = 'none';
+
+ try
+ {
+ var exp = ss.style.editableCssRules;
+
+ if (exp != null)
+ {
+ var regex = new RegExp(exp);
+
+ var data = ss.style.image.substring(ss.style.image.indexOf(',') + 1);
+ var xml = (window.atob) ? atob(data) : Base64.decode(data, true);
+ var svg = mxUtils.parseXml(xml);
+
+ if (svg != null)
+ {
+ var styles = svg.getElementsByTagName('style');
+
+ for (var i = 0; i < styles.length; i++)
+ {
+ var rules = this.getCssRules(mxUtils.getTextContent(styles[i]));
+
+ for (var j = 0; j < rules.length; j++)
+ {
+ this.addSvgRule(container, rules[j], svg, styles[i], rules, j, regex);
+ }
+ }
+ }
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+
+ return container;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addSvgRule = function(container, rule, svg, styleElem, rules, ruleIndex, regex)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+
+ if (regex.test(rule.selectorText))
+ {
+ function rgb2hex(rgb)
+ {
+ rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
+
+ return (rgb && rgb.length === 4) ? "#" +
+ ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
+ ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
+ ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : '';
+ };
+
+ var addStyleRule = mxUtils.bind(this, function(rule, key, label)
+ {
+ var value = mxUtils.trim(rule.style[key]);
+
+ if (value != '' && value.substring(0, 4) != 'url(')
+ {
+ var option = this.createColorOption(label + ' ' + rule.selectorText, function()
+ {
+ return rgb2hex(value);
+ }, mxUtils.bind(this, function(color)
+ {
+ rules[ruleIndex].style[key] = color;
+ var cssTxt = '';
+
+ for (var i = 0; i < rules.length; i++)
+ {
+ cssTxt += rules[i].cssText + ' ';
+ }
+
+ styleElem.textContent = cssTxt;
+ var xml = mxUtils.getXml(svg.documentElement);
+
+ graph.setCellStyles(mxConstants.STYLE_IMAGE, 'data:image/svg+xml,' +
+ ((window.btoa) ? btoa(xml) : Base64.encode(xml, true)),
+ ui.getSelectionState().cells);
+ }), '#ffffff',
+ {
+ install: function(apply)
+ {
+ // ignore
+ },
+ destroy: function()
+ {
+ // ignore
+ }
+ });
+
+ container.appendChild(option);
+
+ // Shows container if rules are added
+ container.style.display = '';
+ }
+ });
+
+ addStyleRule(rule, 'fill', mxResources.get('fill'));
+ addStyleRule(rule, 'stroke', mxResources.get('line'));
+ addStyleRule(rule, 'stop-color', mxResources.get('gradient'));
+ }
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addEditOps = function(div)
+{
+ var ss = this.editorUi.getSelectionState();
+
+ if (ss.cells.length == 1)
+ {
+ var editSelect = document.createElement('select');
+ editSelect.style.width = '210px';
+ editSelect.style.textAlign = 'center';
+ editSelect.style.marginBottom = '2px';
+
+ var ops = ['edit', 'editLink', 'editShape', 'editImage', 'editData',
+ 'copyData', 'pasteData', 'editConnectionPoints', 'editGeometry',
+ 'editTooltip', 'editStyle'];
+
+ for (var i = 0; i < ops.length; i++)
+ {
+ var action = this.editorUi.actions.get(ops[i]);
+
+ if (action == null || action.enabled)
+ {
+ var editOption = document.createElement('option');
+ editOption.setAttribute('value', ops[i]);
+ var title = mxResources.get(ops[i]);
+ mxUtils.write(editOption, title + ((ops[i] == 'edit') ? '' : '...'));
+
+ if (action != null && action.shortcut != null)
+ {
+ title += ' (' + action.shortcut + ')';
+ }
+
+ editOption.setAttribute('title', title);
+ editSelect.appendChild(editOption);
+ }
+ }
+
+ if (editSelect.children.length > 1)
+ {
+ div.appendChild(editSelect);
+
+ mxEvent.addListener(editSelect, 'change', mxUtils.bind(this, function(evt)
+ {
+ var action = this.editorUi.actions.get(editSelect.value);
+ editSelect.value = 'edit';
+
+ if (action != null)
+ {
+ action.funct();
+ }
+ }));
+
+ if (ss.image && ss.cells.length > 0)
+ {
+ var graph = this.editorUi.editor.graph;
+ var state = graph.view.getState(graph.getSelectionCell());
+
+ if (state != null && mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE, null) != null)
+ {
+ var btn = mxUtils.button(mxResources.get('crop') + '...',
+ mxUtils.bind(this, function(evt)
+ {
+ this.editorUi.actions.get('crop').funct();
+ }));
+
+ btn.setAttribute('title', mxResources.get('crop'));
+ editSelect.style.width = '104px';
+ btn.style.width = '104px';
+ btn.style.marginLeft = '2px';
+ btn.style.marginBottom = '2px';
+
+ div.appendChild(btn);
+ }
+ }
+ }
+ }
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addFill = function(container)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var ss = ui.getSelectionState();
+ container.style.paddingTop = '6px';
+ container.style.paddingBottom = '6px';
+
+ // Adds gradient direction option
+ var gradientSelect = document.createElement('select');
+ gradientSelect.style.position = 'absolute';
+ gradientSelect.style.left = '104px';
+ gradientSelect.style.width = '70px';
+ gradientSelect.style.height = '22px';
+ gradientSelect.style.padding = '0px';
+ gradientSelect.style.marginTop = '-3px';
+ gradientSelect.style.borderWidth = '1px';
+ gradientSelect.style.borderStyle = 'solid';
+ gradientSelect.style.boxSizing = 'border-box';
+
+ var fillStyleSelect = gradientSelect.cloneNode(false);
+
+ // Stops events from bubbling to color option event handler
+ mxEvent.addListener(gradientSelect, 'click', function(evt)
+ {
+ mxEvent.consume(evt);
+ });
+ mxEvent.addListener(fillStyleSelect, 'click', function(evt)
+ {
+ mxEvent.consume(evt);
+ });
+
+ var gradientPanel = this.createCellColorOption(mxResources.get('gradient'),
+ mxConstants.STYLE_GRADIENTCOLOR, 'default', function(color)
+ {
+ if (color == null || color == mxConstants.NONE)
+ {
+ gradientSelect.style.display = 'none';
+ }
+ else
+ {
+ gradientSelect.style.display = '';
+ }
+ }, function(color)
+ {
+ graph.updateCellStyles({'gradientColor': color}, graph.getSelectionCells());
+ }, graph.getDefaultColor(ss.style, mxConstants.STYLE_GRADIENTCOLOR,
+ graph.shapeForegroundColor, graph.shapeBackgroundColor));
+
+ var fillKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BACKGROUND : mxConstants.STYLE_FILLCOLOR;
+
+ var fillPanel = this.createCellColorOption(mxResources.get('fill'),
+ fillKey, 'default', null, mxUtils.bind(this, function(color)
+ {
+ graph.setCellStyles(fillKey, color, ss.cells);
+ }), graph.getDefaultColor(ss.style, fillKey, graph.shapeBackgroundColor,
+ graph.shapeForegroundColor));
+
+ fillPanel.style.fontWeight = 'bold';
+ var tmpColor = mxUtils.getValue(ss.style, fillKey, null);
+ gradientPanel.style.display = (tmpColor != null && tmpColor != mxConstants.NONE &&
+ ss.fill && ss.style.shape != 'image') ? '' : 'none';
+
+ var directions = [mxConstants.DIRECTION_NORTH, mxConstants.DIRECTION_EAST,
+ mxConstants.DIRECTION_SOUTH, mxConstants.DIRECTION_WEST,
+ mxConstants.DIRECTION_RADIAL];
+
+ for (var i = 0; i < directions.length; i++)
+ {
+ var gradientOption = document.createElement('option');
+ gradientOption.setAttribute('value', directions[i]);
+ mxUtils.write(gradientOption, mxResources.get(directions[i]));
+ gradientSelect.appendChild(gradientOption);
+ }
+
+ gradientPanel.appendChild(gradientSelect);
+
+ var curFillStyle;
+
+ function populateFillStyle()
+ {
+ fillStyleSelect.innerHTML = '';
+ curFillStyle = 1;
+
+ for (var i = 0; i < Editor.fillStyles.length; i++)
+ {
+ var fillStyleOption = document.createElement('option');
+ fillStyleOption.setAttribute('value', Editor.fillStyles[i].val);
+ mxUtils.write(fillStyleOption, Editor.fillStyles[i].dispName);
+ fillStyleSelect.appendChild(fillStyleOption);
+ }
+ };
+
+ function populateRoughFillStyle()
+ {
+ fillStyleSelect.innerHTML = '';
+ curFillStyle = 2;
+
+ for (var i = 0; i < Editor.roughFillStyles.length; i++)
+ {
+ var fillStyleOption = document.createElement('option');
+ fillStyleOption.setAttribute('value', Editor.roughFillStyles[i].val);
+ mxUtils.write(fillStyleOption, Editor.roughFillStyles[i].dispName);
+ fillStyleSelect.appendChild(fillStyleOption);
+ }
+
+ fillStyleSelect.value = 'auto';
+ };
+
+ populateFillStyle();
+
+ if (ss.gradient)
+ {
+ fillPanel.appendChild(fillStyleSelect);
+ }
+
+ var listener = mxUtils.bind(this, function()
+ {
+ ss = ui.getSelectionState();
+ var value = mxUtils.getValue(ss.style, mxConstants.STYLE_GRADIENT_DIRECTION,
+ mxConstants.DIRECTION_SOUTH);
+ var fillStyle = mxUtils.getValue(ss.style, 'fillStyle', 'auto');
+
+ // Handles empty string which is not allowed as a value
+ if (value == '')
+ {
+ value = mxConstants.DIRECTION_SOUTH;
+ }
+
+ gradientSelect.value = value;
+ container.style.display = (ss.fill) ? '' : 'none';
+
+ var fillColor = mxUtils.getValue(ss.style, fillKey, null);
+
+ if (!ss.fill || fillColor == null || fillColor == mxConstants.NONE ||
+ ss.style.shape == 'filledEdge')
+ {
+ fillStyleSelect.style.display = 'none';
+ gradientPanel.style.display = 'none';
+ }
+ else
+ {
+ if (ss.style.sketch == '1')
+ {
+ if (curFillStyle != 2)
+ {
+ populateRoughFillStyle()
+ }
+ }
+ else if (curFillStyle != 1)
+ {
+ populateFillStyle();
+ }
+
+ fillStyleSelect.value = fillStyle;
+
+ //In case of switching from sketch to regular and fill type is not there
+ if (!fillStyleSelect.value)
+ {
+ fillStyle = 'auto';
+ fillStyleSelect.value = fillStyle;
+ }
+
+ fillStyleSelect.style.display = ss.style.sketch == '1' ||
+ gradientSelect.style.display == 'none'? '' : 'none';
+ gradientPanel.style.display = (ss.gradient &&
+ !ss.containsImage && (ss.style.sketch != '1' ||
+ fillStyle == 'solid' || fillStyle == 'auto')) ?
+ '' : 'none';
+ }
+ });
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+
+ mxEvent.addListener(gradientSelect, 'change', function(evt)
+ {
+ graph.setCellStyles(mxConstants.STYLE_GRADIENT_DIRECTION, gradientSelect.value, ss.cells);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_GRADIENT_DIRECTION],
+ 'values', [gradientSelect.value], 'cells', ss.cells));
+ mxEvent.consume(evt);
+ });
+
+ mxEvent.addListener(fillStyleSelect, 'change', function(evt)
+ {
+ graph.setCellStyles('fillStyle', fillStyleSelect.value, ss.cells);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['fillStyle'],
+ 'values', [fillStyleSelect.value], 'cells', ss.cells));
+ mxEvent.consume(evt);
+ });
+
+ container.appendChild(fillPanel);
+ container.appendChild(gradientPanel);
+
+ // Adds custom colors
+ var custom = this.getCustomColors();
+
+ for (var i = 0; i < custom.length; i++)
+ {
+ container.appendChild(this.createCellColorOption(custom[i].title,
+ custom[i].key, custom[i].defaultValue));
+ }
+
+ return container;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.getCustomColors = function()
+{
+ var ss = this.editorUi.getSelectionState();
+ var result = [];
+
+ if (ss.swimlane)
+ {
+ result.push({title: mxResources.get('laneColor'),
+ key: 'swimlaneFillColor', defaultValue: 'default'});
+ }
+
+ return result;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addStroke = function(container)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var ss = ui.getSelectionState();
+
+ container.style.paddingTop = '6px';
+ container.style.paddingBottom = '4px';
+ container.style.whiteSpace = 'normal';
+
+ var colorPanel = document.createElement('div');
+ colorPanel.style.fontWeight = 'bold';
+
+ if (!ss.stroke)
+ {
+ colorPanel.style.display = 'none';
+ }
+
+ // Adds gradient direction option
+ var styleSelect = document.createElement('select');
+ styleSelect.style.position = 'absolute';
+ styleSelect.style.height = '22px';
+ styleSelect.style.padding = '0px';
+ styleSelect.style.marginTop = '-3px';
+ styleSelect.style.textAlign = 'center';
+ styleSelect.style.boxSizing = 'border-box';
+ styleSelect.style.left = '90px';
+ styleSelect.style.width = '83px';
+ styleSelect.style.borderWidth = '1px';
+ styleSelect.style.borderStyle = 'solid';
+
+ var styles = ['sharp', 'rounded', 'curved'];
+
+ for (var i = 0; i < styles.length; i++)
+ {
+ var styleOption = document.createElement('option');
+ styleOption.setAttribute('value', styles[i]);
+ mxUtils.write(styleOption, mxResources.get(styles[i]));
+ styleSelect.appendChild(styleOption);
+ }
+
+ mxEvent.addListener(styleSelect, 'change', function(evt)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var keys = [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED];
+ // Default for rounded is 1
+ var values = ['0', null];
+
+ if (styleSelect.value == 'rounded')
+ {
+ values = ['1', null];
+ }
+ else if (styleSelect.value == 'curved')
+ {
+ values = [null, '1'];
+ }
+
+ for (var i = 0; i < keys.length; i++)
+ {
+ graph.setCellStyles(keys[i], values[i], ss.cells);
+ }
+
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', keys,
+ 'values', values, 'cells', ss.cells));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ // Stops events from bubbling to color option event handler
+ mxEvent.addListener(styleSelect, 'click', function(evt)
+ {
+ mxEvent.consume(evt);
+ });
+
+ var strokeKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BORDER : mxConstants.STYLE_STROKECOLOR;
+ var label = (ss.style.shape == 'image') ? mxResources.get('border') : mxResources.get('line');
+
+ var lineColor = this.createCellColorOption(label, strokeKey, 'default', null, mxUtils.bind(this, function(color)
+ {
+ graph.setCellStyles(strokeKey, color, ss.cells);
+
+ // Sets strokeColor to inherit for rows and cells in tables
+ if (color == null || color == mxConstants.NONE)
+ {
+ var tableCells = [];
+
+ for (var i = 0; i < ss.cells.length; i++)
+ {
+ if (graph.isTableCell(ss.cells[i]) ||
+ graph.isTableRow(ss.cells[i]))
+ {
+ tableCells.push(ss.cells[i]);
+ }
+ }
+
+ if (tableCells.length > 0)
+ {
+ graph.setCellStyles(strokeKey, 'inherit', tableCells);
+ }
+ }
+ }), graph.shapeForegroundColor);
+
+ lineColor.appendChild(styleSelect);
+ colorPanel.appendChild(lineColor);
+
+ // Used if only edges selected
+ var stylePanel = colorPanel.cloneNode(false);
+ stylePanel.style.display = 'inline-flex';
+ stylePanel.style.alignItems = 'top';
+ stylePanel.style.fontWeight = 'normal';
+ stylePanel.style.whiteSpace = 'nowrap';
+ stylePanel.style.position = 'relative';
+ stylePanel.style.paddingLeft = '5px';
+ stylePanel.style.overflow = 'hidden';
+ stylePanel.style.marginTop = '2px';
+ stylePanel.style.width = '220px';
+
+ var addItem = mxUtils.bind(this, function(menu, width, cssName, keys, values)
+ {
+ var item = this.editorUi.menus.styleChange(menu, '', keys, values, 'geIcon', null);
+
+ var pat = document.createElement('div');
+ pat.style.width = width + 'px';
+ pat.style.height = '1px';
+ pat.style.borderBottom = '1px ' + cssName + ' ' + this.defaultStrokeColor;
+ pat.style.paddingTop = '6px';
+
+ item.firstChild.firstChild.style.padding = '0px 4px 0px 4px';
+ item.firstChild.firstChild.style.width = width + 'px';
+ item.firstChild.firstChild.appendChild(pat);
+
+ return item;
+ });
+
+ var pattern = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel, 'geSprite-orthogonal', mxResources.get('pattern'), false, mxUtils.bind(this, function(menu)
+ {
+ addItem(menu, 75, 'solid', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], [null, null]).setAttribute('title', mxResources.get('solid'));
+ addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', null]).setAttribute('title', mxResources.get('dashed') + ' (1)');
+ addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '8 8']).setAttribute('title', mxResources.get('dashed') + ' (2)');
+ addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '12 12']).setAttribute('title', mxResources.get('dashed') + ' (3)');
+ addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 1']).setAttribute('title', mxResources.get('dotted') + ' (1)');
+ addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 2']).setAttribute('title', mxResources.get('dotted') + ' (2)');
+ addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 4']).setAttribute('title', mxResources.get('dotted') + ' (3)');
+ }));
+
+ // Used for mixed selection (vertices and edges)
+ var altStylePanel = stylePanel.cloneNode(false);
+
+ var edgeShape = this.editorUi.toolbar.addMenuFunctionInContainer(altStylePanel, 'geSprite-connection', mxResources.get('connection'), false, mxUtils.bind(this, function(menu)
+ {
+ this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
+ [null, null, null, null], 'geIcon geSprite geSprite-connection', null, null, null, true).setAttribute('title', mxResources.get('line'));
+ this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
+ ['link', null, null, null], 'geIcon geSprite geSprite-linkedge', null, null, null, true).setAttribute('title', mxResources.get('link'));
+ this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
+ ['flexArrow', null, null, null], 'geIcon geSprite geSprite-arrow', null, null, null, true).setAttribute('title', mxResources.get('arrow'));
+ this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
+ ['arrow', null, null, null], 'geIcon geSprite geSprite-simplearrow', null, null, null, true).setAttribute('title', mxResources.get('simpleArrow'));
+ }));
+
+ var altPattern = this.editorUi.toolbar.addMenuFunctionInContainer(altStylePanel, 'geSprite-orthogonal', mxResources.get('pattern'), false, mxUtils.bind(this, function(menu)
+ {
+ addItem(menu, 33, 'solid', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], [null, null]).setAttribute('title', mxResources.get('solid'));
+ addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', null]).setAttribute('title', mxResources.get('dashed') + ' (1)');
+ addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '8 8']).setAttribute('title', mxResources.get('dashed') + ' (2)');
+ addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '12 12']).setAttribute('title', mxResources.get('dashed') + ' (3)');
+ addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 1']).setAttribute('title', mxResources.get('dotted') + ' (1)');
+ addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 2']).setAttribute('title', mxResources.get('dotted') + ' (2)');
+ addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 4']).setAttribute('title', mxResources.get('dotted') + ' (3)');
+ }));
+
+ var stylePanel2 = stylePanel.cloneNode(false);
+
+ // Stroke width
+ var input = document.createElement('input');
+ input.style.position = 'absolute';
+ input.style.textAlign = 'right';
+ input.style.marginTop = '2px';
+ input.style.width = '52px';
+ input.style.height = '22px';
+ input.style.left = '146px';
+ input.style.borderWidth = '1px';
+ input.style.borderStyle = 'solid';
+ input.style.boxSizing = 'border-box';
+ input.setAttribute('title', mxResources.get('linewidth'));
+
+ stylePanel.appendChild(input);
+
+ var altInput = input.cloneNode(true);
+ altStylePanel.appendChild(altInput);
+
+ function update(evt)
+ {
+ // Maximum stroke width is 999
+ var value = parseFloat(input.value);
+ value = Math.min(999, Math.max(0, (isNaN(value)) ? 1 : value));
+
+ if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1))
+ {
+ graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_STROKEWIDTH],
+ 'values', [value], 'cells', ss.cells));
+ }
+
+ input.value = value + ' pt';
+ mxEvent.consume(evt);
+ };
+
+ function altUpdate(evt)
+ {
+ // Maximum stroke width is 999
+ var value = parseFloat(altInput.value);
+ value = Math.min(999, Math.max(0, (isNaN(value)) ? 1 : value));
+
+ if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1))
+ {
+ graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_STROKEWIDTH],
+ 'values', [value], 'cells', ss.cells));
+ }
+
+ altInput.value = value + ' pt';
+ mxEvent.consume(evt);
+ };
+
+ var stepper = this.createStepper(input, update, 1, 9);
+ stepper.style.display = input.style.display;
+ stepper.style.top = '2px';
+ stepper.style.left = '198px';
+ stylePanel.appendChild(stepper);
+
+ var altStepper = this.createStepper(altInput, altUpdate, 1, 9);
+ altStepper.style.display = altInput.style.display;
+ altInput.style.position = 'absolute';
+ altStepper.style.top = '2px';
+ altStepper.style.left = '198px';
+ altStylePanel.appendChild(altStepper);
+
+ mxEvent.addListener(input, 'blur', update);
+ mxEvent.addListener(input, 'change', update);
+
+ mxEvent.addListener(altInput, 'blur', altUpdate);
+ mxEvent.addListener(altInput, 'change', altUpdate);
+
+ var edgeStyle = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-orthogonal', mxResources.get('waypoints'), false, mxUtils.bind(this, function(menu)
+ {
+ if (ss.style.shape != 'arrow')
+ {
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], [null, null, null], 'geIcon geSprite geSprite-straight', null, true).setAttribute('title', mxResources.get('straight'));
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', null, null], 'geIcon geSprite geSprite-orthogonal', null, true).setAttribute('title', mxResources.get('orthogonal'));
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalelbow', null, true).setAttribute('title', mxResources.get('vertical'));
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalelbow', null, true).setAttribute('title', mxResources.get('horizontal'));
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalisometric', null, true).setAttribute('title', mxResources.get('isometric'));
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalisometric', null, true).setAttribute('title', mxResources.get('isometric'));
+
+ if (ss.style.shape == 'connector')
+ {
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', '1', null], 'geIcon geSprite geSprite-curved', null, true).setAttribute('title', mxResources.get('curved'));
+ }
+
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['entityRelationEdgeStyle', null, null], 'geIcon geSprite geSprite-entity', null, true).setAttribute('title', mxResources.get('entityRelation'));
+ }
+ }));
+
+ var lineStart = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-startclassic', mxResources.get('linestart'), false, mxUtils.bind(this, function(menu)
+ {
+ if (ss.style.shape == 'connector' || ss.style.shape == 'flexArrow' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
+ {
+ var item = this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.NONE, 0], 'geIcon', null, false);
+ item.setAttribute('title', mxResources.get('none'));
+
+ var font = document.createElement('span');
+ font.style.fontSize = '11px';
+ mxUtils.write(font, mxResources.get('none'));
+ item.firstChild.firstChild.appendChild(font);
+
+ if (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
+ {
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC, 1], null, null, false, Format.classicFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC_THIN, 1], null, null, false, Format.classicThinFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OPEN, 0], null, null, false, Format.openFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OPEN_THIN, 0], null, null, false, Format.openThinFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['openAsync', 0], null, null, false, Format.openAsyncFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK, 1], null, null, false, Format.blockFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK_THIN, 1], null, null, false, Format.blockThinFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['async', 1], null, null, false, Format.asyncFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OVAL, 1], null, null, false, Format.ovalFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND, 1], null, null, false, Format.diamondFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND_THIN, 1], null, null, false, Format.diamondThinFilledMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC, 0], null, null, false, Format.classicMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC_THIN, 0], null, null, false, Format.classicThinMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK, 0], null, null, false, Format.blockMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK_THIN, 0], null, null, false, Format.blockThinMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['async', 0], null, null, false, Format.asyncMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OVAL, 0], null, null, false, Format.ovalMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND, 0], null, null, false, Format.diamondMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND_THIN, 0], null, null, false, Format.diamondThinMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['box', 0], null, null, false, Format.boxMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['halfCircle', 0], null, null, false, Format.halfCircleMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['dash', 0], null, null, false, Format.dashMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['cross', 0], null, null, false, Format.crossMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['circlePlus', 0], null, null, false, Format.circlePlusMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['circle', 1], null, null, false, Format.circleMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['baseDash', 0], null, null, false, Format.baseDashMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERone', 0], null, null, false, Format.EROneMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERmandOne', 0], null, null, false, Format.ERmandOneMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERmany', 0], null, null, false, Format.ERmanyMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERoneToMany', 0], null, null, false, Format.ERoneToManyMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERzeroToOne', 0], null, null, false, Format.ERzeroToOneMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERzeroToMany', 0], null, null, false, Format.ERzeroToManyMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['doubleBlock', 0], null, null, false, Format.doubleBlockMarkerImage.src));
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['doubleBlock', 1], null, null, false, Format.doubleBlockFilledMarkerImage.src));
+ }
+ else
+ {
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW], [mxConstants.ARROW_BLOCK], 'geIcon geSprite geSprite-startblocktrans', null, false).setAttribute('title', mxResources.get('block'));
+ }
+
+ menu.div.style.width = '40px';
+
+ window.setTimeout(mxUtils.bind(this, function()
+ {
+ if (menu.div != null)
+ {
+ mxUtils.fit(menu.div);
+ }
+ }), 0);
+ }
+ }));
+
+ var lineEnd = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-endclassic', mxResources.get('lineend'), false, mxUtils.bind(this, function(menu)
+ {
+ if (ss.style.shape == 'connector' || ss.style.shape == 'flexArrow' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
+ {
+ var item = this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.NONE, 0], 'geIcon', null, false);
+ item.setAttribute('title', mxResources.get('none'));
+
+ var font = document.createElement('span');
+ font.style.fontSize = '11px';
+ mxUtils.write(font, mxResources.get('none'));
+ item.firstChild.firstChild.appendChild(font);
+
+ if (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
+ {
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC, 1], null, null, false, Format.classicFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC_THIN, 1], null, null, false, Format.classicThinFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OPEN, 0], null, null, false, Format.openFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OPEN_THIN, 0], null, null, false, Format.openThinFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['openAsync', 0], null, null, false, Format.openAsyncFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK, 1], null, null, false, Format.blockFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK_THIN, 1], null, null, false, Format.blockThinFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['async', 1], null, null, false, Format.asyncFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OVAL, 1], null, null, false, Format.ovalFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND, 1], null, null, false, Format.diamondFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND_THIN, 1], null, null, false, Format.diamondThinFilledMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC, 0], null, null, false, Format.classicMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC_THIN, 0], null, null, false, Format.classicThinMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK, 0], null, null, false, Format.blockMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK_THIN, 0], null, null, false, Format.blockThinMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['async', 0], null, null, false, Format.asyncMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OVAL, 0], null, null, false, Format.ovalMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND, 0], null, null, false, Format.diamondMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND_THIN, 0], null, null, false, Format.diamondThinMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['box', 0], null, null, false, Format.boxMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['halfCircle', 0], null, null, false, Format.halfCircleMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['dash', 0], null, null, false, Format.dashMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['cross', 0], null, null, false, Format.crossMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['circlePlus', 0], null, null, false, Format.circlePlusMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['circle', 0], null, null, false, Format.circleMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['baseDash', 0], null, null, false, Format.baseDashMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERone', 0], null, null, false, Format.EROneMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERmandOne', 0], null, null, false, Format.ERmandOneMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERmany', 0], null, null, false, Format.ERmanyMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERoneToMany', 0], null, null, false, Format.ERoneToManyMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERzeroToOne', 0], null, null, false, Format.ERzeroToOneMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERzeroToMany', 0], null, null, false, Format.ERzeroToManyMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['doubleBlock', 0], null, null, false, Format.doubleBlockMarkerImage.src), 'scaleX(-1)');
+ Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['doubleBlock', 1], null, null, false, Format.doubleBlockFilledMarkerImage.src), 'scaleX(-1)');
+ }
+ else
+ {
+ this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW], [mxConstants.ARROW_BLOCK], 'geIcon geSprite geSprite-endblocktrans', null, false).setAttribute('title', mxResources.get('block'));
+ }
+
+ menu.div.style.width = '40px';
+
+ window.setTimeout(mxUtils.bind(this, function()
+ {
+ if (menu.div != null)
+ {
+ mxUtils.fit(menu.div);
+ }
+ }), 0);
+ }
+ }));
+
+ this.addArrow(edgeShape);
+ this.addArrow(edgeStyle).style.marginTop = '-1px';
+ this.addArrow(lineStart);
+ this.addArrow(lineEnd);
+
+ var symbol = this.addArrow(pattern);
+ symbol.className = 'geIcon';
+ pattern.style.width = '134px';
+
+ var altSymbol = this.addArrow(altPattern);
+ altSymbol.className = 'geIcon';
+ altSymbol.style.width = '22px';
+
+ var solid = document.createElement('div');
+ solid.style.width = '102px';
+ solid.style.height = '10px';
+ solid.style.borderBottom = '1px solid ' + this.defaultStrokeColor;
+ solid.style.marginLeft = '10px';
+ symbol.appendChild(solid);
+
+ var altSolid = document.createElement('div');
+ altSolid.style.width = '30px';
+ altSolid.style.height = '10px';
+ altSolid.style.borderBottom = '1px solid ' + this.defaultStrokeColor;
+ altSolid.style.marginLeft = '10px';
+ altSymbol.appendChild(altSolid);
+
+ container.appendChild(colorPanel);
+ container.appendChild(altStylePanel);
+ container.appendChild(stylePanel);
+
+ var arrowPanel = stylePanel.cloneNode(false);
+ arrowPanel.style.display = 'block';
+ arrowPanel.style.padding = '5px 4px 6px 0px';
+ arrowPanel.style.fontWeight = 'normal';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.maxWidth = '78px';
+ span.style.overflow = 'hidden';
+ span.style.textOverflow = 'ellipsis';
+ span.style.marginLeft = '0px';
+ span.style.marginBottom = '12px';
+ span.style.marginTop = '2px';
+ span.style.fontWeight = 'normal';
+
+ mxUtils.write(span, mxResources.get('lineend'));
+ arrowPanel.appendChild(span);
+
+ var endSpacingUpdate, endSizeUpdate;
+ var endSpacing = this.addUnitInput(arrowPanel, 'pt', 98, 52, function()
+ {
+ endSpacingUpdate.apply(this, arguments);
+ });
+ var endSize = this.addUnitInput(arrowPanel, 'pt', 30, 52, function()
+ {
+ endSizeUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(arrowPanel);
+
+ var spacer = document.createElement('div');
+ spacer.style.height = '8px';
+ arrowPanel.appendChild(spacer);
+
+ span = span.cloneNode(false);
+ mxUtils.write(span, mxResources.get('linestart'));
+ arrowPanel.appendChild(span);
+
+ var startSpacingUpdate, startSizeUpdate;
+ var startSpacing = this.addUnitInput(arrowPanel, 'pt', 98, 52, function()
+ {
+ startSpacingUpdate.apply(this, arguments);
+ });
+ var startSize = this.addUnitInput(arrowPanel, 'pt', 30, 52, function()
+ {
+ startSizeUpdate.apply(this, arguments);
+ });
+
+ mxUtils.br(arrowPanel);
+ this.addLabel(arrowPanel, mxResources.get('spacing'),
+ 98, 64).style.fontSize = '11px';
+ this.addLabel(arrowPanel, mxResources.get('size'),
+ 30, 64).style.fontSize = '11px';
+ mxUtils.br(arrowPanel);
+
+ var perimeterPanel = colorPanel.cloneNode(false);
+ perimeterPanel.style.fontWeight = 'normal';
+ perimeterPanel.style.position = 'relative';
+ perimeterPanel.style.paddingLeft = '16px'
+ perimeterPanel.style.marginBottom = '2px';
+ perimeterPanel.style.marginTop = '6px';
+ perimeterPanel.style.borderWidth = '0px';
+ perimeterPanel.style.paddingBottom = '18px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.marginLeft = '3px';
+ span.style.marginBottom = '12px';
+ span.style.marginTop = '1px';
+ span.style.fontWeight = 'normal';
+ span.style.width = '120px';
+ mxUtils.write(span, mxResources.get('perimeter'));
+ perimeterPanel.appendChild(span);
+
+ var perimeterUpdate;
+ var perimeterSpacing = this.addUnitInput(perimeterPanel, 'pt', 30, 52, function()
+ {
+ perimeterUpdate.apply(this, arguments);
+ });
+
+ if (ss.edges.length == ss.cells.length)
+ {
+ container.appendChild(stylePanel2);
+ container.appendChild(arrowPanel);
+ }
+ else if (ss.vertices.length == ss.cells.length)
+ {
+ container.appendChild(perimeterPanel);
+ }
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ ss = ui.getSelectionState();
+
+ if (force || document.activeElement != input)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1));
+ input.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != altInput)
+ {
+ var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1));
+ altInput.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ styleSelect.style.visibility = (ss.style.shape == 'connector' ||
+ ss.style.shape == 'filledEdge' || ss.style.shape == 'wire') ?
+ '' : 'hidden';
+
+ if (mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == '1')
+ {
+ styleSelect.value = 'curved';
+ }
+ else if (mxUtils.getValue(ss.style, mxConstants.STYLE_ROUNDED, null) == '1')
+ {
+ styleSelect.value = 'rounded';
+ }
+
+ if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASHED, null) == '1')
+ {
+ if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASH_PATTERN, null) == null ||
+ String(mxUtils.getValue(ss.style, mxConstants.STYLE_DASH_PATTERN, '')).substring(0, 2) != '1 ')
+ {
+ solid.style.borderBottom = '1px dashed ' + this.defaultStrokeColor;
+ }
+ else
+ {
+ solid.style.borderBottom = '1px dotted ' + this.defaultStrokeColor;
+ }
+ }
+ else
+ {
+ solid.style.borderBottom = '1px solid ' + this.defaultStrokeColor;
+ }
+
+ altSolid.style.borderBottom = solid.style.borderBottom;
+
+ // Updates toolbar icon for edge style
+ var edgeStyleDiv = edgeStyle.getElementsByTagName('div')[0];
+
+ if (edgeStyleDiv != null)
+ {
+ var es = mxUtils.getValue(ss.style, mxConstants.STYLE_EDGE, null);
+
+ if (mxUtils.getValue(ss.style, mxConstants.STYLE_NOEDGESTYLE, null) == '1')
+ {
+ es = null;
+ }
+
+ if (es == 'orthogonalEdgeStyle' && mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == '1')
+ {
+ edgeStyleDiv.className = 'geSprite geSprite-curved';
+ }
+ else if (es == 'straight' || es == 'none' || es == null)
+ {
+ edgeStyleDiv.className = 'geSprite geSprite-straight';
+ }
+ else if (es == 'entityRelationEdgeStyle')
+ {
+ edgeStyleDiv.className = 'geSprite geSprite-entity';
+ }
+ else if (es == 'elbowEdgeStyle')
+ {
+ edgeStyleDiv.className = 'geSprite ' + ((mxUtils.getValue(ss.style,
+ mxConstants.STYLE_ELBOW, null) == 'vertical') ?
+ 'geSprite-verticalelbow' : 'geSprite-horizontalelbow');
+ }
+ else if (es == 'isometricEdgeStyle')
+ {
+ edgeStyleDiv.className = 'geSprite ' + ((mxUtils.getValue(ss.style,
+ mxConstants.STYLE_ELBOW, null) == 'vertical') ?
+ 'geSprite-verticalisometric' : 'geSprite-horizontalisometric');
+ }
+ else
+ {
+ edgeStyleDiv.className = 'geSprite geSprite-orthogonal';
+ }
+ }
+
+ // Updates icon for edge shape
+ var edgeShapeDiv = edgeShape.getElementsByTagName('div')[0];
+
+ if (edgeShapeDiv != null)
+ {
+ if (ss.style.shape == 'link')
+ {
+ edgeShapeDiv.className = 'geSprite geSprite-linkedge';
+ }
+ else if (ss.style.shape == 'flexArrow')
+ {
+ edgeShapeDiv.className = 'geSprite geSprite-arrow';
+ }
+ else if (ss.style.shape == 'arrow')
+ {
+ edgeShapeDiv.className = 'geSprite geSprite-simplearrow';
+ }
+ else
+ {
+ edgeShapeDiv.className = 'geSprite geSprite-connection';
+ }
+ }
+
+ if (ss.edges.length == ss.cells.length)
+ {
+ altStylePanel.style.display = '';
+ stylePanel.style.display = 'none';
+ }
+ else
+ {
+ altStylePanel.style.display = 'none';
+ stylePanel.style.display = '';
+ }
+
+ if (Graph.lineJumpsEnabled && ss.edges.length > 0 &&
+ ss.vertices.length == 0 && ss.lineJumps)
+ {
+ container.style.borderBottomStyle = 'none';
+ }
+
+ function updateArrow(marker, fill, elt, prefix)
+ {
+ var markerDiv = elt.getElementsByTagName('div')[0];
+
+ if (markerDiv != null)
+ {
+ ui.updateCssForMarker(markerDiv, prefix, ss.style.shape, marker, fill);
+ }
+
+ return markerDiv;
+ };
+
+ var sourceDiv = updateArrow(mxUtils.getValue(ss.style, mxConstants.STYLE_STARTARROW, null),
+ mxUtils.getValue(ss.style, 'startFill', '1'), lineStart, 'start');
+ var targetDiv = updateArrow(mxUtils.getValue(ss.style, mxConstants.STYLE_ENDARROW, null),
+ mxUtils.getValue(ss.style, 'endFill', '1'), lineEnd, 'end');
+
+ // Special cases for markers
+ if (sourceDiv != null && targetDiv != null)
+ {
+ if (ss.style.shape == 'arrow')
+ {
+ sourceDiv.className = 'geSprite geSprite-noarrow';
+ targetDiv.className = 'geSprite geSprite-endblocktrans';
+ }
+ else if (ss.style.shape == 'link')
+ {
+ sourceDiv.className = 'geSprite geSprite-noarrow';
+ targetDiv.className = 'geSprite geSprite-noarrow';
+ }
+ }
+
+ mxUtils.setOpacity(edgeStyle, (ss.style.shape == 'arrow') ? 30 : 100);
+
+ if (ss.style.shape != 'connector' && ss.style.shape != 'flexArrow' &&
+ ss.style.shape != 'filledEdge' && ss.style.shape != 'wire')
+ {
+ mxUtils.setOpacity(lineStart, 30);
+ mxUtils.setOpacity(lineEnd, 30);
+ }
+ else
+ {
+ mxUtils.setOpacity(lineStart, 100);
+ mxUtils.setOpacity(lineEnd, 100);
+ }
+
+ if (force || document.activeElement != startSize)
+ {
+ var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE));
+ startSize.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != startSpacing)
+ {
+ var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_SOURCE_PERIMETER_SPACING, 0));
+ startSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != endSize)
+ {
+ var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE));
+ endSize.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != startSpacing)
+ {
+ var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_TARGET_PERIMETER_SPACING, 0));
+ endSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+
+ if (force || document.activeElement != perimeterSpacing)
+ {
+ var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_PERIMETER_SPACING, 0));
+ perimeterSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+ });
+
+ startSizeUpdate = this.installInputHandler(startSize, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE, 0, 999, ' pt');
+ startSpacingUpdate = this.installInputHandler(startSpacing, mxConstants.STYLE_SOURCE_PERIMETER_SPACING, 0, -999, 999, ' pt');
+ endSizeUpdate = this.installInputHandler(endSize, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE, 0, 999, ' pt');
+ endSpacingUpdate = this.installInputHandler(endSpacing, mxConstants.STYLE_TARGET_PERIMETER_SPACING, 0, -999, 999, ' pt');
+ perimeterUpdate = this.installInputHandler(perimeterSpacing, mxConstants.STYLE_PERIMETER_SPACING, 0, 0, 999, ' pt');
+
+ this.addKeyHandler(input, listener);
+ this.addKeyHandler(startSize, listener);
+ this.addKeyHandler(startSpacing, listener);
+ this.addKeyHandler(endSize, listener);
+ this.addKeyHandler(endSpacing, listener);
+ this.addKeyHandler(perimeterSpacing, listener);
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+
+ return container;
+};
+
+/**
+ * Adds UI for configuring line jumps.
+ */
+StyleFormatPanel.prototype.addLineJumps = function(container)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var ss = ui.getSelectionState();
+
+ if (Graph.lineJumpsEnabled && ss.edges.length > 0 &&
+ ss.vertices.length == 0 && ss.lineJumps)
+ {
+ container.style.padding = '2px 0px 24px 14px';
+
+ var span = document.createElement('div');
+ span.style.position = 'absolute';
+ span.style.maxWidth = '78px';
+ span.style.overflow = 'hidden';
+ span.style.textOverflow = 'ellipsis';
+
+ mxUtils.write(span, mxResources.get('lineJumps'));
+ container.appendChild(span);
+
+ var styleSelect = document.createElement('select');
+ styleSelect.style.position = 'absolute';
+ styleSelect.style.height = '21px';
+ styleSelect.style.padding = '0px';
+ styleSelect.style.marginTop = '-2px';
+ styleSelect.style.boxSizing = 'border-box';
+ styleSelect.style.textAlign = 'center';
+ styleSelect.style.right = '84px';
+ styleSelect.style.width = '64px';
+ styleSelect.style.borderWidth = '1px';
+ styleSelect.style.borderStyle = 'solid';
+
+ var styles = ['none', 'arc', 'gap', 'sharp', 'line'];
+
+ for (var i = 0; i < styles.length; i++)
+ {
+ var styleOption = document.createElement('option');
+ styleOption.setAttribute('value', styles[i]);
+ mxUtils.write(styleOption, mxResources.get(styles[i]));
+ styleSelect.appendChild(styleOption);
+ }
+
+ mxEvent.addListener(styleSelect, 'change', function(evt)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ graph.setCellStyles('jumpStyle', styleSelect.value, ss.cells);
+ ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['jumpStyle'],
+ 'values', [styleSelect.value], 'cells', ss.cells));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+
+ mxEvent.consume(evt);
+ });
+
+ // Stops events from bubbling to color option event handler
+ mxEvent.addListener(styleSelect, 'click', function(evt)
+ {
+ mxEvent.consume(evt);
+ });
+
+ container.appendChild(styleSelect);
+
+ var jumpSizeUpdate;
+
+ var jumpSize = this.addUnitInput(container, 'pt', 16, 52, function()
+ {
+ jumpSizeUpdate.apply(this, arguments);
+ });
+
+ jumpSizeUpdate = this.installInputHandler(jumpSize, 'jumpSize',
+ Graph.defaultJumpSize, 0, 999, ' pt');
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ ss = ui.getSelectionState();
+ styleSelect.value = mxUtils.getValue(ss.style, 'jumpStyle', 'none');
+
+ if (force || document.activeElement != jumpSize)
+ {
+ var tmp = parseInt(mxUtils.getValue(ss.style, 'jumpSize', Graph.defaultJumpSize));
+ jumpSize.value = (isNaN(tmp)) ? '' : tmp + ' pt';
+ }
+ });
+
+ this.addKeyHandler(jumpSize, listener);
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+ }
+ else
+ {
+ container.style.display = 'none';
+ }
+
+ return container;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addEffects = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var ss = ui.getSelectionState();
+
+ div.style.paddingTop = '4px';
+ div.style.paddingBottom = '4px';
+
+ var table = document.createElement('table');
+
+ table.style.width = '210px';
+ table.style.fontWeight = 'bold';
+ table.style.tableLayout = 'fixed';
+ var tbody = document.createElement('tbody');
+ var row = document.createElement('tr');
+ row.style.padding = '0px';
+ var left = document.createElement('td');
+ left.style.padding = '0px';
+ left.style.width = '50%';
+ left.setAttribute('valign', 'top');
+
+ var right = left.cloneNode(true);
+ right.style.paddingLeft = '8px';
+ row.appendChild(left);
+ row.appendChild(right);
+ tbody.appendChild(row);
+ table.appendChild(tbody);
+ div.appendChild(table);
+
+ var current = left;
+
+ var addOption = mxUtils.bind(this, function(label, key, defaultValue, fn)
+ {
+ var opt = this.createCellOption(label, key, defaultValue, null, null, fn);
+ opt.style.width = '100%';
+ current.appendChild(opt);
+ current = (current == left) ? right : left;
+ });
+
+ var listener = mxUtils.bind(this, function(sender, evt, force)
+ {
+ ss = ui.getSelectionState();
+
+ left.innerText = '';
+ right.innerText = '';
+ current = left;
+
+ if (ss.rounded)
+ {
+ addOption(mxResources.get('rounded'), mxConstants.STYLE_ROUNDED, 0);
+ }
+
+ if (ss.swimlane)
+ {
+ addOption(mxResources.get('divider'), 'swimlaneLine', 1);
+ }
+
+ addOption(mxResources.get('sketch'), 'sketch', 0, function(cells, enabled)
+ {
+ graph.updateCellStyles({'sketch': (enabled) ? '1' : null,
+ 'curveFitting': (enabled) ? Editor.sketchDefaultCurveFitting : null,
+ 'jiggle': (enabled) ? Editor.sketchDefaultJiggle : null}, cells);
+ });
+
+ if (ss.glass)
+ {
+ addOption(mxResources.get('glass'), mxConstants.STYLE_GLASS, 0);
+ }
+
+ if (!ss.containsImage)
+ {
+ addOption(mxResources.get('shadow'), mxConstants.STYLE_SHADOW, 0);
+ }
+ });
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+ listener();
+
+ return div;
+}
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+StyleFormatPanel.prototype.addStyleOps = function(div)
+{
+ var ss = this.editorUi.getSelectionState();
+
+ if (ss.cells.length == 1)
+ {
+ this.addActions(div, ['setAsDefaultStyle']);
+ }
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramStylePanel = function(format, editorUi, container)
+{
+ BaseFormatPanel.call(this, format, editorUi, container);
+ this.init();
+};
+
+mxUtils.extend(DiagramStylePanel, BaseFormatPanel);
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramStylePanel.prototype.init = function()
+{
+ var ui = this.editorUi;
+
+ this.darkModeChangedListener = mxUtils.bind(this, function()
+ {
+ this.format.cachedStyleEntries = [];
+ });
+
+ ui.addListener('darkModeChanged', this.darkModeChangedListener);
+ this.container.appendChild(this.addView(this.createPanel()));
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramStylePanel.prototype.getGlobalStyleButtons = function()
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ var buttons = [mxUtils.button(mxResources.get('sketch'), mxUtils.bind(this, function(evt)
+ {
+ var value = !Editor.sketchMode;
+ graph.updateCellStyles({'sketch': (value) ? '1' : null,
+ 'curveFitting': (value) ? Editor.sketchDefaultCurveFitting : null,
+ 'jiggle': (value) ? Editor.sketchDefaultJiggle : null},
+ graph.getVerticesAndEdges());
+ ui.setSketchMode(value);
+ mxEvent.consume(evt);
+ })), mxUtils.button(mxResources.get('rounded'), mxUtils.bind(this, function(evt)
+ {
+ // Checks if all cells are rounded
+ var cells = graph.getVerticesAndEdges();
+ var rounded = true;
+
+ if (cells.length > 0)
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ var style = graph.getCellStyle(cells[i]);
+
+ if (mxUtils.getValue(style, mxConstants.STYLE_ROUNDED, 0) == 0)
+ {
+ rounded = false;
+ break;
+ }
+ }
+ }
+
+ rounded = !rounded;
+ graph.updateCellStyles({'rounded': (rounded) ? '1' : '0'}, cells);
+
+ if (rounded)
+ {
+ graph.currentEdgeStyle['rounded'] = '1';
+ graph.currentVertexStyle['rounded'] = '1';
+ }
+ else
+ {
+ delete graph.currentEdgeStyle['rounded'];
+ delete graph.currentVertexStyle['rounded'];
+ }
+
+ mxEvent.consume(evt);
+ }))];
+
+ return buttons;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramStylePanel.prototype.addView = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+ var model = graph.getModel();
+ var gridColor = graph.view.gridColor;
+
+ div.style.paddingTop = '2px';
+ div.style.whiteSpace = 'normal';
+
+ var opts = document.createElement('div');
+ opts.style.marginRight = '16px';
+ opts.style.paddingBottom = '2px';
+
+ var table = document.createElement('table');
+ table.style.width = '204px';
+
+ var tbody = document.createElement('tbody');
+ var row = document.createElement('tr');
+ row.style.padding = '0px';
+
+ var left = document.createElement('td');
+ left.style.textAlign = 'center';
+ left.style.padding = '2px';
+ left.style.width = '50%';
+
+ var right = left.cloneNode(true);
+ var buttons = this.getGlobalStyleButtons();
+
+ for (var i = 0; i < buttons.length; i += 2)
+ {
+ var btn = buttons[i];
+ btn.style.height = '22px';
+ btn.style.width = '92px';
+
+ left.appendChild(btn);
+ row.appendChild(left);
+
+ btn = buttons[i + 1];
+
+ if (btn != null)
+ {
+ btn.style.height = '22px';
+ btn.style.width = '92px';
+ right.appendChild(btn);
+ }
+
+ row.appendChild(right);
+ tbody.appendChild(row);
+
+ left = left.cloneNode(false);
+ right = right.cloneNode(false);
+ row = row.cloneNode(false);
+ }
+
+ table.appendChild(tbody);
+ opts.appendChild(table);
+ div.appendChild(opts);
+
+ var defaultStyles = ['fillColor', 'strokeColor', 'fontColor', 'gradientColor'];
+
+ div.style.whiteSpace = 'normal';
+ div.style.paddingLeft = '18px';
+ div.style.paddingTop = '6px';
+
+ var updateCells = mxUtils.bind(this, function(styles, graphStyle)
+ {
+ var cells = graph.getVerticesAndEdges();
+
+ model.beginUpdate();
+ try
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ var style = graph.getCellStyle(cells[i]);
+
+ // Handles special label background color
+ if (!ignoreGraphStyle && style['labelBackgroundColor'] != null)
+ {
+ graph.updateCellStyles({'labelBackgroundColor': (graphStyle != null) ?
+ graphStyle.background : null}, [cells[i]]);
+ }
+ else if (ignoreGraphStyle)
+ {
+ graph.updateCellStyles({'labelBackgroundColor': mxConstants.NONE}, [cells[i]]);
+ }
+
+ var edge = model.isEdge(cells[i]);
+ var newStyle = model.getStyle(cells[i]);
+ var current = (edge) ? graph.currentEdgeStyle : graph.currentVertexStyle;
+
+ for (var j = 0; j < styles.length; j++)
+ {
+ if ((style[styles[j]] != null && style[styles[j]] != mxConstants.NONE) ||
+ (styles[j] != mxConstants.STYLE_FILLCOLOR &&
+ styles[j] != mxConstants.STYLE_STROKECOLOR))
+ {
+ if (ignoreGraphStyle && edge && styles[j] == mxConstants.STYLE_FONTCOLOR)
+ {
+ newStyle = mxUtils.setStyle(newStyle, styles[j], 'default');
+ }
+ else
+ {
+ newStyle = mxUtils.setStyle(newStyle, styles[j], current[styles[j]]);
+ }
+ }
+ }
+
+ model.setStyle(cells[i], newStyle);
+ }
+ }
+ finally
+ {
+ model.endUpdate();
+ }
+ });
+
+ var removeStyles = mxUtils.bind(this, function(style, styles, defaultStyle)
+ {
+ if (style != null)
+ {
+ for (var j = 0; j < styles.length; j++)
+ {
+ if (((style[styles[j]] != null &&
+ style[styles[j]] != mxConstants.NONE) ||
+ (styles[j] != mxConstants.STYLE_FILLCOLOR &&
+ styles[j] != mxConstants.STYLE_STROKECOLOR)))
+ {
+ style[styles[j]] = defaultStyle[styles[j]];
+ }
+ }
+ }
+ });
+
+ var ignoreGraphStyle = true;
+
+ var applyStyle = mxUtils.bind(this, function(style, result, cell, graphStyle, theGraph)
+ {
+ if (style != null)
+ {
+ if (cell != null)
+ {
+ // Handles special label background color
+ if (!ignoreGraphStyle && result['labelBackgroundColor'] != null)
+ {
+ var bg = (graphStyle != null) ? graphStyle.background : null;
+ theGraph = (theGraph != null) ? theGraph : graph;
+
+ if (bg == null)
+ {
+ bg = theGraph.background;
+ }
+
+ if (bg == null)
+ {
+ bg = theGraph.defaultPageBackgroundColor;
+ }
+
+ result['labelBackgroundColor'] = bg;
+ }
+ else if (ignoreGraphStyle)
+ {
+ result['labelBackgroundColor'] = mxConstants.NONE;
+ }
+ }
+
+ for (var key in style)
+ {
+ if (cell == null || ((result[key] != null &&
+ result[key] != mxConstants.NONE) ||
+ (key != mxConstants.STYLE_FILLCOLOR &&
+ key != mxConstants.STYLE_STROKECOLOR)))
+ {
+ if (ignoreGraphStyle && model.isEdge(cell) &&
+ key == mxConstants.STYLE_FONTCOLOR)
+ {
+ result[key] = 'default';
+ }
+ else
+ {
+ result[key] = style[key];
+ }
+ }
+ }
+ }
+ });
+
+ var createPreview = mxUtils.bind(this, function(commonStyle, vertexStyle, edgeStyle, graphStyle, container)
+ {
+ // Wrapper needed to catch events
+ var div = document.createElement('div');
+ div.style.background = (Editor.isDarkMode() ? '#2a252f' : '#f1f3f4');
+ div.style.position = 'absolute';
+ div.style.display = 'inline-block';
+ div.style.overflow = 'hidden';
+ div.style.pointerEvents = 'none';
+ div.style.width = '100%';
+ div.style.height = '100%';
+ container.appendChild(div);
+
+ var graph2 = new Graph(div, null, null, graph.getStylesheet());
+ graph2.shapeBackgroundColor = div.style.background;
+ graph2.resetViewOnRootChange = false;
+ graph2.foldingEnabled = false;
+ graph2.gridEnabled = false;
+ graph2.autoScroll = false;
+ graph2.setTooltips(false);
+ graph2.setConnectable(false);
+ graph2.setPanning(false);
+ graph2.setEnabled(false);
+
+ graph2.getCellStyle = function(cell, resolve)
+ {
+ resolve = (resolve != null) ? resolve : true;
+ var result = mxUtils.clone(graph.getCellStyle.apply(this, arguments));
+ var defaultStyle = graph.stylesheet.getDefaultVertexStyle();
+ var appliedStyle = vertexStyle;
+
+ if (model.isEdge(cell))
+ {
+ defaultStyle = graph.stylesheet.getDefaultEdgeStyle();
+ appliedStyle = edgeStyle;
+ }
+
+ removeStyles(result, defaultStyles, defaultStyle);
+ applyStyle(commonStyle, result, cell, graphStyle, graph2);
+ applyStyle(appliedStyle, result, cell, graphStyle, graph2);
+
+ if (resolve)
+ {
+ result = graph.postProcessCellStyle(cell, result);
+ }
+
+ return result;
+ };
+
+ // Avoid HTML labels to capture events in bubble phase
+ graph2.model.beginUpdate();
+ try
+ {
+ var v1 = graph2.insertVertex(graph2.getDefaultParent(), null, 'Shape', 14, 8, 70, 36, 'strokeWidth=2;');
+ var e1 = graph2.insertEdge(graph2.getDefaultParent(), null, 'Connector', v1, v1,
+ 'edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;endSize=5;strokeWidth=2;')
+ e1.geometry.points = [new mxPoint(32, 66)];
+ e1.geometry.offset = new mxPoint(0, 8);
+ }
+ finally
+ {
+ graph2.model.endUpdate();
+ }
+ });
+
+ // Entries
+ var entries = document.createElement('div');
+ entries.style.position = 'relative';
+ entries.style.width = '210px';
+ div.appendChild(entries);
+
+ // Cached entries
+ if (this.format.cachedStyleEntries == null)
+ {
+ this.format.cachedStyleEntries = [];
+ }
+
+ function addKeys(style, result)
+ {
+ for (var key in style)
+ {
+ result.push(key);
+ }
+
+ return result;
+ };
+
+ var addEntry = mxUtils.bind(this, function(commonStyle, vertexStyle, edgeStyle, graphStyle, index)
+ {
+ var panel = this.format.cachedStyleEntries[index];
+
+ if (panel == null)
+ {
+ panel = document.createElement('div');
+ panel.style.display = 'inline-block';
+ panel.style.position = 'relative';
+ panel.style.width = '96px';
+ panel.style.height = '86px';
+ panel.style.cursor = 'pointer';
+ panel.style.border = '1px solid gray';
+ panel.style.borderRadius = '8px';
+ panel.style.margin = '1px 2px';
+ panel.style.overflow = 'hidden';
+
+ if (!ignoreGraphStyle && graphStyle != null && graphStyle.background != null)
+ {
+ panel.style.backgroundColor = graphStyle.background;
+ }
+
+ createPreview(commonStyle, vertexStyle, edgeStyle, graphStyle, panel);
+
+ mxEvent.addGestureListeners(panel, mxUtils.bind(this, function(evt)
+ {
+ panel.style.opacity = 0.5;
+ }), null, mxUtils.bind(this, function(evt)
+ {
+ panel.style.opacity = 1;
+ graph.currentVertexStyle = mxUtils.clone(graph.defaultVertexStyle);
+ graph.currentEdgeStyle = mxUtils.clone(graph.defaultEdgeStyle);
+
+ applyStyle(commonStyle, graph.currentVertexStyle);
+ applyStyle(commonStyle, graph.currentEdgeStyle);
+ applyStyle(vertexStyle, graph.currentVertexStyle);
+ applyStyle(edgeStyle, graph.currentEdgeStyle);
+
+ model.beginUpdate();
+ try
+ {
+ updateCells(addKeys(commonStyle, defaultStyles.slice()), graphStyle);
+
+ if (!ignoreGraphStyle)
+ {
+ var change = new ChangePageSetup(ui, (graphStyle != null) ? graphStyle.background : null);
+ change.ignoreImage = true;
+ model.execute(change);
+
+ model.execute(new ChangeGridColor(ui,
+ (graphStyle != null && graphStyle.gridColor != null) ?
+ graphStyle.gridColor : gridColor));
+ }
+ }
+ finally
+ {
+ model.endUpdate();
+ }
+ }));
+
+ mxEvent.addListener(panel, 'mouseenter', mxUtils.bind(this, function(evt)
+ {
+ var prev = graph.getCellStyle;
+ var prevBg = graph.background;
+ var prevGrid = graph.view.gridColor;
+
+ if (!ignoreGraphStyle)
+ {
+ graph.background = (graphStyle != null) ? graphStyle.background : null;
+ graph.view.gridColor = (graphStyle != null && graphStyle.gridColor != null) ?
+ graphStyle.gridColor : gridColor;
+ }
+
+ graph.getCellStyle = function(cell, resolve)
+ {
+ resolve = (resolve != null) ? resolve : true;
+ var result = mxUtils.clone(prev.apply(this, arguments));
+
+ var defaultStyle = graph.stylesheet.getDefaultVertexStyle();
+ var appliedStyle = vertexStyle;
+
+ if (model.isEdge(cell))
+ {
+ defaultStyle = graph.stylesheet.getDefaultEdgeStyle();
+ appliedStyle = edgeStyle;
+ }
+
+ removeStyles(result, defaultStyles, defaultStyle);
+ applyStyle(commonStyle, result, cell, graphStyle);
+ applyStyle(appliedStyle, result, cell, graphStyle);
+
+ if (resolve)
+ {
+ result = this.postProcessCellStyle(cell, result);
+ }
+
+ return result;
+ };
+
+ graph.refresh();
+ graph.getCellStyle = prev;
+ graph.background = prevBg;
+ graph.view.gridColor = prevGrid;
+ }));
+
+ mxEvent.addListener(panel, 'mouseleave', mxUtils.bind(this, function(evt)
+ {
+ graph.refresh();
+ }));
+
+ // Workaround for broken cache in IE11
+ if (!mxClient.IS_IE && !mxClient.IS_IE11)
+ {
+ this.format.cachedStyleEntries[index] = panel;
+ }
+ }
+
+ entries.appendChild(panel);
+ });
+
+ // Maximum palettes to switch the switcher
+ var maxEntries = 10;
+ var pageCount = Math.ceil(Editor.styles.length / maxEntries);
+ this.format.currentStylePage = (this.format.currentStylePage != null) ? this.format.currentStylePage : 0;
+ var dots = [];
+
+ var addEntries = mxUtils.bind(this, function()
+ {
+ if (dots.length > 0)
+ {
+ dots[this.format.currentStylePage].style.background = '#84d7ff';
+ }
+
+ for (var i = this.format.currentStylePage * maxEntries;
+ i < Math.min((this.format.currentStylePage + 1) * maxEntries,
+ Editor.styles.length); i++)
+ {
+ var s = Editor.styles[i];
+ addEntry(s.commonStyle, s.vertexStyle, s.edgeStyle, s.graph, i);
+ }
+ });
+
+ var selectPage = mxUtils.bind(this, function(index)
+ {
+ if (index >= 0 && index < pageCount)
+ {
+ dots[this.format.currentStylePage].style.background = 'transparent';
+ entries.innerText = '';
+ this.format.currentStylePage = index;
+ addEntries();
+ }
+ });
+
+ if (pageCount > 1)
+ {
+ // Selector
+ var switcher = document.createElement('div');
+ switcher.style.whiteSpace = 'nowrap';
+ switcher.style.position = 'relative';
+ switcher.style.textAlign = 'center';
+ switcher.style.paddingTop = '4px';
+ switcher.style.width = '210px';
+
+ for (var i = 0; i < pageCount; i++)
+ {
+ var dot = document.createElement('div');
+ dot.style.display = 'inline-block';
+ dot.style.width = '6px';
+ dot.style.height = '6px';
+ dot.style.marginLeft = '4px';
+ dot.style.marginRight = '3px';
+ dot.style.borderRadius = '3px';
+ dot.style.cursor = 'pointer';
+ dot.style.background = 'transparent';
+ dot.style.border = '1px solid #b5b6b7';
+
+ (mxUtils.bind(this, function(index, elt)
+ {
+ mxEvent.addListener(dot, 'click', mxUtils.bind(this, function()
+ {
+ selectPage(index);
+ }));
+ }))(i, dot);
+
+ switcher.appendChild(dot);
+ dots.push(dot);
+ }
+
+ div.appendChild(switcher);
+ addEntries();
+
+ if (pageCount < 15)
+ {
+ var left = document.createElement('div');
+ left.className = 'geAdaptiveAsset';
+ left.style.position = 'absolute';
+ left.style.left = '0px';
+ left.style.top = '0px';
+ left.style.bottom = '0px';
+ left.style.width = '24px';
+ left.style.height = '24px';
+ left.style.margin = '0px';
+ left.style.cursor = 'pointer';
+ left.style.opacity = '0.5';
+ left.style.backgroundRepeat = 'no-repeat';
+ left.style.backgroundPosition = 'center center';
+ left.style.backgroundSize = '24px 24px';
+ left.style.backgroundImage = 'url(' + Editor.previousImage + ')';
+
+ var right = left.cloneNode(false);
+ right.style.backgroundImage = 'url(' + Editor.nextImage + ')';
+ right.style.left = '';
+ right.style.right = '2px';
+
+ switcher.appendChild(left);
+ switcher.appendChild(right);
+
+ mxEvent.addListener(left, 'click', mxUtils.bind(this, function()
+ {
+ selectPage(mxUtils.mod(this.format.currentStylePage - 1, pageCount));
+ }));
+
+ mxEvent.addListener(right, 'click', mxUtils.bind(this, function()
+ {
+ selectPage(mxUtils.mod(this.format.currentStylePage + 1, pageCount));
+ }));
+
+ // Hover state
+ function addHoverState(elt)
+ {
+ mxEvent.addListener(elt, 'mouseenter', function()
+ {
+ elt.style.opacity = '1';
+ });
+ mxEvent.addListener(elt, 'mouseleave', function()
+ {
+ elt.style.opacity = '0.5';
+ });
+ };
+
+ addHoverState(left);
+ addHoverState(right);
+ }
+ }
+ else
+ {
+ addEntries();
+ }
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramStylePanel.prototype.destroy = function()
+{
+ BaseFormatPanel.prototype.destroy.apply(this, arguments);
+
+ if (this.darkModeChangedListener)
+ {
+ this.editorUi.removeListener(this.darkModeChangedListener);
+ this.darkModeChangedListener = null;
+ }
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel = function(format, editorUi, container)
+{
+ BaseFormatPanel.call(this, format, editorUi, container);
+ this.init();
+};
+
+mxUtils.extend(DiagramFormatPanel, BaseFormatPanel);
+
+/**
+ * Switch to disable page view.
+ */
+DiagramFormatPanel.showPageView = true;
+
+/**
+ * Specifies if the background image option should be shown. Default is true.
+ */
+DiagramFormatPanel.prototype.showBackgroundImageOption = true;
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.init = function()
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ this.container.appendChild(this.addView(this.createPanel()));
+
+ if (graph.isEnabled())
+ {
+ this.container.appendChild(this.addOptions(this.createPanel()));
+ this.container.appendChild(this.addPaperSize(this.createPanel()));
+ this.container.appendChild(this.addStyleOps(this.createPanel()));
+ }
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.addView = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ div.appendChild(this.createTitle(mxResources.get('view')));
+
+ // Grid
+ this.addGridOption(div);
+
+ // Page View
+ if (DiagramFormatPanel.showPageView)
+ {
+ div.appendChild(this.createOption(mxResources.get('pageView'), function()
+ {
+ return graph.pageVisible;
+ }, function(checked)
+ {
+ ui.actions.get('pageView').funct();
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(graph.pageVisible);
+ };
+
+ ui.addListener('pageViewChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ }));
+ }
+
+ if (graph.isEnabled())
+ {
+ if (this.showBackgroundImageOption)
+ {
+ var bg = this.createOption(mxResources.get('background'), function()
+ {
+ return graph.backgroundImage != null;
+ }, function(checked)
+ {
+ if (!checked)
+ {
+ var change = new ChangePageSetup(ui, null, null);
+ change.ignoreColor = true;
+
+ graph.model.execute(change);
+ }
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(graph.backgroundImage != null);
+ };
+
+ ui.addListener('backgroundImageChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ });
+
+ var input = bg.getElementsByTagName('input')[0];
+
+ if (input != null)
+ {
+ input.style.visibility = graph.backgroundImage != null ? 'visible' : 'hidden';
+ }
+
+ var label = bg.getElementsByTagName('div')[0];
+
+ if (label != null)
+ {
+ label.style.display = 'inline-block';
+ label.style.textOverflow = 'ellipsis';
+ label.style.overflow = 'hidden';
+ label.style.maxWidth = '80px';
+ }
+
+ if (mxClient.IS_FF)
+ {
+ label.style.marginTop = '1px';
+ }
+
+ var btn = mxUtils.button(mxResources.get('change') + '...', function(evt)
+ {
+ ui.showBackgroundImageDialog(null,
+ ui.editor.graph.backgroundImage,
+ ui.editor.graph.background);
+ mxEvent.consume(evt);
+ })
+
+ btn.style.position = 'absolute';
+ btn.style.height = '22px';
+ btn.style.left = '47%';
+ btn.style.marginLeft = '1px';
+ btn.style.width = '110px';
+ btn.style.maxWidth = '110px';
+
+ bg.appendChild(btn);
+ div.appendChild(bg);
+ }
+
+ var bgColor = this.createColorOption(mxResources.get('backgroundColor'), function()
+ {
+ return graph.background;
+ }, function(color)
+ {
+ var change = new ChangePageSetup(ui, color);
+ change.ignoreImage = true;
+
+ graph.model.execute(change);
+ }, '#ffffff');
+
+ bgColor.style.padding = '5px 0 1px 0';
+ div.appendChild(bgColor);
+
+ var option = this.createOption(mxResources.get('shadow'), function()
+ {
+ return graph.shadowVisible;
+ }, function(checked)
+ {
+ var change = new ChangePageSetup(ui);
+ change.ignoreColor = true;
+ change.ignoreImage = true;
+ change.shadowVisible = checked;
+
+ graph.model.execute(change);
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(graph.shadowVisible);
+ };
+
+ ui.addListener('shadowVisibleChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ });
+
+ if (!Editor.enableShadowOption)
+ {
+ option.getElementsByTagName('input')[0].setAttribute('disabled', 'disabled');
+ mxUtils.setOpacity(option, 60);
+ }
+
+ option.style.display = 'inline-flex';
+ option.style.width = '100px';
+ option.style.maxWidth = '100px';
+ option.style.marginRight = '4px';
+ div.appendChild(option);
+
+ var sketchOption = this.createOption(mxResources.get('sketch'), function()
+ {
+ return Editor.sketchMode;
+ }, function(checked)
+ {
+ ui.setSketchMode(checked);
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(Editor.sketchMode);
+ };
+
+ ui.addListener('sketchModeChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ });
+
+ sketchOption.style.display = 'inline-flex';
+ sketchOption.style.width = '104px';
+ sketchOption.style.maxWidth = '104px';
+ div.appendChild(sketchOption);
+ }
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.addOptions = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ div.appendChild(this.createTitle(mxResources.get('options')));
+
+ if (graph.isEnabled())
+ {
+ // Connection arrows
+ div.appendChild(this.createOption(mxResources.get('connectionArrows'), function()
+ {
+ return graph.connectionArrowsEnabled;
+ }, function(checked)
+ {
+ ui.actions.get('connectionArrows').funct();
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(graph.connectionArrowsEnabled);
+ };
+
+ ui.addListener('connectionArrowsChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ }));
+
+ // Connection points
+ div.appendChild(this.createOption(mxResources.get('connectionPoints'), function()
+ {
+ return graph.connectionHandler.isEnabled();
+ }, function(checked)
+ {
+ ui.actions.get('connectionPoints').funct();
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(graph.connectionHandler.isEnabled());
+ };
+
+ ui.addListener('connectionPointsChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ }));
+
+ // Guides
+ div.appendChild(this.createOption(mxResources.get('guides'), function()
+ {
+ return graph.graphHandler.guidesEnabled;
+ }, function(checked)
+ {
+ ui.actions.get('guides').funct();
+ },
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply(graph.graphHandler.guidesEnabled);
+ };
+
+ ui.addListener('guidesEnabledChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ }));
+ }
+
+ return div;
+};
+
+/**
+ *
+ */
+DiagramFormatPanel.prototype.addGridOption = function(container)
+{
+ var fPanel = this;
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+
+ var input = document.createElement('input');
+ input.style.position = 'absolute';
+ input.style.textAlign = 'right';
+ input.style.width = '48px';
+ input.style.marginTop = '-2px';
+ input.style.height = '21px';
+ input.style.borderWidth = '1px';
+ input.style.borderStyle = 'solid';
+ input.style.boxSizing = 'border-box';
+ input.value = this.inUnit(graph.getGridSize()) + ' ' + this.getUnit();
+
+ var stepper = this.createStepper(input, update, this.getUnitStep(), null, null, null, this.isFloatUnit());
+ input.style.display = (graph.isGridEnabled()) ? '' : 'none';
+ stepper.style.display = input.style.display;
+
+ mxEvent.addListener(input, 'keydown', function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ graph.container.focus();
+ mxEvent.consume(e);
+ }
+ else if (e.keyCode == 27)
+ {
+ input.value = graph.getGridSize();
+ graph.container.focus();
+ mxEvent.consume(e);
+ }
+ });
+
+ function update(evt)
+ {
+ var value = fPanel.isFloatUnit()? parseFloat(input.value) : parseInt(input.value);
+ value = fPanel.fromUnit(Math.max(fPanel.inUnit(1), (isNaN(value)) ? fPanel.inUnit(10) : value));
+
+ if (value != graph.getGridSize())
+ {
+ mxGraph.prototype.gridSize = value;
+ graph.setGridSize(value)
+ }
+
+ input.value = fPanel.inUnit(value) + ' ' + fPanel.getUnit();
+ mxEvent.consume(evt);
+ };
+
+ mxEvent.addListener(input, 'blur', update);
+ mxEvent.addListener(input, 'change', update);
+
+ input.style.right = '78px';
+ stepper.style.marginTop = (mxClient.IS_MAC && mxClient.IS_GC) ?
+ '-16px' : ((mxClient.IS_WIN) ? '-18px' : '-17px');
+ stepper.style.right = '66px';
+
+ var panel = this.createColorOption(mxResources.get('grid'), function()
+ {
+ var color = graph.view.gridColor;
+
+ return (graph.isGridEnabled()) ? color : null;
+ }, function(color)
+ {
+ var enabled = graph.isGridEnabled();
+
+ if (color == mxConstants.NONE)
+ {
+ graph.setGridEnabled(false);
+ }
+ else
+ {
+ graph.setGridEnabled(true);
+ ui.setGridColor(color);
+ }
+
+ input.style.display = (graph.isGridEnabled()) ? '' : 'none';
+ stepper.style.display = input.style.display;
+
+ if (enabled != graph.isGridEnabled())
+ {
+ graph.defaultGridEnabled = graph.isGridEnabled();
+ ui.fireEvent(new mxEventObject('gridEnabledChanged'));
+ }
+ }, Editor.isDarkMode() ? graph.view.defaultDarkGridColor : graph.view.defaultGridColor,
+ {
+ install: function(apply)
+ {
+ this.listener = function()
+ {
+ apply((graph.isGridEnabled()) ? graph.view.gridColor : null);
+ };
+
+ ui.addListener('gridColorChanged', this.listener);
+ ui.addListener('gridEnabledChanged', this.listener);
+ },
+ destroy: function()
+ {
+ ui.removeListener(this.listener);
+ }
+ });
+
+ panel.style.padding = '6px 0 0 0';
+ panel.appendChild(input);
+ panel.appendChild(stepper);
+ container.appendChild(panel);
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.addDocumentProperties = function(div)
+{
+ // Hook for subclassers
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ div.appendChild(this.createTitle(mxResources.get('options')));
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.addPaperSize = function(div)
+{
+ var ui = this.editorUi;
+ var editor = ui.editor;
+ var graph = editor.graph;
+
+ div.appendChild(this.createTitle(mxResources.get('paperSize')));
+
+ var accessor = PageSetupDialog.addPageFormatPanel(div, 'formatpanel', graph.pageFormat, function(pageFormat)
+ {
+ if (graph.pageFormat == null || graph.pageFormat.width != pageFormat.width ||
+ graph.pageFormat.height != pageFormat.height)
+ {
+ var change = new ChangePageSetup(ui, null, null, pageFormat);
+ change.ignoreColor = true;
+ change.ignoreImage = true;
+
+ graph.model.execute(change);
+ }
+ });
+
+ this.addKeyHandler(accessor.widthInput, function()
+ {
+ accessor.set(graph.pageFormat);
+ });
+
+ this.addKeyHandler(accessor.heightInput, function()
+ {
+ accessor.set(graph.pageFormat);
+ });
+
+ var listener = function()
+ {
+ accessor.set(graph.pageFormat);
+ };
+
+ ui.addListener('pageFormatChanged', listener);
+ this.listeners.push({destroy: function() { ui.removeListener(listener); }});
+
+ graph.getModel().addListener(mxEvent.CHANGE, listener);
+ this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.addStyleOps = function(div)
+{
+ this.addActions(div, ['editData']);
+ this.addActions(div, ['clearDefaultStyle']);
+
+ return div;
+};
+
+/**
+ * Adds the label menu items to the given menu and parent.
+ */
+DiagramFormatPanel.prototype.destroy = function()
+{
+ BaseFormatPanel.prototype.destroy.apply(this, arguments);
+
+ if (this.gridEnabledListener)
+ {
+ this.editorUi.removeListener(this.gridEnabledListener);
+ this.gridEnabledListener = null;
+ }
+};
+
+
+/**
+ * Configures global color schemes.
+ */
+StyleFormatPanel.prototype.defaultColorSchemes = [[{fill: '', stroke: ''}, {fill: '#f5f5f5', stroke: '#666666', font: '#333333'},
+{fill: '#dae8fc', stroke: '#6c8ebf'}, {fill: '#d5e8d4', stroke: '#82b366'},
+{fill: '#ffe6cc', stroke: '#d79b00'}, {fill: '#fff2cc', stroke: '#d6b656'},
+{fill: '#f8cecc', stroke: '#b85450'}, {fill: '#e1d5e7', stroke: '#9673a6'}],
+[{fill: '', stroke: ''}, {fill: '#60a917', stroke: '#2D7600', font: '#ffffff'},
+{fill: '#008a00', stroke: '#005700', font: '#ffffff'}, {fill: '#1ba1e2', stroke: '#006EAF', font: '#ffffff'},
+{fill: '#0050ef', stroke: '#001DBC', font: '#ffffff'}, {fill: '#6a00ff', stroke: '#3700CC', font: '#ffffff'},
+//{fill: '#aa00ff', stroke: '#7700CC', font: '#ffffff'},
+{fill: '#d80073', stroke: '#A50040', font: '#ffffff'}, {fill: '#a20025', stroke: '#6F0000', font: '#ffffff'}],
+[{fill: '#e51400', stroke: '#B20000', font: '#ffffff'}, {fill: '#fa6800', stroke: '#C73500', font: '#000000'},
+{fill: '#f0a30a', stroke: '#BD7000', font: '#000000'}, {fill: '#e3c800', stroke: '#B09500', font: '#000000'},
+{fill: '#6d8764', stroke: '#3A5431', font: '#ffffff'}, {fill: '#647687', stroke: '#314354', font: '#ffffff'},
+{fill: '#76608a', stroke: '#432D57', font: '#ffffff'}, {fill: '#a0522d', stroke: '#6D1F00', font: '#ffffff'}],
+[{fill: '', stroke: ''}, {fill: mxConstants.NONE, stroke: ''},
+{fill: '#fad7ac', stroke: '#b46504'}, {fill: '#fad9d5', stroke: '#ae4132'},
+{fill: '#b0e3e6', stroke: '#0e8088'}, {fill: '#b1ddf0', stroke: '#10739e'},
+{fill: '#d0cee2', stroke: '#56517e'}, {fill: '#bac8d3', stroke: '#23445d'}],
+[{fill: '', stroke: ''},
+{fill: '#f5f5f5', stroke: '#666666', gradient: '#b3b3b3'},
+{fill: '#dae8fc', stroke: '#6c8ebf', gradient: '#7ea6e0'},
+{fill: '#d5e8d4', stroke: '#82b366', gradient: '#97d077'},
+{fill: '#ffcd28', stroke: '#d79b00', gradient: '#ffa500'},
+{fill: '#fff2cc', stroke: '#d6b656', gradient: '#ffd966'},
+{fill: '#f8cecc', stroke: '#b85450', gradient: '#ea6b66'},
+{fill: '#e6d0de', stroke: '#996185', gradient: '#d5739d'}],
+[{fill: '', stroke: ''}, {fill: '#eeeeee', stroke: '#36393d'},
+{fill: '#f9f7ed', stroke: '#36393d'}, {fill: '#ffcc99', stroke: '#36393d'},
+{fill: '#cce5ff', stroke: '#36393d'}, {fill: '#ffff88', stroke: '#36393d'},
+{fill: '#cdeb8b', stroke: '#36393d'}, {fill: '#ffcccc', stroke: '#36393d'}]];
+
+/**
+* Configures custom color schemes.
+*/
+StyleFormatPanel.prototype.customColorSchemes = null;
+
+StyleFormatPanel.prototype.findCommonProperties = function(cell, properties, addAll)
+{
+if (properties == null) return;
+
+var handleCustomProp = function(custProperties)
+{
+ if (custProperties != null)
+ {
+ if (addAll)
+ {
+ for (var i = 0; i < custProperties.length; i++)
+ {
+ properties[custProperties[i].name] = custProperties[i];
+ }
+ }
+ else
+ {
+ for (var key in properties)
+ {
+ var found = false;
+
+ for (var i = 0; i < custProperties.length; i++)
+ {
+ if (custProperties[i].name == key && custProperties[i].type == properties[key].type)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ delete properties[key];
+ }
+ }
+ }
+ }
+};
+
+var view = this.editorUi.editor.graph.view;
+var state = view.getState(cell);
+
+if (state != null && state.shape != null)
+{
+ //Add common properties to all shapes
+ if (!state.shape.commonCustomPropAdded)
+ {
+ state.shape.commonCustomPropAdded = true;
+ state.shape.customProperties = state.shape.customProperties || [];
+
+ if (state.cell.vertex)
+ {
+ Array.prototype.push.apply(state.shape.customProperties, Editor.commonVertexProperties);
+ }
+ else
+ {
+ Array.prototype.push.apply(state.shape.customProperties, Editor.commonEdgeProperties);
+ }
+ }
+
+ handleCustomProp(state.shape.customProperties);
+}
+
+//This currently is not needed but let's keep it in case we needed in the future
+var userCustomProp = cell.getAttribute('customProperties');
+
+if (userCustomProp != null)
+{
+ try
+ {
+ handleCustomProp(JSON.parse(userCustomProp));
+ }
+ catch(e){}
+}
+};
+
+/**
+* Adds predefiend styles.
+*/
+var styleFormatPanelInit = StyleFormatPanel.prototype.init;
+
+StyleFormatPanel.prototype.init = function()
+{
+var sstate = this.editorUi.getSelectionState();
+
+if (this.defaultColorSchemes != null && this.defaultColorSchemes.length > 0 &&
+ sstate.style.shape != 'image' && !sstate.containsLabel &&
+ sstate.cells.length > 0)
+{
+ this.container.appendChild(this.addStyles(this.createPanel()));
+}
+
+styleFormatPanelInit.apply(this, arguments);
+
+if (Editor.enableCustomProperties)
+{
+ var properties = {};
+ var vertices = sstate.vertices;
+ var edges = sstate.edges;
+
+ for (var i = 0; i < vertices.length; i++)
+ {
+ this.findCommonProperties(vertices[i], properties, i == 0);
+ }
+
+ for (var i = 0; i < edges.length; i++)
+ {
+ this.findCommonProperties(edges[i], properties, vertices.length == 0 && i == 0);
+ }
+
+ if (Object.getOwnPropertyNames != null && Object.getOwnPropertyNames(properties).length > 0)
+ {
+ this.container.appendChild(this.addProperties(this.createPanel(), properties, sstate));
+ }
+}
+};
+
+/**
+* Overridden to add copy and paste style.
+*/
+var styleFormatPanelAddStyleOps = StyleFormatPanel.prototype.addStyleOps;
+
+StyleFormatPanel.prototype.addStyleOps = function(div)
+{
+var ss = this.editorUi.getSelectionState();
+
+if (ss.cells.length == 1)
+{
+ this.addActions(div, ['copyStyle', 'pasteStyle']);
+}
+else if (ss.cells.length >= 1)
+{
+ this.addActions(div, ['pasteStyle', 'pasteData']);
+}
+
+return styleFormatPanelAddStyleOps.apply(this, arguments);
+};
+
+/**
+* Initial collapsed state of the properties panel.
+*/
+EditorUi.prototype.propertiesCollapsed = true;
+
+/**
+* Create Properties Panel
+*/
+StyleFormatPanel.prototype.addProperties = function(div, properties, state)
+{
+var that = this;
+var graph = this.editorUi.editor.graph;
+var secondLevel = [];
+
+function insertAfter(newElem, curElem)
+{
+ curElem.parentNode.insertBefore(newElem, curElem.nextSibling);
+};
+
+function applyStyleVal(pName, newVal, prop, delIndex)
+{
+ graph.getModel().beginUpdate();
+ try
+ {
+ var changedProps = [];
+ var changedVals = [];
+
+ if (prop.index != null)
+ {
+ var allVals = [];
+ var curVal = prop.parentRow.nextSibling;
+
+ while(curVal && curVal.getAttribute('data-pName') == pName)
+ {
+ allVals.push(curVal.getAttribute('data-pValue'));
+ curVal = curVal.nextSibling;
+ }
+
+ if (prop.index < allVals.length)
+ {
+ if (delIndex != null)
+ {
+ allVals.splice(delIndex, 1);
+ }
+ else
+ {
+ allVals[prop.index] = newVal;
+ }
+ }
+ else
+ {
+ allVals.push(newVal);
+ }
+
+ if (prop.size != null && allVals.length > prop.size) //trim the array to the specifies size
+ {
+ allVals = allVals.slice(0, prop.size);
+ }
+
+ newVal = allVals.join(',');
+
+ if (prop.countProperty != null)
+ {
+ graph.setCellStyles(prop.countProperty, allVals.length, graph.getSelectionCells());
+
+ changedProps.push(prop.countProperty);
+ changedVals.push(allVals.length);
+ }
+ }
+
+ graph.setCellStyles(pName, newVal, graph.getSelectionCells());
+ changedProps.push(pName);
+ changedVals.push(newVal);
+
+ if (prop.dependentProps != null)
+ {
+ for (var i = 0; i < prop.dependentProps.length; i++)
+ {
+ var defVal = prop.dependentPropsDefVal[i];
+ var vals = prop.dependentPropsVals[i];
+
+ if (vals.length > newVal)
+ {
+ vals = vals.slice(0, newVal);
+ }
+ else
+ {
+ for (var j = vals.length; j < newVal; j++)
+ {
+ vals.push(defVal);
+ }
+ }
+
+ vals = vals.join(',');
+ graph.setCellStyles(prop.dependentProps[i], vals, graph.getSelectionCells());
+ changedProps.push(prop.dependentProps[i]);
+ changedVals.push(vals);
+ }
+ }
+
+ if (typeof(prop.onChange) == 'function')
+ {
+ prop.onChange(graph, newVal);
+ }
+
+ that.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', changedProps,
+ 'values', changedVals, 'cells', graph.getSelectionCells()));
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+}
+
+function setElementPos(td, elem, adjustHeight)
+{
+ var divPos = mxUtils.getOffset(div, true);
+ var pos = mxUtils.getOffset(td, true);
+ elem.style.position = 'absolute';
+ elem.style.left = (pos.x - divPos.x) + 'px';
+ elem.style.top = (pos.y - divPos.y) + 'px';
+ elem.style.width = td.offsetWidth + 'px';
+ elem.style.height = (td.offsetHeight - (adjustHeight? 4 : 0)) + 'px';
+ elem.style.zIndex = 5;
+};
+
+function createColorBtn(pName, pValue, prop)
+{
+ var clrDiv = document.createElement('div');
+ clrDiv.style.width = '32px';
+ clrDiv.style.height = '4px';
+ clrDiv.style.margin = '2px';
+ clrDiv.style.border = '1px solid black';
+ clrDiv.style.background = !pValue || pValue == 'none'? 'url(\'' + Dialog.prototype.noColorImage + '\')' : pValue;
+
+ btn = mxUtils.button('', mxUtils.bind(that, function(evt)
+ {
+ this.editorUi.pickColor(pValue, function(color)
+ {
+ clrDiv.style.background = color == 'none'? 'url(\'' + Dialog.prototype.noColorImage + '\')' : color;
+ applyStyleVal(pName, color, prop);
+ });
+ mxEvent.consume(evt);
+ }));
+
+ btn.style.height = '12px';
+ btn.style.width = '40px';
+ btn.className = 'geColorBtn';
+
+ btn.appendChild(clrDiv);
+ return btn;
+};
+
+function createDynArrList(pName, pValue, subType, defVal, countProperty, myRow, flipBkg)
+{
+ if (pValue != null)
+ {
+ var vals = pValue.split(',');
+ secondLevel.push({name: pName, values: vals, type: subType, defVal: defVal, countProperty: countProperty, parentRow: myRow, isDeletable: true, flipBkg: flipBkg});
+ }
+
+ btn = mxUtils.button('+', mxUtils.bind(that, function(evt)
+ {
+ var beforeElem = myRow;
+ var index = 0;
+
+ while (beforeElem.nextSibling != null)
+ {
+ var cur = beforeElem.nextSibling;
+ var elemPName = cur.getAttribute('data-pName');
+
+ if (elemPName == pName)
+ {
+ beforeElem = beforeElem.nextSibling;
+ index++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ var newProp = {type: subType, parentRow: myRow, index: index, isDeletable: true, defVal: defVal, countProperty: countProperty};
+ var arrItem = createPropertyRow(pName, '', newProp, index % 2 == 0, flipBkg);
+ applyStyleVal(pName, defVal, newProp);
+ insertAfter(arrItem, beforeElem);
+
+ mxEvent.consume(evt);
+ }));
+
+ btn.style.height = '16px';
+ btn.style.width = '25px';
+ btn.className = 'geColorBtn';
+
+ return btn;
+};
+
+function createStaticArrList(pName, pValue, subType, defVal, size, myRow, flipBkg)
+{
+ if (size > 0)
+ {
+ var vals = new Array(size);
+
+ var curVals = pValue != null? pValue.split(',') : [];
+
+ for (var i = 0; i < size; i++)
+ {
+ vals[i] = curVals[i] != null? curVals[i] : (defVal != null? defVal : '');
+ }
+
+ secondLevel.push({name: pName, values: vals, type: subType, defVal: defVal, parentRow: myRow, flipBkg: flipBkg, size: size});
+ }
+
+ return document.createElement('div'); //empty cell
+};
+
+function createCheckbox(pName, pValue, prop)
+{
+ var input = document.createElement('input');
+ input.type = 'checkbox';
+ input.checked = pValue == '1';
+
+ mxEvent.addListener(input, 'change', function()
+ {
+ applyStyleVal(pName, input.checked? '1' : '0', prop);
+ });
+ return input;
+};
+
+function createPropertyRow(pName, pValue, prop, isOdd, flipBkg)
+{
+ var pDiplayName = prop.dispName;
+ var pType = prop.type;
+ var row = document.createElement('tr');
+ row.className = 'gePropRow' + (flipBkg? 'Dark' : '') + (isOdd? 'Alt' : '') + ' gePropNonHeaderRow';
+ row.setAttribute('data-pName', pName);
+ row.setAttribute('data-pValue', pValue);
+ var rightAlig = false;
+
+ if (prop.index != null)
+ {
+ row.setAttribute('data-index', prop.index);
+ pDiplayName = (pDiplayName != null? pDiplayName : '') + '[' + prop.index + ']';
+ rightAlig = true;
+ }
+
+ var td = document.createElement('td');
+ td.className = 'gePropRowCell';
+ var label = mxResources.get(pDiplayName, null, pDiplayName);
+ mxUtils.write(td, label);
+ td.setAttribute('title', label);
+
+ if (rightAlig)
+ {
+ td.style.textAlign = 'right';
+ }
+
+ row.appendChild(td);
+ td = document.createElement('td');
+ td.className = 'gePropRowCell';
+
+ if (pType == 'color')
+ {
+ td.appendChild(createColorBtn(pName, pValue, prop));
+ }
+ else if (pType == 'bool' || pType == 'boolean')
+ {
+ td.appendChild(createCheckbox(pName, pValue, prop));
+ }
+ else if (pType == 'enum')
+ {
+ var pEnumList = prop.enumList;
+
+ for (var i = 0; i < pEnumList.length; i++)
+ {
+ var op = pEnumList[i];
+
+ if (op.val == pValue)
+ {
+ mxUtils.write(td, mxResources.get(op.dispName, null, op.dispName));
+ break;
+ }
+ }
+
+ mxEvent.addListener(td, 'click', mxUtils.bind(that, function()
+ {
+ var select = document.createElement('select');
+ setElementPos(td, select);
+
+ for (var i = 0; i < pEnumList.length; i++)
+ {
+ var op = pEnumList[i];
+ var opElem = document.createElement('option');
+ opElem.value = mxUtils.htmlEntities(op.val);
+ mxUtils.write(opElem, mxResources.get(op.dispName, null, op.dispName));
+ select.appendChild(opElem);
+ }
+
+ select.value = pValue;
+
+ div.appendChild(select);
+
+ mxEvent.addListener(select, 'change', function()
+ {
+ var newVal = mxUtils.htmlEntities(select.value);
+ applyStyleVal(pName, newVal, prop);
+ //set value triggers a redraw of the panel which removes the select and updates the row
+ });
+
+ select.focus();
+
+ //FF calls blur on focus! so set the event after focusing (not with selects but to be safe)
+ mxEvent.addListener(select, 'blur', function()
+ {
+ div.removeChild(select);
+ });
+ }));
+ }
+ else if (pType == 'dynamicArr')
+ {
+ td.appendChild(createDynArrList(pName, pValue, prop.subType, prop.subDefVal, prop.countProperty, row, flipBkg));
+ }
+ else if (pType == 'staticArr')
+ {
+ td.appendChild(createStaticArrList(pName, pValue, prop.subType, prop.subDefVal, prop.size, row, flipBkg));
+ }
+ else if (pType == 'readOnly')
+ {
+ var inp = document.createElement('input');
+ inp.setAttribute('readonly', '');
+ inp.value = pValue;
+ inp.style.width = '96px';
+ inp.style.borderWidth = '0px';
+ td.appendChild(inp);
+ }
+ else
+ {
+ td.innerHTML = mxUtils.htmlEntities(decodeURIComponent(pValue));
+
+ mxEvent.addListener(td, 'click', mxUtils.bind(that, function()
+ {
+ var input = document.createElement('input');
+ setElementPos(td, input, true);
+ input.value = decodeURIComponent(pValue);
+ input.className = 'gePropEditor';
+
+ if ((pType == 'int' || pType == 'float') && !prop.allowAuto)
+ {
+ input.type = 'number';
+ input.step = pType == 'int'? '1' : 'any';
+
+ if (prop.min != null)
+ {
+ input.min = parseFloat(prop.min);
+ }
+
+ if (prop.max != null)
+ {
+ input.max = parseFloat(prop.max);
+ }
+ }
+
+ div.appendChild(input);
+
+ function setInputVal()
+ {
+ var inputVal = input.value;
+ inputVal = inputVal.length == 0 && pType != 'string'? 0 : inputVal;
+
+ if (prop.allowAuto)
+ {
+ if (inputVal.trim != null && inputVal.trim().toLowerCase() == 'auto')
+ {
+ inputVal = 'auto';
+ pType = 'string';
+ }
+ else
+ {
+ inputVal = parseFloat(inputVal);
+ inputVal = isNaN(inputVal)? 0 : inputVal;
+ }
+ }
+
+ if (prop.min != null && inputVal < prop.min)
+ {
+ inputVal = prop.min;
+ }
+ else if (prop.max != null && inputVal > prop.max)
+ {
+ inputVal = prop.max;
+ }
+
+ var newVal = encodeURIComponent((pType == 'int'? parseInt(inputVal) : inputVal) + '');
+
+ applyStyleVal(pName, newVal, prop);
+ }
+
+ mxEvent.addListener(input, 'keypress', function(e)
+ {
+ if (e.keyCode == 13)
+ {
+ setInputVal();
+ //set value triggers a redraw of the panel which removes the input
+ }
+ });
+
+ input.focus();
+
+ //FF calls blur on focus! so set the event after focusing
+ mxEvent.addListener(input, 'blur', function()
+ {
+ setInputVal();
+ });
+ }));
+ }
+
+ if (prop.isDeletable)
+ {
+ var delBtn = mxUtils.button('-', mxUtils.bind(that, function(evt)
+ {
+ //delete the node by refreshing the properties
+ applyStyleVal(pName, '', prop, prop.index);
+
+ mxEvent.consume(evt);
+ }));
+
+ delBtn.style.height = '16px';
+ delBtn.style.width = '25px';
+ delBtn.style.float = 'right';
+ delBtn.className = 'geColorBtn';
+ td.appendChild(delBtn);
+ }
+
+ row.appendChild(td);
+ return row;
+};
+
+div.style.position = 'relative';
+div.style.padding = '0';
+var grid = document.createElement('table');
+grid.className = 'geProperties';
+grid.style.whiteSpace = 'nowrap';
+grid.style.width = '100%';
+//create header row
+var hrow = document.createElement('tr');
+hrow.className = 'gePropHeader';
+var th = document.createElement('th');
+th.className = 'gePropHeaderCell';
+var collapseImg = document.createElement('img');
+collapseImg.src = Sidebar.prototype.expandedImage;
+collapseImg.style.verticalAlign = 'middle';
+th.appendChild(collapseImg);
+mxUtils.write(th, mxResources.get('property'));
+hrow.style.cursor = 'pointer';
+
+var onFold = function()
+{
+ var rows = grid.querySelectorAll('.gePropNonHeaderRow');
+ var display;
+
+ if (!that.editorUi.propertiesCollapsed)
+ {
+ collapseImg.src = Sidebar.prototype.expandedImage;
+ display = '';
+ }
+ else
+ {
+ collapseImg.src = Sidebar.prototype.collapsedImage;
+ display = 'none';
+
+ for (var e = div.childNodes.length - 1; e >= 0 ; e--)
+ {
+ //Blur can be executed concurrently with this method and the element is removed before removing it here
+ try
+ {
+ var child = div.childNodes[e];
+ var nodeName = child.nodeName.toUpperCase();
+
+ if (nodeName == 'INPUT' || nodeName == 'SELECT')
+ {
+ div.removeChild(child);
+ }
+ }
+ catch(ex){}
+ }
+ }
+
+ for (var r = 0; r < rows.length; r++)
+ {
+ rows[r].style.display = display;
+ }
+};
+
+mxEvent.addListener(hrow, 'click', function()
+{
+ that.editorUi.propertiesCollapsed = !that.editorUi.propertiesCollapsed;
+ onFold();
+});
+hrow.appendChild(th);
+th = document.createElement('th');
+th.className = 'gePropHeaderCell';
+th.innerHTML = mxResources.get('value');
+hrow.appendChild(th);
+grid.appendChild(hrow);
+
+var isOdd = false;
+var flipBkg = false;
+
+var cellId = null;
+
+if (state.vertices.length == 1 && state.edges.length == 0)
+{
+ cellId = state.vertices[0].id;
+}
+else if (state.vertices.length == 0 && state.edges.length == 1)
+{
+ cellId = state.edges[0].id;
+}
+
+//Add it to top (always)
+if (cellId != null)
+{
+ grid.appendChild(createPropertyRow('id', mxUtils.htmlEntities(cellId), {dispName: 'ID', type: 'readOnly'}, true, false));
+}
+
+for (var key in properties)
+{
+ var prop = properties[key];
+
+ if (typeof(prop.isVisible) == 'function')
+ {
+ if (!prop.isVisible(state, this)) continue;
+ }
+
+ var pValue = state.style[key] != null? mxUtils.htmlEntities(state.style[key] + '') :
+ ((prop.getDefaultValue != null) ? prop.getDefaultValue(state, this) : prop.defVal); //or undefined if defVal is undefined
+
+ if (prop.type == 'separator')
+ {
+ flipBkg = !flipBkg;
+ continue;
+ }
+ else if (prop.type == 'staticArr') //if dynamic values are needed, a more elegant technique is needed to replace such values
+ {
+ prop.size = parseInt(state.style[prop.sizeProperty] || properties[prop.sizeProperty].defVal) || 0;
+ }
+ else if (prop.dependentProps != null)
+ {
+ var dependentProps = prop.dependentProps;
+ var dependentPropsVals = [];
+ var dependentPropsDefVal = [];
+
+ for (var i = 0; i < dependentProps.length; i++)
+ {
+ var propVal = state.style[dependentProps[i]];
+ dependentPropsDefVal.push(properties[dependentProps[i]].subDefVal);
+ dependentPropsVals.push(propVal != null? propVal.split(',') : []);
+ }
+
+ prop.dependentPropsDefVal = dependentPropsDefVal;
+ prop.dependentPropsVals = dependentPropsVals;
+ }
+
+ grid.appendChild(createPropertyRow(key, pValue, prop, isOdd, flipBkg));
+
+ isOdd = !isOdd;
+}
+
+for (var i = 0; i < secondLevel.length; i++)
+{
+ var prop = secondLevel[i];
+ var insertElem = prop.parentRow;
+
+ for (var j = 0; j < prop.values.length; j++)
+ {
+ //mxUtils.clone failed because of the HTM element, so manual cloning is used
+ var iProp = {type: prop.type, parentRow: prop.parentRow, isDeletable: prop.isDeletable, index: j, defVal: prop.defVal, countProperty: prop.countProperty, size: prop.size};
+ var arrItem = createPropertyRow(prop.name, prop.values[j], iProp, j % 2 == 0, prop.flipBkg);
+ insertAfter(arrItem, insertElem);
+ insertElem = arrItem;
+ }
+}
+
+div.appendChild(grid);
+onFold();
+
+return div;
+};
+
+/**
+* Creates the buttons for the predefined styles.
+*/
+StyleFormatPanel.prototype.addStyles = function(div)
+{
+if (this.defaultColorSchemes != null)
+{
+ var ui = this.editorUi;
+ var graph = ui.editor.graph;
+ var picker = document.createElement('div');
+ picker.style.whiteSpace = 'nowrap';
+ picker.style.paddingLeft = '24px';
+ picker.style.paddingRight = '20px';
+ div.style.paddingLeft = '16px';
+ div.style.paddingBottom = '6px';
+ div.style.position = 'relative';
+ div.appendChild(picker);
+
+ var stylenames = ['plain-gray', 'plain-blue', 'plain-green', 'plain-turquoise',
+ 'plain-orange', 'plain-yellow', 'plain-red', 'plain-pink', 'plain-purple', 'gray',
+ 'blue', 'green', 'turquoise', 'orange', 'yellow', 'red', 'pink', 'purple'];
+
+ // Maximum palettes to switch the switcher
+ var maxEntries = 10;
+
+ // Selector
+ var switcher = document.createElement('div');
+ switcher.style.whiteSpace = 'nowrap';
+ switcher.style.position = 'relative';
+ switcher.style.textAlign = 'center';
+ switcher.style.width = '210px';
+
+ var dots = [];
+
+ for (var i = 0; i < this.defaultColorSchemes.length; i++)
+ {
+ var dot = document.createElement('div');
+ dot.style.display = 'inline-block';
+ dot.style.width = '6px';
+ dot.style.height = '6px';
+ dot.style.marginLeft = '4px';
+ dot.style.marginRight = '3px';
+ dot.style.borderRadius = '3px';
+ dot.style.cursor = 'pointer';
+ dot.style.background = 'transparent';
+ dot.style.border = '1px solid #b5b6b7';
+
+ (mxUtils.bind(this, function(index)
+ {
+ mxEvent.addListener(dot, 'click', mxUtils.bind(this, function()
+ {
+ setScheme(index);
+ }));
+ }))(i);
+
+ dots.push(dot);
+ switcher.appendChild(dot);
+ }
+
+ var setScheme = mxUtils.bind(this, function(index)
+ {
+ if (dots[index] != null)
+ {
+ if (this.format.currentScheme != null && dots[this.format.currentScheme] != null)
+ {
+ dots[this.format.currentScheme].style.background = 'transparent';
+ }
+
+ this.format.currentScheme = index;
+ updateScheme(this.defaultColorSchemes[this.format.currentScheme]);
+ dots[this.format.currentScheme].style.background = '#84d7ff';
+ }
+ });
+
+ var updateScheme = mxUtils.bind(this, function(colorsets)
+ {
+ var addButton = mxUtils.bind(this, function(colorset)
+ {
+ var btn = mxUtils.button('', mxUtils.bind(this, function(evt)
+ {
+ graph.getModel().beginUpdate();
+ try
+ {
+ var cells = ui.getSelectionState().cells;
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ var style = graph.getModel().getStyle(cells[i]);
+
+ for (var j = 0; j < stylenames.length; j++)
+ {
+ style = mxUtils.removeStylename(style, stylenames[j]);
+ }
+
+ var defaults = (graph.getModel().isVertex(cells[i])) ? graph.defaultVertexStyle : graph.defaultEdgeStyle;
+
+ if (colorset != null)
+ {
+ if (!mxEvent.isShiftDown(evt))
+ {
+ if (colorset['fill'] == '')
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR, null);
+ }
+ else
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR, colorset['fill'] ||
+ mxUtils.getValue(defaults, mxConstants.STYLE_FILLCOLOR, null));
+ }
+
+ style = mxUtils.setStyle(style, mxConstants.STYLE_GRADIENTCOLOR, colorset['gradient'] ||
+ mxUtils.getValue(defaults, mxConstants.STYLE_GRADIENTCOLOR, null));
+
+ if (!mxEvent.isControlDown(evt) && (!mxClient.IS_MAC || !mxEvent.isMetaDown(evt)) &&
+ graph.getModel().isVertex(cells[i]))
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_FONTCOLOR, colorset['font'] ||
+ mxUtils.getValue(defaults, mxConstants.STYLE_FONTCOLOR, null));
+ }
+ }
+
+ if (!mxEvent.isAltDown(evt))
+ {
+ if (colorset['stroke'] == '')
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR, null);
+ }
+ else
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR, colorset['stroke'] ||
+ mxUtils.getValue(defaults, mxConstants.STYLE_STROKECOLOR, null));
+ }
+ }
+ }
+ else
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR,
+ mxUtils.getValue(defaults, mxConstants.STYLE_FILLCOLOR, '#ffffff'));
+ style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR,
+ mxUtils.getValue(defaults, mxConstants.STYLE_STROKECOLOR, '#000000'));
+ style = mxUtils.setStyle(style, mxConstants.STYLE_GRADIENTCOLOR,
+ mxUtils.getValue(defaults, mxConstants.STYLE_GRADIENTCOLOR, null));
+
+ if (graph.getModel().isVertex(cells[i]))
+ {
+ style = mxUtils.setStyle(style, mxConstants.STYLE_FONTCOLOR,
+ mxUtils.getValue(defaults, mxConstants.STYLE_FONTCOLOR, null));
+ }
+ }
+
+ graph.getModel().setStyle(cells[i], style);
+ }
+ }
+ finally
+ {
+ graph.getModel().endUpdate();
+ }
+ }));
+
+ btn.className = 'geStyleButton';
+ btn.style.width = '36px';
+ btn.style.height = (this.defaultColorSchemes.length <= maxEntries) ? '24px' : '30px';
+ btn.style.margin = '0px 6px 6px 0px';
+
+ if (colorset != null)
+ {
+ var b = (Editor.isDarkMode()) ? '2px solid' : '1px solid';
+
+ if (colorset['border'] != null)
+ {
+ b = colorset['border'];
+ }
+
+ if (colorset['gradient'] != null)
+ {
+ if (mxClient.IS_IE && (document.documentMode < 10))
+ {
+ btn.style.filter = 'progid:DXImageTransform.Microsoft.Gradient('+
+ 'StartColorStr=\'' + colorset['fill'] +
+ '\', EndColorStr=\'' + colorset['gradient'] + '\', GradientType=0)';
+ }
+ else
+ {
+ btn.style.backgroundImage = 'linear-gradient(' + colorset['fill'] + ' 0px,' +
+ colorset['gradient'] + ' 100%)';
+ }
+ }
+ else if (colorset['fill'] == mxConstants.NONE)
+ {
+ btn.style.background = 'url(\'' + Dialog.prototype.noColorImage + '\')';
+ }
+ else if (colorset['fill'] == '')
+ {
+ btn.style.backgroundColor = mxUtils.getValue(graph.defaultVertexStyle,
+ mxConstants.STYLE_FILLCOLOR, (Editor.isDarkMode()) ? Editor.darkColor : '#ffffff');
+ }
+ else
+ {
+ btn.style.backgroundColor = colorset['fill'] || mxUtils.getValue(graph.defaultVertexStyle,
+ mxConstants.STYLE_FILLCOLOR, (Editor.isDarkMode()) ? Editor.darkColor : '#ffffff');
+ }
+
+ if (colorset['stroke'] == mxConstants.NONE)
+ {
+ btn.style.border = b + ' transparent';
+ }
+ else if (colorset['stroke'] == '')
+ {
+ btn.style.border = b + ' ' + mxUtils.getValue(graph.defaultVertexStyle,
+ mxConstants.STYLE_STROKECOLOR, (!Editor.isDarkMode()) ? Editor.darkColor : '#ffffff');
+ }
+ else
+ {
+ btn.style.border = b + ' ' + (colorset['stroke'] || mxUtils.getValue(graph.defaultVertexStyle,
+ mxConstants.STYLE_STROKECOLOR, (!Editor.isDarkMode()) ? Editor.darkColor : '#ffffff'));
+ }
+
+ if (colorset['title'] != null)
+ {
+ btn.setAttribute('title', colorset['title']);
+ }
+ }
+ else
+ {
+ var bg = mxUtils.getValue(graph.defaultVertexStyle, mxConstants.STYLE_FILLCOLOR, '#ffffff');
+ var bd = mxUtils.getValue(graph.defaultVertexStyle, mxConstants.STYLE_STROKECOLOR, '#000000');
+
+ btn.style.backgroundColor = bg;
+ btn.style.border = '1px solid ' + bd;
+ }
+
+ btn.style.borderRadius = '0';
+
+ picker.appendChild(btn);
+ });
+
+ picker.innerText = '';
+
+ for (var i = 0; i < colorsets.length; i++)
+ {
+ if (i > 0 && mxUtils.mod(i, 4) == 0)
+ {
+ mxUtils.br(picker);
+ }
+
+ addButton(colorsets[i]);
+ }
+ });
+
+ if (this.format.currentScheme == null)
+ {
+ setScheme(Math.min(dots.length - 1, Editor.isDarkMode()
+ ? 1 : (urlParams['sketch'] == '1' ? 5 : 0)));
+ }
+ else
+ {
+ setScheme(this.format.currentScheme);
+ }
+
+ var bottom = (this.defaultColorSchemes.length <= maxEntries) ? 28 : 8;
+
+ var left = document.createElement('div');
+ left.style.cssText = 'position:absolute;left:10px;top:8px;bottom:' + bottom + 'px;width:20px;margin:4px;opacity:0.5;' +
+ 'background-repeat:no-repeat;background-position:center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAB2dnZ4eHh3d3d1dXVxcXF2dnZ2dnZ2dnZxcXF2dnYmb3w1AAAACnRSTlMAfCTkhhvb7cQSPH2JPgAAADRJREFUCNdjwACMAmBKaiGYs2oJmLPKAZ3DabU8AMRTXpUKopislqFyVzCAuUZgikkBZjoAcMYLnp53P/UAAAAASUVORK5CYII=);';
+
+ mxEvent.addListener(left, 'click', mxUtils.bind(this, function()
+ {
+ setScheme(mxUtils.mod(this.format.currentScheme - 1, this.defaultColorSchemes.length));
+ }));
+
+ var right = document.createElement('div');
+ right.style.cssText = 'position:absolute;left:202px;top:8px;bottom:' + bottom + 'px;width:20px;margin:4px;opacity:0.5;' +
+ 'background-repeat:no-repeat;background-position:center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnYBuwCcAAAACnRSTlMAfCTkhhvb7cQSPH2JPgAAADZJREFUCNdjQAOMAmBKaiGY8loF5rKswsZlrVo8AUiFrTICcbIWK8A5DF1gDoMymMPApIAwHwCS0Qx/U7qCBQAAAABJRU5ErkJggg==);';
+
+ if (this.defaultColorSchemes.length > 1)
+ {
+ div.appendChild(left);
+ div.appendChild(right);
+ }
+
+ mxEvent.addListener(right, 'click', mxUtils.bind(this, function()
+ {
+ setScheme(mxUtils.mod(this.format.currentScheme + 1, this.defaultColorSchemes.length));
+ }));
+
+ // Hover state
+ function addHoverState(elt)
+ {
+ mxEvent.addListener(elt, 'mouseenter', function()
+ {
+ elt.style.opacity = '1';
+ });
+ mxEvent.addListener(elt, 'mouseleave', function()
+ {
+ elt.style.opacity = '0.5';
+ });
+ };
+
+ addHoverState(left);
+ addHoverState(right);
+
+ updateScheme(this.defaultColorSchemes[this.format.currentScheme]);
+
+ if (this.defaultColorSchemes.length <= maxEntries)
+ {
+ div.appendChild(switcher);
+ }
+}
+
+return div;
+};
diff --git a/static/cherry/drawio_demo/Graph.js b/static/cherry/drawio_demo/Graph.js
new file mode 100644
index 000000000..534bfa99a
--- /dev/null
+++ b/static/cherry/drawio_demo/Graph.js
@@ -0,0 +1,15007 @@
+/**
+ * Copyright (c) 2006-2012, JGraph Ltd
+ */
+// Workaround for handling named HTML entities in mxUtils.parseXml
+// LATER: How to configure DOMParser to just ignore all entities?
+(function()
+{
+ var entities = [
+ ['nbsp', '160'],
+ ['shy', '173']
+ ];
+
+ var parseXml = mxUtils.parseXml;
+
+ mxUtils.parseXml = function(text)
+ {
+ for (var i = 0; i < entities.length; i++)
+ {
+ text = text.replace(new RegExp(
+ '&' + entities[i][0] + ';', 'g'),
+ '' + entities[i][1] + ';');
+ }
+
+ return parseXml(text);
+ };
+})();
+
+// Shim for missing toISOString in older versions of IE
+// See https://stackoverflow.com/questions/12907862
+if (!Date.prototype.toISOString)
+{
+ (function()
+ {
+ function pad(number)
+ {
+ var r = String(number);
+
+ if (r.length === 1)
+ {
+ r = '0' + r;
+ }
+
+ return r;
+ };
+
+ Date.prototype.toISOString = function()
+ {
+ return this.getUTCFullYear()
+ + '-' + pad( this.getUTCMonth() + 1 )
+ + '-' + pad( this.getUTCDate() )
+ + 'T' + pad( this.getUTCHours() )
+ + ':' + pad( this.getUTCMinutes() )
+ + ':' + pad( this.getUTCSeconds() )
+ + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
+ + 'Z';
+ };
+ }());
+}
+
+// Shim for Date.now()
+if (!Date.now)
+{
+ Date.now = function()
+ {
+ return new Date().getTime();
+ };
+}
+
+// Polyfill for Uint8Array.from in IE11 used in Graph.decompress
+// See https://stackoverflow.com/questions/36810940/alternative-or-polyfill-for-array-from-on-the-internet-explorer
+if (!Uint8Array.from) {
+ Uint8Array.from = (function () {
+ var toStr = Object.prototype.toString;
+ var isCallable = function (fn) {
+ return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
+ };
+ var toInteger = function (value) {
+ var number = Number(value);
+ if (isNaN(number)) { return 0; }
+ if (number === 0 || !isFinite(number)) { return number; }
+ return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
+ };
+ var maxSafeInteger = Math.pow(2, 53) - 1;
+ var toLength = function (value) {
+ var len = toInteger(value);
+ return Math.min(Math.max(len, 0), maxSafeInteger);
+ };
+
+ // The length property of the from method is 1.
+ return function from(arrayLike/*, mapFn, thisArg */) {
+ // 1. Let C be the this value.
+ var C = this;
+
+ // 2. Let items be ToObject(arrayLike).
+ var items = Object(arrayLike);
+
+ // 3. ReturnIfAbrupt(items).
+ if (arrayLike == null) {
+ throw new TypeError("Array.from requires an array-like object - not null or undefined");
+ }
+
+ // 4. If mapfn is undefined, then let mapping be false.
+ var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
+ var T;
+ if (typeof mapFn !== 'undefined') {
+ // 5. else
+ // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
+ if (!isCallable(mapFn)) {
+ throw new TypeError('Array.from: when provided, the second argument must be a function');
+ }
+
+ // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
+ if (arguments.length > 2) {
+ T = arguments[2];
+ }
+ }
+
+ // 10. Let lenValue be Get(items, "length").
+ // 11. Let len be ToLength(lenValue).
+ var len = toLength(items.length);
+
+ // 13. If IsConstructor(C) is true, then
+ // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
+ // 14. a. Else, Let A be ArrayCreate(len).
+ var A = isCallable(C) ? Object(new C(len)) : new Array(len);
+
+ // 16. Let k be 0.
+ var k = 0;
+ // 17. Repeat, while k < len… (also steps a - h)
+ var kValue;
+ while (k < len) {
+ kValue = items[k];
+ if (mapFn) {
+ A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
+ } else {
+ A[k] = kValue;
+ }
+ k += 1;
+ }
+ // 18. Let putStatus be Put(A, "length", len, true).
+ A.length = len;
+ // 20. Return A.
+ return A;
+ };
+ }());
+}
+
+/**
+ * Measurements Units
+ */
+mxConstants.POINTS = 1;
+mxConstants.MILLIMETERS = 2;
+mxConstants.INCHES = 3;
+mxConstants.METERS = 4;
+
+/**
+ * This ratio is with page scale 1
+ */
+mxConstants.PIXELS_PER_MM = 3.937;
+mxConstants.PIXELS_PER_INCH = 100;
+mxConstants.SHADOW_OPACITY = 0.25;
+mxConstants.SHADOWCOLOR = '#000000';
+mxConstants.VML_SHADOWCOLOR = '#d0d0d0';
+
+mxCodec.allowlist = ['mxStylesheet', 'Array', 'mxGraphModel',
+ 'mxCell', 'mxGeometry', 'mxRectangle', 'mxPoint',
+ 'mxChildChange', 'mxRootChange', 'mxTerminalChange',
+ 'mxValueChange', 'mxStyleChange', 'mxGeometryChange',
+ 'mxCollapseChange', 'mxVisibleChange', 'mxCellAttributeChange'];
+mxGraph.prototype.pageBreakColor = '#c0c0c0';
+mxGraph.prototype.pageScale = 1;
+
+// Letter page format is default in US, Canada and Mexico
+(function()
+{
+ try
+ {
+ if (navigator != null && navigator.language != null)
+ {
+ var lang = navigator.language.toLowerCase();
+ mxGraph.prototype.pageFormat = (lang === 'en-us' || lang === 'en-ca' || lang === 'es-mx') ?
+ mxConstants.PAGE_FORMAT_LETTER_PORTRAIT : mxConstants.PAGE_FORMAT_A4_PORTRAIT;
+ }
+ }
+ catch (e)
+ {
+ // ignore
+ }
+})();
+
+// Matches label positions of mxGraph 1.x
+mxText.prototype.baseSpacingTop = 5;
+mxText.prototype.baseSpacingBottom = 1;
+
+// Keeps edges between relative child cells inside parent
+mxGraphModel.prototype.ignoreRelativeEdgeParent = false;
+
+// Defines grid properties
+mxGraphView.prototype.gridImage = (mxClient.IS_SVG) ? 'data:image/gif;base64,R0lGODlhCgAKAJEAAAAAAP///8zMzP///yH5BAEAAAMALAAAAAAKAAoAAAIJ1I6py+0Po2wFADs=' :
+ IMAGE_PATH + '/grid.gif';
+mxGraphView.prototype.gridSteps = 4;
+mxGraphView.prototype.minGridSize = 4;
+
+// UrlParams is null in embed mode
+mxGraphView.prototype.defaultGridColor = '#d0d0d0';
+mxGraphView.prototype.defaultDarkGridColor = '#424242';
+mxGraphView.prototype.gridColor = mxGraphView.prototype.defaultGridColor;
+
+// Units
+mxGraphView.prototype.unit = mxConstants.POINTS;
+
+mxGraphView.prototype.setUnit = function(unit)
+{
+ if (this.unit != unit)
+ {
+ this.unit = unit;
+
+ this.fireEvent(new mxEventObject('unitChanged', 'unit', unit));
+ }
+};
+
+// Alternative text for unsupported foreignObjects
+mxSvgCanvas2D.prototype.foAltText = '[Not supported by viewer]';
+
+// Hook for custom constraints
+mxShape.prototype.getConstraints = function(style, w, h)
+{
+ return null;
+};
+
+// Override for clipSvg style
+mxImageShape.prototype.getImageDataUri = function()
+{
+ var src = this.image;
+
+ if (src.substring(0, 26) == 'data:image/svg+xml;base64,' && this.style != null &&
+ mxUtils.getValue(this.style, 'clipSvg', '0') == '1')
+ {
+ if (this.clippedSvg == null || this.clippedImage != src)
+ {
+ this.clippedSvg = Graph.clipSvgDataUri(src, true);
+ this.clippedImage = src;
+ }
+
+ src = this.clippedSvg;
+ }
+
+ return src;
+};
+
+// Override to use key as fallback
+(function()
+{
+ var mxResourcesGet = mxResources.get;
+
+ mxResources.get = function(key, params, defaultValue)
+ {
+ if (defaultValue == null)
+ {
+ defaultValue = key;
+ }
+
+ return mxResourcesGet.apply(this, [key, params, defaultValue]);
+ };
+
+})();
+
+/**
+ * Constructs a new graph instance. Note that the constructor does not take a
+ * container because the graph instance is needed for creating the UI, which
+ * in turn will create the container for the graph. Hence, the container is
+ * assigned later in EditorUi.
+ */
+/**
+ * Defines graph class.
+ */
+Graph = function(container, model, renderHint, stylesheet, themes, standalone)
+{
+ mxGraph.call(this, container, model, renderHint, stylesheet);
+
+ this.themes = themes || this.defaultThemes;
+ this.currentEdgeStyle = mxUtils.clone(this.defaultEdgeStyle);
+ this.currentVertexStyle = mxUtils.clone(this.defaultVertexStyle);
+ this.standalone = (standalone != null) ? standalone : false;
+
+ // Sets the base domain URL and domain path URL for relative links.
+ var b = this.baseUrl;
+ var p = b.indexOf('//');
+ this.domainUrl = '';
+ this.domainPathUrl = '';
+
+ if (p > 0)
+ {
+ var d = b.indexOf('/', p + 2);
+
+ if (d > 0)
+ {
+ this.domainUrl = b.substring(0, d);
+ }
+
+ d = b.lastIndexOf('/');
+
+ if (d > 0)
+ {
+ this.domainPathUrl = b.substring(0, d + 1);
+ }
+ }
+
+ // Adds support for HTML labels via style. Note: Currently, only the Java
+ // backend supports HTML labels but CSS support is limited to the following:
+ // http://docs.oracle.com/javase/6/docs/api/index.html?javax/swing/text/html/CSS.html
+ // TODO: Wrap should not affect isHtmlLabel output (should be handled later)
+ this.isHtmlLabel = function(cell)
+ {
+ var style = this.getCurrentCellStyle(cell);
+
+ return (style != null) ? (style['html'] == '1' || style[mxConstants.STYLE_WHITE_SPACE] == 'wrap') : false;
+ };
+
+ // Implements a listener for hover and click handling on edges and tables
+ if (this.immediateHandling)
+ {
+ var start = {
+ point: null,
+ event: null,
+ state: null,
+ handle: null,
+ selected: false
+ };
+
+ var initialSelected = false;
+
+ // Uses this event to process mouseDown to check the selection state before it is changed
+ this.addListener(mxEvent.FIRE_MOUSE_EVENT, mxUtils.bind(this, function(sender, evt)
+ {
+ if (evt.getProperty('eventName') == 'mouseDown' && this.isEnabled())
+ {
+ var me = evt.getProperty('event');
+ var state = me.getState();
+ var s = this.view.scale;
+
+ if (!mxEvent.isAltDown(me.getEvent()) && state != null)
+ {
+ initialSelected = this.isCellSelected(state.cell);
+
+ if (!this.panningHandler.isActive() && !mxEvent.isControlDown(me.getEvent()))
+ {
+ var handler = this.selectionCellsHandler.getHandler(state.cell);
+
+ // Cell handles have precedence over row and col resize
+ if (handler == null || handler.getHandleForEvent(me) == null)
+ {
+ var box = new mxRectangle(me.getGraphX() - 1, me.getGraphY() - 1);
+ var tol = mxEvent.isTouchEvent(me.getEvent()) ?
+ mxShape.prototype.svgStrokeTolerance - 1 :
+ (mxShape.prototype.svgStrokeTolerance + 2) / 2;
+ var t1 = tol + 2;
+ box.grow(tol);
+
+ // Ignores clicks inside cell to avoid delayed selection on
+ // merged cells when clicking on invisible part of dividers
+ if (this.isTableCell(state.cell) && this.isCellMovable(state.cell) &&
+ !this.isCellSelected(state.cell) &&
+ (!mxUtils.contains(state, me.getGraphX() - t1, me.getGraphY() - t1) ||
+ !mxUtils.contains(state, me.getGraphX() - t1, me.getGraphY() + t1) ||
+ !mxUtils.contains(state, me.getGraphX() + t1, me.getGraphY() + t1) ||
+ !mxUtils.contains(state, me.getGraphX() + t1, me.getGraphY() - t1)))
+ {
+ var row = this.model.getParent(state.cell);
+ var table = this.model.getParent(row);
+
+ if (!this.isCellSelected(table))
+ {
+ var b = tol * s;
+ var b2 = 2 * b;
+
+ // Ignores events on top line of top row and left line of left column
+ if ((this.model.getChildAt(table, 0) != row) && mxUtils.intersects(box,
+ new mxRectangle(state.x, state.y - b, state.width, b2)) ||
+ (this.model.getChildAt(row, 0) != state.cell) && mxUtils.intersects(box,
+ new mxRectangle(state.x - b, state.y, b2, state.height)) ||
+ mxUtils.intersects(box, new mxRectangle(state.x, state.y + state.height - b, state.width, b2)) ||
+ mxUtils.intersects(box, new mxRectangle(state.x + state.width - b, state.y, b2, state.height)))
+ {
+ var wasSelected = this.selectionCellsHandler.isHandled(table);
+ this.selectCellForEvent(table, me.getEvent());
+ handler = this.selectionCellsHandler.getHandler(table);
+
+ if (handler != null)
+ {
+ var handle = handler.getHandleForEvent(me);
+
+ if (handle != null)
+ {
+ handler.start(me.getGraphX(), me.getGraphY(), handle);
+ handler.blockDelayedSelection = !wasSelected;
+ me.consume();
+ }
+ }
+ }
+ }
+ }
+
+ // Hover for swimlane start sizes inside tables
+ var current = state;
+
+ while (!me.isConsumed() && current != null && (this.isTableCell(current.cell) ||
+ this.isTableRow(current.cell) || this.isTable(current.cell)))
+ {
+ if (this.isSwimlane(current.cell) && this.isCellMovable(current.cell))
+ {
+ var offset = this.getActualStartSize(current.cell);
+
+ if (((offset.x > 0 || offset.width > 0) && mxUtils.intersects(box, new mxRectangle(
+ current.x + (offset.x - offset.width - 1) * s + ((offset.x == 0) ? current.width : 0),
+ current.y, 1, current.height))) || ((offset.y > 0 || offset.height > 0) &&
+ mxUtils.intersects(box, new mxRectangle(current.x, current.y + (offset.y -
+ offset.height - 1) * s + ((offset.y == 0) ? current.height : 0), current.width, 1))))
+ {
+ this.selectCellForEvent(current.cell, me.getEvent());
+ handler = this.selectionCellsHandler.getHandler(current.cell);
+
+ if (handler != null && handler.customHandles != null)
+ {
+ // Swimlane start size handle is last custom handle
+ var handle = mxEvent.CUSTOM_HANDLE - handler.customHandles.length + 1;
+ handler.start(me.getGraphX(), me.getGraphY(), handle);
+ me.consume();
+ }
+ }
+ }
+
+ current = this.view.getState(this.model.getParent(current.cell));
+ }
+ }
+ }
+ }
+ }
+ }));
+
+ // Uses this event to process mouseDown to check the selection state before it is changed
+ this.addListener(mxEvent.CONSUME_MOUSE_EVENT, mxUtils.bind(this, function(sender, evt)
+ {
+ if (evt.getProperty('eventName') == 'mouseDown' && this.isEnabled())
+ {
+ var me = evt.getProperty('event');
+ var state = me.getState();
+
+ if (!mxEvent.isAltDown(me.getEvent()) && !mxEvent.isControlDown(evt) &&
+ !mxEvent.isShiftDown(evt) && !initialSelected &&
+ state != null && this.model.isEdge(state.cell))
+ {
+ start.point = new mxPoint(me.getGraphX(), me.getGraphY());
+ start.selected = this.isCellSelected(state.cell);
+ start.state = state;
+ start.event = me;
+
+ if (state.text != null && state.text.boundingBox != null &&
+ mxUtils.contains(state.text.boundingBox, me.getGraphX(), me.getGraphY()))
+ {
+ start.handle = mxEvent.LABEL_HANDLE;
+ }
+ else
+ {
+ var handler = this.selectionCellsHandler.getHandler(state.cell);
+
+ if (handler != null && handler.bends != null && handler.bends.length > 0)
+ {
+ start.handle = handler.getHandleForEvent(me);
+ }
+ }
+ }
+ }
+ }));
+
+ this.addMouseListener(
+ {
+ mouseDown: function(sender, me) {},
+ mouseMove: mxUtils.bind(this, function(sender, me)
+ {
+ // Checks if any other handler is active
+ var handlerMap = this.selectionCellsHandler.handlers.map;
+
+ for (var key in handlerMap)
+ {
+ if (handlerMap[key].index != null)
+ {
+ return;
+ }
+ }
+
+ if (this.isEnabled() && !this.panningHandler.isActive() && !mxEvent.isAltDown(me.getEvent()))
+ {
+ var tol = this.tolerance;
+
+ if (start.point != null && start.state != null && start.event != null)
+ {
+ var state = start.state;
+
+ if (start.handle != null || Math.abs(start.point.x - me.getGraphX()) > tol ||
+ Math.abs(start.point.y - me.getGraphY()) > tol)
+ {
+ var handler = null;
+
+ if (!mxEvent.isControlDown(me.getEvent()) &&
+ !mxEvent.isShiftDown(me.getEvent()))
+ {
+ handler = this.selectionCellsHandler.getHandler(state.cell);
+ }
+
+ if (handler != null && handler.bends != null && handler.bends.length > 0)
+ {
+ handler.redrawHandles();
+ var handle = (start.handle != null) ? start.handle :
+ handler.getHandleForEvent(start.event);
+ var edgeStyle = this.view.getEdgeStyle(state);
+ var entity = edgeStyle == mxEdgeStyle.EntityRelation;
+
+ // Handles special case where label was clicked on unselected edge in which
+ // case the label will be moved regardless of the handle that is returned
+ if (!start.selected && start.handle == mxEvent.LABEL_HANDLE)
+ {
+ handle = start.handle;
+ }
+
+ if (!entity || handle == 0 || handle == handler.bends.length - 1 || handle == mxEvent.LABEL_HANDLE)
+ {
+ // Source or target handle or connected for direct handle access or orthogonal line
+ // with just two points where the central handle is moved regardless of mouse position
+ if (handle == mxEvent.LABEL_HANDLE || handle == 0 || state.visibleSourceState != null ||
+ handle == handler.bends.length - 1 || state.visibleTargetState != null)
+ {
+ if (!entity && handle != mxEvent.LABEL_HANDLE)
+ {
+ var pts = state.absolutePoints;
+
+ // Default case where handles are at corner points handles
+ // drag of corner as drag of existing point
+ if (pts != null && ((edgeStyle == null && handle == null) ||
+ edgeStyle == mxEdgeStyle.SegmentConnector ||
+ edgeStyle == mxEdgeStyle.OrthConnector))
+ {
+ // Does not use handles if they were not initially visible
+ handle = start.handle;
+
+ if (handle == null)
+ {
+ var box = new mxRectangle(start.point.x, start.point.y);
+ box.grow(mxEdgeHandler.prototype.handleImage.width / 2);
+
+ if (mxUtils.contains(box, pts[0].x, pts[0].y))
+ {
+ // Moves source terminal handle
+ handle = 0;
+ }
+ else if (mxUtils.contains(box, pts[pts.length - 1].x, pts[pts.length - 1].y))
+ {
+ // Moves target terminal handle
+ handle = handler.bends.length - 1;
+ }
+ else
+ {
+ // Checks if edge has no bends
+ var nobends = edgeStyle != null && (pts.length == 2 || (pts.length == 3 &&
+ ((Math.round(pts[0].x - pts[1].x) == 0 && Math.round(pts[1].x - pts[2].x) == 0) ||
+ (Math.round(pts[0].y - pts[1].y) == 0 && Math.round(pts[1].y - pts[2].y) == 0))));
+
+ if (nobends)
+ {
+ // Moves central handle for straight orthogonal edges
+ handle = 2;
+ }
+ else
+ {
+ // Finds and moves vertical or horizontal segment
+ handle = mxUtils.findNearestSegment(state, start.point.x, start.point.y);
+
+ // Converts segment to virtual handle index
+ if (edgeStyle == null)
+ {
+ handle = mxEvent.VIRTUAL_HANDLE - handle;
+ }
+ // Maps segment to handle
+ else
+ {
+ handle += 1;
+ }
+ }
+ }
+ }
+ }
+
+ // Creates a new waypoint and starts moving it
+ if (handle == null)
+ {
+ handle = mxEvent.VIRTUAL_HANDLE;
+ }
+ }
+
+ handler.start(me.getGraphX(), me.getGraphX(), handle);
+ me.consume();
+
+ // Removes preview rectangle in graph handler
+ this.graphHandler.reset();
+ }
+ }
+ else if (entity && (state.visibleSourceState != null || state.visibleTargetState != null))
+ {
+ // Disables moves on entity to make it consistent
+ this.graphHandler.reset();
+ me.consume();
+ }
+ }
+
+ if (handler != null)
+ {
+ // Lazy selection for edges inside groups
+ if (this.selectionCellsHandler.isHandlerActive(handler))
+ {
+ if (!this.isCellSelected(state.cell))
+ {
+ this.selectionCellsHandler.handlers.put(state.cell, handler);
+ this.selectCellForEvent(state.cell, me.getEvent());
+ }
+ }
+ else if (!this.isCellSelected(state.cell))
+ {
+ // Destroy temporary handler
+ handler.destroy();
+ }
+ }
+
+ // Reset start state
+ start.selected = false;
+ start.handle = null;
+ start.state = null;
+ start.event = null;
+ start.point = null;
+ }
+ }
+ else
+ {
+ // Updates cursor for unselected edges under the mouse
+ var state = me.getState();
+
+ if (state != null && this.isCellEditable(state.cell))
+ {
+ var cursor = null;
+
+ // Checks if state was removed in call to stopEditing above
+ if (this.model.isEdge(state.cell) &&
+ !this.isCellSelected(state.cell) &&
+ !mxEvent.isAltDown(me.getEvent()) &&
+ !mxEvent.isControlDown(me.getEvent()) &&
+ !mxEvent.isShiftDown(me.getEvent()))
+ {
+ var box = new mxRectangle(me.getGraphX(), me.getGraphY());
+ box.grow(mxEdgeHandler.prototype.handleImage.width / 2);
+ var pts = state.absolutePoints;
+
+ if (pts != null)
+ {
+ if (state.text != null && state.text.boundingBox != null &&
+ mxUtils.contains(state.text.boundingBox, me.getGraphX(), me.getGraphY()))
+ {
+ cursor = 'move';
+ }
+ else if (mxUtils.contains(box, pts[0].x, pts[0].y) ||
+ mxUtils.contains(box, pts[pts.length - 1].x, pts[pts.length - 1].y))
+ {
+ cursor = 'pointer';
+ }
+ else if (state.visibleSourceState != null || state.visibleTargetState != null)
+ {
+ // Moving is not allowed for entity relation but still indicate hover state
+ var tmp = this.view.getEdgeStyle(state);
+ cursor = 'crosshair';
+
+ if (tmp != mxEdgeStyle.EntityRelation && this.isOrthogonal(state))
+ {
+ var idx = mxUtils.findNearestSegment(state, me.getGraphX(), me.getGraphY());
+
+ if (idx < pts.length - 1 && idx >= 0)
+ {
+ cursor = (Math.round(pts[idx].x - pts[idx + 1].x) == 0) ?
+ 'col-resize' : 'row-resize';
+ }
+ }
+ }
+ }
+ }
+ else if (!mxEvent.isControlDown(me.getEvent()))
+ {
+ var tol = mxShape.prototype.svgStrokeTolerance / 2;
+ var box = new mxRectangle(me.getGraphX(), me.getGraphY());
+ box.grow(tol);
+
+ if (this.isTableCell(state.cell) && this.isCellMovable(state.cell))
+ {
+ var row = this.model.getParent(state.cell);
+ var table = this.model.getParent(row);
+
+ if (!this.isCellSelected(table))
+ {
+ if ((mxUtils.intersects(box, new mxRectangle(state.x, state.y - 2, state.width, 4)) &&
+ this.model.getChildAt(table, 0) != row) || mxUtils.intersects(box,
+ new mxRectangle(state.x, state.y + state.height - 2, state.width, 4)))
+ {
+ cursor ='row-resize';
+ }
+ else if ((mxUtils.intersects(box, new mxRectangle(state.x - 2, state.y, 4, state.height)) &&
+ this.model.getChildAt(row, 0) != state.cell) || mxUtils.intersects(box,
+ new mxRectangle(state.x + state.width - 2, state.y, 4, state.height)))
+ {
+ cursor ='col-resize';
+ }
+ }
+ }
+
+ // Hover for swimlane start sizes inside tables
+ var current = state;
+
+ while (cursor == null && current != null && (this.isTableCell(current.cell) ||
+ this.isTableRow(current.cell) || this.isTable(current.cell)))
+ {
+ if (this.isSwimlane(current.cell) && this.isCellMovable(current.cell))
+ {
+ var offset = this.getActualStartSize(current.cell);
+ var s = this.view.scale;
+
+ if ((offset.x > 0 || offset.width > 0) && mxUtils.intersects(box, new mxRectangle(
+ current.x + (offset.x - offset.width - 1) * s + ((offset.x == 0) ? current.width * s : 0),
+ current.y, 1, current.height)))
+ {
+ cursor ='col-resize';
+ }
+ else if ((offset.y > 0 || offset.height > 0) && mxUtils.intersects(box, new mxRectangle(
+ current.x, current.y + (offset.y - offset.height - 1) * s + ((offset.y == 0) ? current.height : 0),
+ current.width, 1)))
+ {
+ cursor ='row-resize';
+ }
+ }
+
+ current = this.view.getState(this.model.getParent(current.cell));
+ }
+ }
+
+ if (cursor != null)
+ {
+ state.setCursor(cursor);
+ }
+ }
+ }
+ }
+ }),
+ mouseUp: mxUtils.bind(this, function(sender, me)
+ {
+ start.state = null;
+ start.event = null;
+ start.point = null;
+ start.handle = null;
+ })
+ });
+ }
+
+ this.cellRenderer.minSvgStrokeWidth = 0.1;
+
+ // HTML entities are displayed as plain text in wrapped plain text labels
+ this.cellRenderer.getLabelValue = function(state)
+ {
+ var result = mxCellRenderer.prototype.getLabelValue.apply(this, arguments);
+
+ if (state.view.graph.isHtmlLabel(state.cell))
+ {
+ if (state.style['html'] != 1)
+ {
+ result = mxUtils.htmlEntities(result, false);
+ }
+ else
+ {
+ // Skips sanitizeHtml for unchanged labels
+ if (state.lastLabelValue != result)
+ {
+ state.lastLabelValue = result;
+ state.lastSanitizedLabelValue = Graph.sanitizeHtml(result);
+ }
+
+ result = state.lastSanitizedLabelValue;
+ }
+ }
+
+ return result;
+ };
+
+ // All code below not available and not needed in embed mode
+ if (typeof mxVertexHandler !== 'undefined')
+ {
+ this.setConnectable(true);
+ this.setDropEnabled(true);
+ this.setPanning(true);
+ this.setTooltips(true);
+ this.setAllowLoops(true);
+ this.allowAutoPanning = true;
+ this.resetEdgesOnConnect = false;
+ this.constrainChildren = false;
+ this.constrainRelativeChildren = true;
+
+ // Do not scroll after moving cells
+ this.graphHandler.scrollOnMove = false;
+ this.graphHandler.scaleGrid = true;
+
+ // Disables cloning of connection sources by default
+ this.connectionHandler.setCreateTarget(false);
+ this.connectionHandler.insertBeforeSource = true;
+
+ // Disables built-in connection starts
+ this.connectionHandler.isValidSource = function(cell, me)
+ {
+ return false;
+ };
+
+ // Sets the style to be used when an elbow edge is double clicked
+ this.alternateEdgeStyle = 'vertical';
+
+ if (stylesheet == null)
+ {
+ this.loadStylesheet();
+ }
+
+ // Adds page centers to the guides for moving cells
+ var graphHandlerGetGuideStates = this.graphHandler.getGuideStates;
+ this.graphHandler.getGuideStates = function()
+ {
+ var result = graphHandlerGetGuideStates.apply(this, arguments);
+
+ // Create virtual cell state for page centers
+ if (this.graph.pageVisible)
+ {
+ var guides = [];
+
+ var pf = this.graph.pageFormat;
+ var ps = this.graph.pageScale;
+ var pw = pf.width * ps;
+ var ph = pf.height * ps;
+ var t = this.graph.view.translate;
+ var s = this.graph.view.scale;
+
+ var layout = this.graph.getPageLayout();
+
+ for (var i = 0; i < layout.width; i++)
+ {
+ guides.push(new mxRectangle(((layout.x + i) * pw + t.x) * s,
+ (layout.y * ph + t.y) * s, pw * s, ph * s));
+ }
+
+ for (var j = 1; j < layout.height; j++)
+ {
+ guides.push(new mxRectangle((layout.x * pw + t.x) * s,
+ ((layout.y + j) * ph + t.y) * s, pw * s, ph * s));
+ }
+
+ // Page center guides have precedence over normal guides
+ result = guides.concat(result);
+ }
+
+ return result;
+ };
+
+ // Overrides zIndex for dragElement
+ mxDragSource.prototype.dragElementZIndex = mxPopupMenu.prototype.zIndex;
+
+ // Overrides color for virtual guides for page centers
+ mxGuide.prototype.getGuideColor = function(state, horizontal)
+ {
+ return (state.cell == null) ? '#ffa500' /* orange */ : mxConstants.GUIDE_COLOR;
+ };
+
+ // Changes color of move preview for black backgrounds
+ this.graphHandler.createPreviewShape = function(bounds)
+ {
+ this.previewColor = (this.graph.background == '#000000') ? '#ffffff' : mxGraphHandler.prototype.previewColor;
+
+ return mxGraphHandler.prototype.createPreviewShape.apply(this, arguments);
+ };
+
+ // Handles parts of cells by checking if part=1 is in the style and returning the parent
+ // if the parent is not already in the list of cells. container style is used to disable
+ // step into swimlanes and dropTarget style is used to disable acting as a drop target.
+ // LATER: Handle recursive parts
+ var graphHandlerGetCells = this.graphHandler.getCells;
+
+ this.graphHandler.getCells = function(initialCell)
+ {
+ var cells = graphHandlerGetCells.apply(this, arguments);
+ var lookup = new mxDictionary();
+ var newCells = [];
+
+ for (var i = 0; i < cells.length; i++)
+ {
+ // Propagates to composite parents or moves selected table rows
+ var cell = (this.graph.isTableCell(initialCell) &&
+ this.graph.isTableCell(cells[i]) &&
+ this.graph.isCellSelected(cells[i])) ?
+ this.graph.model.getParent(cells[i]) :
+ ((this.graph.isTableRow(initialCell) &&
+ this.graph.isTableRow(cells[i]) &&
+ this.graph.isCellSelected(cells[i])) ?
+ cells[i] : this.graph.getCompositeParent(cells[i]));
+
+ if (cell != null && !lookup.get(cell))
+ {
+ lookup.put(cell, true);
+ newCells.push(cell);
+ }
+ }
+
+ return newCells;
+ };
+
+ // Handles parts and selected rows in tables of cells for drag and drop
+ var graphHandlerStart = this.graphHandler.start;
+
+ this.graphHandler.start = function(cell, x, y, cells)
+ {
+ // Propagates to selected table row to start move
+ var ignoreParent = false;
+
+ if (this.graph.isTableCell(cell))
+ {
+ if (!this.graph.isCellSelected(cell))
+ {
+ cell = this.graph.model.getParent(cell);
+ }
+ else
+ {
+ ignoreParent = true;
+ }
+ }
+
+ if (!ignoreParent && (!this.graph.isTableRow(cell) || !this.graph.isCellSelected(cell)))
+ {
+ cell = this.graph.getCompositeParent(cell);
+ }
+
+ graphHandlerStart.apply(this, arguments);
+ };
+
+ // Handles parts of cells when cloning the source for new connections
+ this.connectionHandler.createTargetVertex = function(evt, source)
+ {
+ source = this.graph.getCompositeParent(source);
+
+ return mxConnectionHandler.prototype.createTargetVertex.apply(this, arguments);
+ };
+
+ // Applies newEdgeStyle
+ this.connectionHandler.insertEdge = function(parent, id, value, source, target, style)
+ {
+ var edge = mxConnectionHandler.prototype.insertEdge.apply(this, arguments);
+
+ if (source != null)
+ {
+ this.graph.applyNewEdgeStyle(source, [edge]);
+ }
+
+ return edge
+ };
+
+ // Creates rubberband selection and associates with graph instance
+ var rubberband = new mxRubberband(this);
+
+ this.getRubberband = function()
+ {
+ return rubberband;
+ };
+
+ // Timer-based activation of outline connect in connection handler
+ var startTime = new Date().getTime();
+ var timeOnTarget = 0;
+
+ var connectionHandlerMouseMove = this.connectionHandler.mouseMove;
+
+ this.connectionHandler.mouseMove = function()
+ {
+ var prev = this.currentState;
+ connectionHandlerMouseMove.apply(this, arguments);
+
+ if (prev != this.currentState)
+ {
+ startTime = new Date().getTime();
+ timeOnTarget = 0;
+ }
+ else
+ {
+ timeOnTarget = new Date().getTime() - startTime;
+ }
+ };
+
+ // Activates outline connect after 1500ms with touch event or if alt is pressed inside the shape
+ // outlineConnect=0 is a custom style that means do not connect to strokes inside the shape,
+ // or in other words, connect to the shape's perimeter if the highlight is under the mouse
+ // (the name is because the highlight, including all strokes, is called outline in the code)
+ var connectionHandleIsOutlineConnectEvent = this.connectionHandler.isOutlineConnectEvent;
+
+ this.connectionHandler.isOutlineConnectEvent = function(me)
+ {
+ if (mxEvent.isShiftDown(me.getEvent()) && mxEvent.isAltDown(me.getEvent()))
+ {
+ return false;
+ }
+ else
+ {
+ return (this.currentState != null && me.getState() == this.currentState && timeOnTarget > 2000) ||
+ ((this.currentState == null || mxUtils.getValue(this.currentState.style, 'outlineConnect', '1') != '0') &&
+ connectionHandleIsOutlineConnectEvent.apply(this, arguments));
+ }
+ };
+
+ // Adds shift+click to toggle selection state
+ var isToggleEvent = this.isToggleEvent;
+ this.isToggleEvent = function(evt)
+ {
+ return isToggleEvent.apply(this, arguments) || (!mxClient.IS_CHROMEOS && mxEvent.isShiftDown(evt));
+ };
+
+ // Workaround for Firefox where first mouse down is received
+ // after tap and hold if scrollbars are visible, which means
+ // start rubberband immediately if no cell is under mouse.
+ var isForceRubberBandEvent = rubberband.isForceRubberbandEvent;
+ rubberband.isForceRubberbandEvent = function(me)
+ {
+ return isForceRubberBandEvent.apply(this, arguments) ||
+ (mxClient.IS_CHROMEOS && mxEvent.isShiftDown(me.getEvent())) ||
+ (mxUtils.hasScrollbars(this.graph.container) && mxClient.IS_FF &&
+ mxClient.IS_WIN && me.getState() == null && mxEvent.isTouchEvent(me.getEvent()));
+ };
+
+ // Shows hand cursor while panning
+ var prevCursor = null;
+
+ this.panningHandler.addListener(mxEvent.PAN_START, mxUtils.bind(this, function()
+ {
+ if (this.isEnabled())
+ {
+ prevCursor = this.container.style.cursor;
+ this.container.style.cursor = 'move';
+ }
+ }));
+
+ this.panningHandler.addListener(mxEvent.PAN_END, mxUtils.bind(this, function()
+ {
+ if (this.isEnabled())
+ {
+ this.container.style.cursor = prevCursor;
+ }
+ }));
+
+ this.popupMenuHandler.autoExpand = true;
+
+ this.popupMenuHandler.isSelectOnPopup = function(me)
+ {
+ return mxEvent.isMouseEvent(me.getEvent());
+ };
+
+ // Handles links in read-only graphs
+ // and cells in locked layers
+ var click = this.click;
+ this.click = function(me)
+ {
+ var locked = me.state == null && me.sourceState != null &&
+ this.isCellLocked(this.getLayerForCell(
+ me.sourceState.cell));
+
+ if ((!this.isEnabled() || locked) && !me.isConsumed())
+ {
+ var cell = (locked) ? me.sourceState.cell : me.getCell();
+
+ if (cell != null)
+ {
+ var link = this.getClickableLinkForCell(cell);
+
+ if (link != null)
+ {
+ if (this.isCustomLink(link))
+ {
+ this.customLinkClicked(link);
+ }
+ else
+ {
+ this.openLink(link);
+ }
+ }
+ }
+ }
+ else
+ {
+ return click.apply(this, arguments);
+ }
+ };
+
+ // Redirects tooltips for locked cells
+ this.tooltipHandler.getStateForEvent = function(me)
+ {
+ return me.sourceState;
+ };
+
+ // Opens links in tooltips in new windows
+ var tooltipHandlerShow = this.tooltipHandler.show;
+ this.tooltipHandler.show = function()
+ {
+ tooltipHandlerShow.apply(this, arguments);
+
+ if (this.div != null)
+ {
+ var links = this.div.getElementsByTagName('a');
+
+ for (var i = 0; i < links.length; i++)
+ {
+ if (links[i].getAttribute('href') != null &&
+ links[i].getAttribute('target') == null)
+ {
+ links[i].setAttribute('target', '_blank');
+ }
+ }
+ }
+ };
+
+ // Redirects tooltips for locked cells
+ this.tooltipHandler.getStateForEvent = function(me)
+ {
+ return me.sourceState;
+ };
+
+ // Redirects cursor for locked cells
+ var getCursorForMouseEvent = this.getCursorForMouseEvent;
+ this.getCursorForMouseEvent = function(me)
+ {
+ var locked = me.state == null && me.sourceState != null && this.isCellLocked(me.sourceState.cell);
+
+ return this.getCursorForCell((locked) ? me.sourceState.cell : me.getCell());
+ };
+
+ // Shows pointer cursor for clickable cells with links
+ // ie. if the graph is disabled and cells cannot be selected
+ var getCursorForCell = this.getCursorForCell;
+ this.getCursorForCell = function(cell)
+ {
+ if (!this.isEnabled() || this.isCellLocked(cell))
+ {
+ var link = this.getClickableLinkForCell(cell);
+
+ if (link != null)
+ {
+ return 'pointer';
+ }
+ else if (this.isCellLocked(cell))
+ {
+ return 'default';
+ }
+ }
+
+ return getCursorForCell.apply(this, arguments);
+ };
+
+ // Changes rubberband selection ignore locked cells
+ this.selectRegion = function(rect, evt)
+ {
+ var isect = (mxEvent.isAltDown(evt)) ? rect : null;
+ var cells = this.getCells(rect.x, rect.y,
+ rect.width, rect.height, null, null,
+ isect, null, true);
+
+ if (this.isToggleEvent(evt))
+ {
+ for (var i = 0; i < cells.length; i++)
+ {
+ this.selectCellForEvent(cells[i], evt);
+ }
+ }
+ else
+ {
+ this.selectCellsForEvent(cells, evt);
+ }
+
+ return cells;
+ };
+
+ // Never removes cells from parents that are being moved
+ var graphHandlerShouldRemoveCellsFromParent = this.graphHandler.shouldRemoveCellsFromParent;
+ this.graphHandler.shouldRemoveCellsFromParent = function(parent, cells, evt)
+ {
+ if (this.graph.isCellSelected(parent))
+ {
+ return false;
+ }
+
+ return graphHandlerShouldRemoveCellsFromParent.apply(this, arguments);
+ };
+
+ // Enables rubberband selection on cells in locked layers
+ var graphUpdateMouseEvent = this.updateMouseEvent;
+ this.updateMouseEvent = function(me)
+ {
+ me = graphUpdateMouseEvent.apply(this, arguments);
+
+ if (me.state != null && this.isCellLocked(this.getLayerForCell(me.getCell())))
+ {
+ me.state = null;
+ }
+
+ return me;
+ };
+
+ // Cells in locked layers are not selectable
+ var graphIsCellSelectable = this.isCellSelectable;
+ this.isCellSelectable = function(cell)
+ {
+ return graphIsCellSelectable.apply(this, arguments) &&
+ !this.isCellLocked(this.getLayerForCell(cell));
+ };
+
+ // Returns true if the given cell is locked
+ this.isCellLocked = function(cell)
+ {
+ while (cell != null)
+ {
+ if (mxUtils.getValue(this.getCurrentCellStyle(cell), 'locked', '0') == '1')
+ {
+ return true;
+ }
+
+ cell = this.model.getParent(cell);
+ }
+
+ return false;
+ };
+
+ var tapAndHoldSelection = null;
+
+ // Uses this event to process mouseDown to check the selection state before it is changed
+ this.addListener(mxEvent.FIRE_MOUSE_EVENT, mxUtils.bind(this, function(sender, evt)
+ {
+ if (evt.getProperty('eventName') == 'mouseDown')
+ {
+ var me = evt.getProperty('event');
+ var state = me.getState();
+
+ if (state != null && !this.isSelectionEmpty() && !this.isCellSelected(state.cell))
+ {
+ tapAndHoldSelection = this.getSelectionCells();
+ }
+ else
+ {
+ tapAndHoldSelection = null;
+ }
+ }
+ }));
+
+ // Tap and hold on background starts rubberband for multiple selected
+ // cells the cell associated with the event is deselected
+ this.addListener(mxEvent.TAP_AND_HOLD, mxUtils.bind(this, function(sender, evt)
+ {
+ if (!mxEvent.isMultiTouchEvent(evt))
+ {
+ var me = evt.getProperty('event');
+ var cell = evt.getProperty('cell');
+
+ if (cell == null)
+ {
+ var pt = mxUtils.convertPoint(this.container,
+ mxEvent.getClientX(me), mxEvent.getClientY(me));
+ rubberband.start(pt.x, pt.y);
+ }
+ else if (tapAndHoldSelection != null)
+ {
+ this.addSelectionCells(tapAndHoldSelection);
+ }
+ else if (this.getSelectionCount() > 1 && this.isCellSelected(cell))
+ {
+ this.removeSelectionCell(cell);
+ }
+
+ // Blocks further processing of the event
+ tapAndHoldSelection = null;
+ evt.consume();
+ }
+ }));
+
+ // On connect the target is selected and we clone the cell of the preview edge for insert
+ this.connectionHandler.selectCells = function(edge, target)
+ {
+ this.graph.setSelectionCell(target || edge);
+ };
+
+ // Shows connection points only if cell not selected and parent table not handled
+ this.connectionHandler.constraintHandler.isStateIgnored = function(state, source)
+ {
+ var graph = state.view.graph;
+
+ return source && (graph.isCellSelected(state.cell) || (graph.isTableRow(state.cell) &&
+ graph.selectionCellsHandler.isHandled(graph.model.getParent(state.cell))));
+ };
+
+ // Updates constraint handler if the selection changes
+ this.selectionModel.addListener(mxEvent.CHANGE, mxUtils.bind(this, function()
+ {
+ var ch = this.connectionHandler.constraintHandler;
+
+ if (ch.currentFocus != null && ch.isStateIgnored(ch.currentFocus, true))
+ {
+ ch.currentFocus = null;
+ ch.constraints = null;
+ ch.destroyIcons();
+ }
+
+ ch.destroyFocusHighlight();
+ }));
+
+ // Initializes touch interface
+ if (Graph.touchStyle)
+ {
+ this.initTouch();
+ }
+ }
+
+ //Create a unique offset object for each graph instance.
+ this.currentTranslate = new mxPoint(0, 0);
+};
+
+/**
+ * Specifies if the touch UI should be used (cannot detect touch in FF so always on for Windows/Linux)
+ */
+Graph.touchStyle = mxClient.IS_TOUCH || (mxClient.IS_FF && mxClient.IS_WIN) || navigator.maxTouchPoints > 0 ||
+ navigator.msMaxTouchPoints > 0 || window.urlParams == null || urlParams['touch'] == '1';
+
+/**
+ * Shortcut for capability check.
+ */
+Graph.fileSupport = window.File != null && window.FileReader != null && window.FileList != null &&
+ (window.urlParams == null || urlParams['filesupport'] != '0');
+
+/**
+ * Shortcut for capability check.
+ */
+Graph.translateDiagram = urlParams['translate-diagram'] == '1';
+
+/**
+ * Shortcut for capability check.
+ */
+Graph.diagramLanguage = (urlParams['diagram-language'] != null) ? urlParams['diagram-language'] : mxClient.language;
+
+/**
+ * Default size for line jumps.
+ */
+Graph.lineJumpsEnabled = true;
+
+/**
+ * Default size for line jumps.
+ */
+Graph.defaultJumpSize = 6;
+
+/**
+ * Specifies if the mouse wheel is used for zoom without any modifiers.
+ */
+Graph.zoomWheel = false;
+
+/**
+ * Minimum width for table columns.
+ */
+Graph.minTableColumnWidth = 20;
+
+/**
+ * Minimum height for table rows.
+ */
+Graph.minTableRowHeight = 20;
+
+/**
+ * Text for foreign object warning.
+ */
+Graph.foreignObjectWarningText = 'Text is not SVG - cannot display';
+
+/**
+ * Link for foreign object warning.
+ */
+Graph.foreignObjectWarningLink = 'https://www.drawio.com/doc/faq/svg-export-text-problems';
+
+/**
+ *
+ */
+Graph.xmlDeclaration = '';
+
+/**
+ *
+ */
+Graph.svgDoctype = '';
+
+/**
+ *
+ */
+Graph.svgFileComment = ''
+
+/**
+ * Minimum height for table rows.
+ */
+Graph.pasteStyles = ['rounded', 'shadow', 'dashed', 'dashPattern', 'fontFamily', 'fontSource', 'fontSize', 'fontColor', 'fontStyle',
+ 'align', 'verticalAlign', 'strokeColor', 'strokeWidth', 'fillColor', 'gradientColor', 'swimlaneFillColor',
+ 'textOpacity', 'gradientDirection', 'glass', 'labelBackgroundColor', 'labelBorderColor', 'opacity',
+ 'spacing', 'spacingTop', 'spacingLeft', 'spacingBottom', 'spacingRight', 'endFill', 'endArrow',
+ 'endSize', 'targetPerimeterSpacing', 'startFill', 'startArrow', 'startSize', 'sourcePerimeterSpacing',
+ 'arcSize', 'comic', 'sketch', 'fillWeight', 'hachureGap', 'hachureAngle', 'jiggle', 'disableMultiStroke',
+ 'disableMultiStrokeFill', 'fillStyle', 'curveFitting', 'simplification', 'comicStyle'];
+
+/**
+ * Whitelist for known layout names.
+ */
+Graph.layoutNames = ['mxHierarchicalLayout', 'mxCircleLayout', 'mxCompactTreeLayout',
+ 'mxEdgeLabelLayout', 'mxFastOrganicLayout', 'mxParallelEdgeLayout',
+ 'mxPartitionLayout', 'mxRadialTreeLayout', 'mxStackLayout'];
+
+/**
+ * Creates a temporary graph instance for rendering off-screen content.
+ */
+Graph.createOffscreenGraph = function(stylesheet)
+{
+ var graph = new Graph(document.createElement('div'));
+ graph.stylesheet.styles = mxUtils.clone(stylesheet.styles);
+ graph.resetViewOnRootChange = false;
+ graph.setConnectable(false);
+ graph.gridEnabled = false;
+ graph.autoScroll = false;
+ graph.setTooltips(false);
+ graph.setEnabled(false);
+
+ // Container must be in the DOM for correct HTML rendering
+ graph.container.style.visibility = 'hidden';
+ graph.container.style.position = 'absolute';
+ graph.container.style.overflow = 'hidden';
+ graph.container.style.height = '1px';
+ graph.container.style.width = '1px';
+
+ return graph;
+};
+
+/**
+ * Helper function for creating SVG data URI.
+ */
+Graph.createSvgImage = function(w, h, data, coordWidth, coordHeight)
+{
+ var tmp = unescape(encodeURIComponent(Graph.svgDoctype +
+ ''));
+
+ return new mxImage('data:image/svg+xml;base64,' + ((window.btoa) ? btoa(tmp) : Base64.encode(tmp, true)), w, h)
+};
+
+/**
+ * Helper function for creating an SVG node.
+ */
+Graph.createSvgNode = function(x, y, w, h, background)
+{
+ var svgDoc = mxUtils.createXmlDocument();
+ var root = (svgDoc.createElementNS != null) ?
+ svgDoc.createElementNS(mxConstants.NS_SVG, 'svg') :
+ svgDoc.createElement('svg');
+
+ if (background != null)
+ {
+ if (root.style != null)
+ {
+ root.style.backgroundColor = background;
+ }
+ else
+ {
+ root.setAttribute('style', 'background-color:' + background);
+ }
+ }
+
+ if (svgDoc.createElementNS == null)
+ {
+ root.setAttribute('xmlns', mxConstants.NS_SVG);
+ root.setAttribute('xmlns:xlink', mxConstants.NS_XLINK);
+ }
+ else
+ {
+ // KNOWN: Ignored in IE9-11, adds namespace for each image element instead. No workaround.
+ root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', mxConstants.NS_XLINK);
+ }
+
+ root.setAttribute('version', '1.1');
+ root.setAttribute('width', w + 'px');
+ root.setAttribute('height', h + 'px');
+ root.setAttribute('viewBox', x + ' ' + y + ' ' + w + ' ' + h);
+ svgDoc.appendChild(root);
+
+ return root;
+};
+
+/**
+ * Helper function for creating an SVG node.
+ */
+Graph.htmlToPng = function(html, w, h, fn)
+{
+ var canvas = document.createElement('canvas');
+ canvas.width = w;
+ canvas.height = h;
+
+ var img = document.createElement('img');
+ img.onload = mxUtils.bind(this, function()
+ {
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0)
+
+ fn(canvas.toDataURL());
+ });
+
+ img.src = 'data:image/svg+xml,' + encodeURIComponent('');
+};
+
+/**
+ * Removes all illegal control characters with ASCII code <32 except TAB, LF
+ * and CR.
+ */
+Graph.zapGremlins = function(text)
+{
+ var lastIndex = 0;
+ var checked = [];
+
+ for (var i = 0; i < text.length; i++)
+ {
+ var code = text.charCodeAt(i);
+
+ // Removes all control chars except TAB, LF and CR
+ if (!((code >= 32 || code == 9 || code == 10 || code == 13) &&
+ code != 0xFFFF && code != 0xFFFE))
+ {
+ checked.push(text.substring(lastIndex, i));
+ lastIndex = i + 1;
+ }
+ }
+
+ if (lastIndex > 0 && lastIndex < text.length)
+ {
+ checked.push(text.substring(lastIndex));
+ }
+
+ return (checked.length == 0) ? text : checked.join('');
+};
+
+/**
+ * Turns the given string into an array.
+ */
+Graph.stringToBytes = function(str)
+{
+ var arr = new Array(str.length);
+
+ for (var i = 0; i < str.length; i++)
+ {
+ arr[i] = str.charCodeAt(i);
+ }
+
+ return arr;
+};
+
+/**
+ * Turns the given array into a string.
+ */
+Graph.bytesToString = function(arr)
+{
+ var result = new Array(arr.length);
+
+ for (var i = 0; i < arr.length; i++)
+ {
+ result[i] = String.fromCharCode(arr[i]);
+ }
+
+ return result.join('');
+};
+
+/**
+ * Turns the given array into a string.
+ */
+Graph.base64EncodeUnicode = function(str)
+{
+ return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
+ return String.fromCharCode(parseInt(p1, 16))
+ }));
+};
+
+/**
+ * Turns the given array into a string.
+ */
+Graph.base64DecodeUnicode = function(str)
+{
+ return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
+ }).join(''));
+};
+
+/**
+ * Returns a base64 encoded version of the compressed outer XML of the given node.
+ */
+Graph.compressNode = function(node, checked)
+{
+ var xml = mxUtils.getXml(node);
+
+ return Graph.compress((checked) ? xml : Graph.zapGremlins(xml));
+};
+
+/**
+ * Returns a string for the given array buffer.
+ */
+Graph.arrayBufferToString = function(buffer)
+{
+ var binary = '';
+ var bytes = new Uint8Array(buffer);
+ var len = bytes.byteLength;
+
+ for (var i = 0; i < len; i++)
+ {
+ binary += String.fromCharCode(bytes[i]);
+ }
+
+ return binary;
+};
+
+/**
+ * Returns an array buffer for the given string.
+ */
+Graph.stringToArrayBuffer = function(data)
+{
+ return Uint8Array.from(data, function (c)
+ {
+ return c.charCodeAt(0);
+ });
+};
+
+/**
+ * Returns index of a string in an array buffer (UInt8Array)
+ */
+Graph.arrayBufferIndexOfString = function (uint8Array, str, start)
+{
+ var c0 = str.charCodeAt(0), j = 1, p = -1;
+
+ //Index of first char
+ for (var i = start || 0; i < uint8Array.byteLength; i++)
+ {
+ if (uint8Array[i] == c0)
+ {
+ p = i;
+ break;
+ }
+ }
+
+ for (var i = p + 1; p > -1 && i < uint8Array.byteLength && i < p + str.length - 1; i++)
+ {
+ if (uint8Array[i] != str.charCodeAt(j))
+ {
+ return Graph.arrayBufferIndexOfString(uint8Array, str, p + 1);
+ }
+
+ j++;
+ }
+
+ return j == str.length - 1? p : -1;
+};
+
+/**
+ * Returns a base64 encoded version of the compressed string.
+ */
+Graph.compress = function(data, deflate)
+{
+ if (data == null || data.length == 0 || typeof(pako) === 'undefined')
+ {
+ return data;
+ }
+ else
+ {
+ var tmp = (deflate) ? pako.deflate(encodeURIComponent(data)) :
+ pako.deflateRaw(encodeURIComponent(data));
+
+ return btoa(Graph.arrayBufferToString(new Uint8Array(tmp)));
+ }
+};
+
+/**
+ * Returns a decompressed version of the base64 encoded string.
+ */
+Graph.decompress = function(data, inflate, checked)
+{
+ if (data == null || data.length == 0 || typeof(pako) === 'undefined')
+ {
+ return data;
+ }
+ else
+ {
+ var tmp = Graph.stringToArrayBuffer(atob(data));
+ var inflated = decodeURIComponent((inflate) ?
+ pako.inflate(tmp, {to: 'string'}) :
+ pako.inflateRaw(tmp, {to: 'string'}));
+
+ return (checked) ? inflated : Graph.zapGremlins(inflated);
+ }
+};
+
+/**
+ * Fades the given nodes in or out.
+ */
+Graph.fadeNodes = function(nodes, start, end, done, delay)
+{
+ delay = (delay != null) ? delay : 1000;
+ Graph.setTransitionForNodes(nodes, null);
+ Graph.setOpacityForNodes(nodes, start);
+
+ window.setTimeout(function()
+ {
+ Graph.setTransitionForNodes(nodes,
+ 'all ' + delay + 'ms ease-in-out');
+ Graph.setOpacityForNodes(nodes, end);
+
+ window.setTimeout(function()
+ {
+ Graph.setTransitionForNodes(nodes, null);
+
+ if (done != null)
+ {
+ done();
+ }
+ }, delay);
+ }, 0);
+};
+
+/**
+ * Removes the elements from the map where the given function returns true.
+ */
+Graph.removeKeys = function(map, ignoreFn)
+{
+ for (var key in map)
+ {
+ if (ignoreFn(key))
+ {
+ delete map[key];
+ }
+ }
+};
+
+/**
+ * Sets the transition for the given nodes.
+ */
+Graph.setTransitionForNodes = function(nodes, transition)
+{
+ for (var i = 0; i < nodes.length; i++)
+ {
+ mxUtils.setPrefixedStyle(nodes[i].style, 'transition', transition);
+ }
+};
+
+/**
+ * Sets the opacity for the given nodes.
+ */
+Graph.setOpacityForNodes = function(nodes, opacity)
+{
+ for (var i = 0; i < nodes.length; i++)
+ {
+ nodes[i].style.opacity = opacity;
+ }
+};
+
+/**
+ * Removes formatting from pasted HTML.
+ */
+Graph.removePasteFormatting = function(elt, ignoreTabs)
+{
+ while (elt != null)
+ {
+ if (elt.firstChild != null)
+ {
+ Graph.removePasteFormatting(elt.firstChild, true);
+ }
+
+ var next = elt.nextSibling;
+
+ if (elt.nodeType == mxConstants.NODETYPE_ELEMENT && elt.style != null)
+ {
+ elt.style.whiteSpace = '';
+
+ if (elt.style.color == '#000000')
+ {
+ elt.style.color = '';
+ }
+
+ // Replaces tabs from macOS TextEdit
+ if (elt.nodeName == 'SPAN' && elt.className == 'Apple-tab-span')
+ {
+ var temp = Graph.createTabNode(4);
+ elt.parentNode.replaceChild(temp, elt);
+ elt = temp;
+ }
+
+ // Replaces paragraphs from macOS TextEdit
+ if (elt.nodeName == 'P' && elt.className == 'p1')
+ {
+ while (elt.firstChild != null)
+ {
+ elt.parentNode.insertBefore(elt.firstChild, elt);
+ }
+
+ if (next != null && next.nodeName == 'P' &&
+ next.className == 'p1')
+ {
+ elt.parentNode.insertBefore(elt.ownerDocument.
+ createElement('br'), elt);
+ }
+
+ elt.parentNode.removeChild(elt);
+ }
+
+ // Replaces tabs
+ if (!ignoreTabs && elt.innerHTML != null)
+ {
+ var tabNode = Graph.createTabNode(4);
+ elt.innerHTML = elt.innerHTML.replace(/\t/g,
+ tabNode.outerHTML);
+ }
+ }
+
+ elt = next;
+ }
+};
+
+/**
+ * Removes formatting from pasted HTML.
+ */
+Graph.createTabNode = function(spaces)
+{
+ var str = '\t';
+
+ if (spaces != null)
+ {
+ str = '';
+
+ while (spaces > 0)
+ {
+ str += '\xa0';
+ spaces--;
+ }
+ }
+
+ // LATER: Fix normalized tab after editing plain text labels
+ var tabNode = document.createElement('span');
+ tabNode.style.whiteSpace = 'pre';
+ tabNode.appendChild(document.createTextNode(str));
+
+ return tabNode;
+};
+
+/**
+ * Sanitizes the given HTML markup, allowing target attributes and
+ * data: protocol links to pages and custom actions.
+ */
+Graph.sanitizeHtml = function(value, editing)
+{
+ return Graph.domPurify(value, false);
+};
+
+/**
+ * Returns the size of the page format scaled with the page size.
+ */
+ Graph.sanitizeLink = function(href)
+ {
+ if (href == null)
+ {
+ return null;
+ }
+ else
+ {
+ var a = document.createElement('a');
+ a.setAttribute('href', href);
+ Graph.sanitizeNode(a);
+
+ return a.getAttribute('href');
+ }
+ };
+
+/**
+ * Sanitizes the given DOM node in-place.
+ */
+Graph.sanitizeNode = function(value)
+{
+ return Graph.domPurify(value, true);
+};
+
+// Allows use tag in SVG with local references only
+DOMPurify.addHook('afterSanitizeAttributes', function(node)
+{
+ if (node.nodeName == 'use' && ((node.getAttribute('xlink:href') != null &&
+ !node.getAttribute('xlink:href').startsWith('#')) ||
+ (node.getAttribute('href') != null && !node.getAttribute('href').startsWith('#'))))
+ {
+ node.remove();
+ }
+});
+
+// Workaround for removed content with empty nodes
+DOMPurify.addHook('uponSanitizeAttribute', function (node, evt)
+{
+ if (node.nodeName == 'svg' && evt.attrName == 'content')
+ {
+ evt.forceKeepAttr = true;
+ }
+
+ return node;
+});
+
+/**
+ * Sanitizes the given value.
+ */
+Graph.domPurify = function(value, inPlace)
+{
+ window.DOM_PURIFY_CONFIG.IN_PLACE = inPlace;
+
+ return DOMPurify.sanitize(value, window.DOM_PURIFY_CONFIG);
+};
+
+/**
+ * Updates the viewbox, width and height in the given SVG data URI
+ * and returns the updated data URI with all script tags and event
+ * handlers removed.
+ */
+Graph.clipSvgDataUri = function(dataUri, ignorePreserveAspect)
+{
+ // LATER Add workaround for non-default NS declarations with empty URI not allowed in IE11
+ if (!mxClient.IS_IE && !mxClient.IS_IE11 && dataUri != null &&
+ dataUri.substring(0, 26) == 'data:image/svg+xml;base64,')
+ {
+ try
+ {
+ var div = document.createElement('div');
+ div.style.position = 'absolute';
+ div.style.visibility = 'hidden';
+
+ // Adds the text and inserts into DOM for updating of size
+ var data = decodeURIComponent(escape(atob(dataUri.substring(26))));
+ var idx = data.indexOf('