{"id":19112213,"url":"https://github.com/slimkit/plus-editor","last_synced_at":"2025-04-30T22:11:37.625Z","repository":{"id":57160912,"uuid":"145353148","full_name":"slimkit/plus-editor","owner":"slimkit","description":"The markdown editor for Plus","archived":false,"fork":false,"pushed_at":"2023-05-13T12:00:05.000Z","size":3253,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-30T22:11:26.926Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slimkit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-20T01:51:03.000Z","updated_at":"2023-05-05T03:46:22.000Z","dependencies_parsed_at":"2024-11-03T02:32:51.556Z","dependency_job_id":"3720a062-0687-421c-adc9-18e651c37810","html_url":"https://github.com/slimkit/plus-editor","commit_stats":{"total_commits":140,"total_committers":6,"mean_commits":"23.333333333333332","dds":0.5857142857142856,"last_synced_commit":"fb5221a49f4a53bac84211658cf935860a6d8eec"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slimkit%2Fplus-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slimkit%2Fplus-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slimkit%2Fplus-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slimkit%2Fplus-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slimkit","download_url":"https://codeload.github.com/slimkit/plus-editor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251789618,"owners_count":21644086,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T04:32:10.624Z","updated_at":"2025-04-30T22:11:37.588Z","avatar_url":"https://github.com/slimkit.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Plus rich-text editor\n\n![Travis (.org)](https://img.shields.io/travis/slimkit/plus-editor?style=flat-square)\n\n## webview / iframe 通信\n\n### webview -\u003e 客户端 通信\n\n- 安卓端注入 `window.launcher` 对象\n- IOS 端注入 `window.messageHandlers` 对象\n- PC iframe 使用 `window.top.postMessage` 进行通信 **注意自行设置接受 postMessage 消息的安全域名, 详见 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage#Security_concerns **\n\n调用时只需使用 `src/caller.ts` 中的 `callMethod` 方法通知各客户端\n\n### 客户端 -\u003e webview 通信\n\n在各环境中直接调用 webview 中提供的 javascript 方法即可\n\n## 事件\n\n### 向富文本编辑器置入内容\n\n1. 客户端向编辑器插入内容调用 webview 以下内容\n\n   ```js\n   window.setContentReceiver('\u003cp\u003e我是html字符串\u003c/p\u003e')\n   ```\n\n### 视频\n\n1. 点击富文本编辑器中的视频按钮后, 向各端发起视频选择的方法 `chooseVideo()`\n\n2. 宿主端收到视频选择的通知后, 调起视频选择功能,  \n   视频选择完成后, 开始静默上传视频, 同时将视频预览地址, 加上视频唯一标示(id)一同发送给 webview\n\n   调用 webview 的以下方法传递预览图\n\n   ```js\n   window.videoPreviewReceiver(\n     '[{ \"id\": \"unique-id\", \"url\": \"local-file-path\", \"poster\": \"local-file-path\", width:100, height:100 }]',\n   )\n   ```\n\n3. 上传视频过程中，设置视频上传进度\n\n   ```js\n   window.videoProgressReceiver('{ \"id\": \"unique-id\", \"progress\": 15 }')\n   ```\n\n4. 待视频上传完毕后, 将视频网络地址连同刚才的唯一标识(id)再次发送给 webview\n\n   调用 webview 的以下方法传递上传后的视频, 编辑器会在提交时进行替换, node 为可选\n\n   ```js\n   window.videoUrlReceiver(\n     '{ \"id\": \"unique-id\", \"url\": \"newwork-file-url\", \"urlNode\": \"xxx\", \"poster\": \"newwork-file-url\", \"posterNode\": \"xxx\" }',\n   )\n   ```\n\n5. 视频上传失败后, 各端调用 webview 的以下方法通知 webview 在指定 id 的视频上显示上传失败的提示，其中 error 参数不是必填的\n\n   ```js\n   window.videoFailedReceiver('{\"id\":\"unique-id\", \"error\":\"错误原因\"}')\n   ```\n\n6. 用户点击上传失败的视频时，会调用各端的 `reuploadVideo('{\"id\":\"unique-id\"}')` 方法通知重传，重传失败时重复第 5 步，重传成功重复第 4 步.\n\n7. 用户删除视频时，调用各端`removeVideo('{\"id\":\"unique-id\", \"status\":\"UPLOADING\"}')`，其中 status 的值有 UPLOADING|ERROR|SUCCESS 分别表示 上传中|上传失败|上传成功，通常上传失败和成功不需要处理\n\n8. 当编辑器插入 id 重复的视频时（例如删除后撤销删除），将调用各端`reinsertVideo('{\"id\":\"unique-id\", \"status\":\"UPLOADING\"}')`，其中 status 的值有 UPLOADING|ERROR|SUCCESS 分别表示 上传中|上传失败|上传成功，通常上传失败和成功不需要处理\n\n### 图片\n\n1. 点击富文本编辑器中的图片按钮后, 向各端发起图片选择的方法 `chooseImage()`\n\n2. 宿主端收到图片选择的通知后, 调起图片选择功能,  \n   图片选择完成后, 开始静默上传图片, 同时将图片预览地址, 加上图片唯一标示(id)一同发送给 webview\n\n   调用 webview 的以下方法传递预览图\n\n   ```js\n   window.imagePreviewReceiver(\n     '[{ \"id\": \"unique-id\", \"url\": \"local-file-path\", width:100, height:100 }]',\n   )\n   ```\n\n3. 上传图片过程中，设置图片上传进度\n\n   ```js\n   window.imageProgressReceiver('{ \"id\": \"unique-id\", \"progress\": 15 }')\n   ```\n\n4. 待图片上传完毕后, 将图片网络地址连同刚才的唯一标识(id)再次发送给 webview\n\n   调用 webview 的以下方法传递上传后的图片, 编辑器会在提交时进行替换，node 参数是可选的\n\n   ```js\n   window.imageUrlReceiver('{ \"id\": \"unique-id\", \"url\": \"newwork-file-url\", \"node\": \"xxx\" }')\n   ```\n\n5. 图片上传失败后, 各端调用 webview 的以下方法通知 webview 在指定 id 的图片上显示上传失败的提示，其中 error 参数不是必填的\n\n   ```js\n   window.imageFailedReceiver('{\"id\":\"unique-id\", \"error\":\"错误原因\"}')\n   ```\n\n6. 用户点击上传失败的图片时，会调用各端的 `reuploadImage('{\"id\":\"unique-id\"}')` 方法通知重传，重传失败时重复第 5 步，重传成功重复第 4 步.\n\n7. 用户删除图片时，调用各端`removeImage('{\"id\":\"unique-id\", \"status\":\"UPLOADING\"}')`，其中 status 的值有 UPLOADING|ERROR|SUCCESS 分别表示 上传中|上传失败|上传成功，通常上传失败和成功不需要处理\n\n8. 当编辑器插入 id 重复的图片时（例如删除后撤销删除），将调用各端`reinsertImage('{\"id\":\"unique-id\", \"status\":\"UPLOADING\"}')`，其中 status 的值有 UPLOADING|ERROR|SUCCESS 分别表示 上传中|上传失败|上传成功，通常上传失败和成功不需要处理\n\n### 编辑器上传文件\n\n当在 iframe 中时，编辑器会自行上传文件，iframe 上层需设置基础 api url 和用户 token\n\n```js\nwindow.setUploaderOptions(\n  '{\"apiV2BaseUrl\": \"https://domain/api/v2\", \"userToken\": \"token\", \"storage\": {\"channel\": \"public\"}}',\n)\n```\n\n### 提交\n\n1. 移动端点击下一步或提交时, 向 webview 发送一条通知, 用于获取富文本内容\n\n   ```js\n   window.editorSubmitReceiver()\n   ```\n\n2. webview 收到通知后, 会调用客户端的 `sendContentHTML()` 方法传递 html 和其他所需字段, 内容结构如下\n\n   ```json\n   {\n     \"html\": \"\u003ch1\u003e我是html字符串\u003c/h1\u003e\u003cimg src=\\\"https://xxx.png\\\"\u003e\",\n     \"pendingImages\": [\"1\", \"2\", \"3\"], // 正在上传或上传失败的图片id数组\n     \"pendingVideos\": [\"1\", \"2\", \"3\"] // 正在上传或上传失败的视频id数组\n   }\n   ```\n\n### 设置页面尺寸\n\nwebview 文档就绪和窗口大小发生变化时，将调用 `setDocSize('{\"width\":123.0,\"height\":789.0}')` 通知客户端 webview 新的宽高\n\n### 点击图片预览\n\nwebview 中图片被点击后，将调用 `clickImage('{\"src\":\"点击的图片URL\",\"index\":0,\"images\":[{\"src\":\"图片地址\",\"width\":100,\"height\":100}]}')` 通知客户端，客户端实现图片预览功能\n\n### 文档加载完毕\n\nwebview 文档就绪时，将调用 `docReady({\"docWidth\":123.0,\"docHeight\":789.0})` 通知客户端，文档就绪时，图片点击才会通知客户端\n\n### 页面隐藏通知\n\nwebview 被隐藏时，客户端应该通知 webview，webview 将暂停页面播放的媒体\n\n```js\nwindow.pageHiddenReceiver()\n```\n\n### 打印日志\n\nwebview 将调用 `showLog(\"日志内容\")` 通知客户端打印日志，客户端将日志打印在自己的控制台\n\n# 开发\n\n## 技术选型\n\n- `webpack` 多入口打包\n- `stylus` 因为 quill 的样式基于 stylus, 为了保证良好的兼容性, 故也选择了 stylus, 需要配合 vscode 推荐插件达到自动格式化的目的.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslimkit%2Fplus-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslimkit%2Fplus-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslimkit%2Fplus-editor/lists"}