├── .env.development ├── .env.production ├── .gitignore ├── README.md ├── index.html ├── package.json ├── public ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico └── static │ └── tinymce │ ├── icons │ └── default │ │ └── icons.min.js │ ├── langs │ ├── README.md │ └── zh_CN.js │ ├── license.md │ ├── models │ └── dom │ │ └── model.min.js │ ├── plugins │ ├── accordion │ │ └── plugin.min.js │ ├── advlist │ │ └── plugin.min.js │ ├── anchor │ │ └── plugin.min.js │ ├── autolink │ │ └── plugin.min.js │ ├── autoresize │ │ └── plugin.min.js │ ├── autosave │ │ └── plugin.min.js │ ├── charmap │ │ └── plugin.min.js │ ├── code │ │ └── plugin.min.js │ ├── codesample │ │ └── plugin.min.js │ ├── directionality │ │ └── plugin.min.js │ ├── emoticons │ │ ├── js │ │ │ ├── emojiimages.js │ │ │ ├── emojiimages.min.js │ │ │ ├── emojis.js │ │ │ └── emojis.min.js │ │ └── plugin.min.js │ ├── fullscreen │ │ └── plugin.min.js │ ├── help │ │ ├── js │ │ │ └── i18n │ │ │ │ └── keynav │ │ │ │ ├── ar.js │ │ │ │ ├── bg_BG.js │ │ │ │ ├── ca.js │ │ │ │ ├── cs.js │ │ │ │ ├── da.js │ │ │ │ ├── de.js │ │ │ │ ├── el.js │ │ │ │ ├── en.js │ │ │ │ ├── es.js │ │ │ │ ├── eu.js │ │ │ │ ├── fa.js │ │ │ │ ├── fi.js │ │ │ │ ├── fr_FR.js │ │ │ │ ├── he_IL.js │ │ │ │ ├── hi.js │ │ │ │ ├── hr.js │ │ │ │ ├── hu_HU.js │ │ │ │ ├── id.js │ │ │ │ ├── it.js │ │ │ │ ├── ja.js │ │ │ │ ├── kk.js │ │ │ │ ├── ko_KR.js │ │ │ │ ├── ms.js │ │ │ │ ├── nb_NO.js │ │ │ │ ├── nl.js │ │ │ │ ├── pl.js │ │ │ │ ├── pt_BR.js │ │ │ │ ├── pt_PT.js │ │ │ │ ├── ro.js │ │ │ │ ├── ru.js │ │ │ │ ├── sk.js │ │ │ │ ├── sl_SI.js │ │ │ │ ├── sv_SE.js │ │ │ │ ├── th_TH.js │ │ │ │ ├── tr.js │ │ │ │ ├── uk.js │ │ │ │ ├── vi.js │ │ │ │ ├── zh_CN.js │ │ │ │ └── zh_TW.js │ │ └── plugin.min.js │ ├── image │ │ └── plugin.min.js │ ├── importcss │ │ └── plugin.min.js │ ├── insertdatetime │ │ └── plugin.min.js │ ├── link │ │ └── plugin.min.js │ ├── lists │ │ └── plugin.min.js │ ├── media │ │ └── plugin.min.js │ ├── nonbreaking │ │ └── plugin.min.js │ ├── pagebreak │ │ └── plugin.min.js │ ├── preview │ │ └── plugin.min.js │ ├── quickbars │ │ └── plugin.min.js │ ├── save │ │ └── plugin.min.js │ ├── searchreplace │ │ └── plugin.min.js │ ├── table │ │ └── plugin.min.js │ ├── visualblocks │ │ └── plugin.min.js │ ├── visualchars │ │ └── plugin.min.js │ └── wordcount │ │ └── plugin.min.js │ ├── skins │ ├── content │ │ ├── dark │ │ │ ├── content.js │ │ │ └── content.min.css │ │ ├── default │ │ │ ├── content.js │ │ │ └── content.min.css │ │ ├── document │ │ │ ├── content.js │ │ │ └── content.min.css │ │ ├── tinymce-5-dark │ │ │ ├── content.js │ │ │ └── content.min.css │ │ ├── tinymce-5 │ │ │ ├── content.js │ │ │ └── content.min.css │ │ └── writer │ │ │ ├── content.js │ │ │ └── content.min.css │ └── ui │ │ ├── oxide-dark │ │ ├── content.inline.js │ │ ├── content.inline.min.css │ │ ├── content.js │ │ ├── content.min.css │ │ ├── skin.js │ │ ├── skin.min.css │ │ ├── skin.shadowdom.js │ │ └── skin.shadowdom.min.css │ │ ├── oxide │ │ ├── content.inline.js │ │ ├── content.inline.min.css │ │ ├── content.js │ │ ├── content.min.css │ │ ├── skin.js │ │ ├── skin.min.css │ │ ├── skin.shadowdom.js │ │ └── skin.shadowdom.min.css │ │ ├── tinymce-5-dark │ │ ├── content.inline.js │ │ ├── content.inline.min.css │ │ ├── content.js │ │ ├── content.min.css │ │ ├── skin.js │ │ ├── skin.min.css │ │ ├── skin.shadowdom.js │ │ └── skin.shadowdom.min.css │ │ └── tinymce-5 │ │ ├── content.inline.js │ │ ├── content.inline.min.css │ │ ├── content.js │ │ ├── content.min.css │ │ ├── skin.js │ │ ├── skin.min.css │ │ ├── skin.shadowdom.js │ │ └── skin.shadowdom.min.css │ ├── themes │ └── silver │ │ └── theme.min.js │ ├── tinymce.d.ts │ └── tinymce.min.js ├── src ├── App.vue ├── api │ ├── article.ts │ ├── express.ts │ ├── goods.ts │ ├── main.ts │ ├── order.ts │ ├── other.ts │ ├── system.ts │ └── user.ts ├── assets │ ├── images │ │ ├── 401.gif │ │ ├── 404.png │ │ └── 404_cloud.png │ ├── login │ │ ├── bg.png │ │ └── left.jpg │ ├── logo.png │ ├── style │ │ ├── common.scss │ │ └── transition.scss │ └── svg │ │ └── read.md ├── config │ └── index.ts ├── layout │ ├── Header │ │ ├── Breadcrumb.vue │ │ ├── functionList │ │ │ ├── fullscreen.vue │ │ │ ├── sizeChange.vue │ │ │ ├── theme.vue │ │ │ └── theme │ │ │ │ ├── theme-color.vue │ │ │ │ └── theme-icon.vue │ │ ├── index.vue │ │ └── passwordLayer.vue │ ├── Logo │ │ └── index.vue │ ├── Menu │ │ ├── Link.vue │ │ ├── MenuItem.vue │ │ └── index.vue │ ├── Tabs │ │ ├── index.vue │ │ └── item.vue │ └── index.vue ├── main.ts ├── router │ ├── createNode.ts │ ├── index.ts │ ├── index.type.ts │ ├── modules │ │ ├── dashboard.ts │ │ └── system.ts │ ├── permission │ │ └── front.ts │ └── reload.vue ├── stores │ ├── app.ts │ ├── index.ts │ └── user.ts ├── theme │ ├── index.scss │ ├── index.ts │ └── modules │ │ ├── chinese │ │ ├── index.scss │ │ └── screen.png │ │ └── dark.scss ├── types │ ├── images.d.ts │ ├── main.d.ts │ └── shims-vue.d.ts ├── utils │ ├── index.ts │ ├── system │ │ ├── nprogress.ts │ │ ├── request.ts │ │ ├── statistics.ts │ │ └── title.ts │ └── tab │ │ └── index.ts └── views │ ├── article │ ├── article.vue │ └── category.vue │ ├── express │ ├── company.vue │ ├── feeRule.vue │ └── freeRule.vue │ ├── goods │ ├── brand.vue │ ├── category.vue │ ├── goods.vue │ ├── spec.vue │ └── template.vue │ ├── main │ ├── 401.vue │ ├── 404.vue │ ├── home.vue │ ├── login.vue │ └── redirect.vue │ ├── order │ └── order.vue │ ├── other │ ├── carousel.vue │ └── staticRes.vue │ ├── system │ ├── components │ │ └── ElIconPicker.vue │ ├── config.vue │ ├── info.vue │ ├── log.vue │ ├── manager.vue │ ├── menu.vue │ ├── payment.vue │ └── role.vue │ └── user │ ├── balanceLog.vue │ ├── log.vue │ └── user.vue ├── tsconfig.json └── vite.config.mts /.env.development: -------------------------------------------------------------------------------- 1 | ENV = 'development' 2 | 3 | VITE_BASE_URL = '/adminApi' -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | ENV = 'production' 2 | 3 | VITE_BASE_URL = '/adminApi' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /mock 3 | /node_modules 4 | /package-lock.json 5 | /pnpm-lock.yaml 6 | /.idea 7 | /.DS_Store 8 | /.vscode 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 介绍 3 | 4 | 使用最新版本的vue3+vite+element-plus开发而成,目的是为了解决通用型的业务中后台系统复杂的配置。 5 |
6 | 演示地址: 账号:demo 密码:demodemo 7 | 8 | #### 特色功能 9 | 10 | - 适合中后台开发的路由配置、状态管理机制(状态默认支持本地存储)、已封装完善的axios及api管理机制 11 | - 极方便扩展的主题配置功能,默认支持三种典型的中后台风格 12 | - 简易配置的页面缓存功能,只需配置noCache属性,无需配置其他的任何属性,如组件名称,路由名称等等很多框架需要配置的东西 13 | - 典型增删改查的三种业务表格,详情请查看“页面栏目”内的“业务表格”、“分类联动表格”、“树联动表格” 14 | - 无路由跳转的刷新功能,支持缓存页面刷新,目前了解的多数框架都不支持缓存页面的刷新 15 | - 手写版本的各类自定义指令 16 | - 已经过多个中后台业务检验过的表格公用组件及弹窗公用组件,详情请查看“页面栏目”内的“业务表格”、“分类联动表格”、“树联动表格” 17 | 18 | #### 主要技术栈 19 | 20 | - MVVM框架:vue v3 21 | - 工程化管理:vite v5 22 | - UI框架:element-plus 23 | - 路由管理:vue-router v4 24 | - 状态管理:pinia 25 | - 实用工具库:@vueuse/core 26 | 27 | #### 使用 28 | 29 | ```bash 30 | # 安装依赖,推荐使用pnpm 31 | pnpm install 32 | 33 | # 运行 34 | pnpm run dev 35 | 36 | # 打包 37 | pnpm run build 38 | ``` 39 | ### 源代码 40 | 项目地址:
41 | 管理界面: -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-manage", 3 | "version": "1.1.0", 4 | "scripts": { 5 | "dev": "vite --port 8001", 6 | "start": "vite", 7 | "build": "vite build --mode=production", 8 | "serve": "vite preview --port 8001" 9 | }, 10 | "dependencies": { 11 | "@element-plus/icons-vue": "^2.3.1", 12 | "@tinymce/tinymce-vue": "^6.0.1", 13 | "@vueuse/core": "^11.0.3", 14 | "axios": "^1.7.5", 15 | "element-plus": "^2.8.1", 16 | "jsencrypt": "^3.3.2", 17 | "mathjs": "^13.0.3", 18 | "normalize.css": "^8.0.1", 19 | "nprogress": "^0.2.0", 20 | "pinia": "^2.2.2", 21 | "pinia-plugin-persistedstate": "^3.2.1", 22 | "tinymce": "^7.3.0", 23 | "vue": "^3.4.38", 24 | "vue-router": "^4.4.3" 25 | }, 26 | "devDependencies": { 27 | "@rollup/rollup-win32-x64-msvc": "^4.21.0", 28 | "@types/node": "^22.5.0", 29 | "@vitejs/plugin-vue": "^5.1.2", 30 | "@vue/compiler-sfc": "^3.4.38", 31 | "@webxrd/vite-plugin-svg": "^1.0.11", 32 | "eslint": "^9.9.1", 33 | "sass": "^1.77.8", 34 | "typescript": "^5.5.4", 35 | "unplugin-auto-import": "^0.18.2", 36 | "unplugin-vue-components": "^0.27.4", 37 | "vite": "^5.4.2", 38 | "vue-tsc": "^2.0.29" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/public/favicon.ico -------------------------------------------------------------------------------- /public/static/tinymce/langs/README.md: -------------------------------------------------------------------------------- 1 | This is where language files should be placed. 2 | 3 | Please DO NOT translate these directly, use this service instead: https://crowdin.com/project/tinymce 4 | -------------------------------------------------------------------------------- /public/static/tinymce/license.md: -------------------------------------------------------------------------------- 1 | # Software License Agreement 2 | 3 | **TinyMCE** – [](https://github.com/tinymce/tinymce) 4 | Copyright (c) 2024, Ephox Corporation DBA Tiny Technologies, Inc. 5 | 6 | Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). 7 | -------------------------------------------------------------------------------- /public/static/tinymce/plugins/advlist/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),i=t=>null==t,l=t=>!i(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return l(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>e=>l(e)&&t.test(e.nodeName),d=u(/^(OL|UL|DL)$/),g=u(/^(TH|TD)$/),c=t=>i(t)||"default"===t?"":t,h=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;ee.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)&&t.selection.isEditable()})(t,n)&&t.selection.isEditable())})(t,r.parents))),m=(t,s,r,n,i,l)=>{l.length>1?((t,s,r,n,i,l)=>{t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(l,(t=>{const e="OL"===i?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=c(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,i,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return a.from(s)})(t);return s.map((t=>e===t)).getOr(!1)},onSetup:h(t,i)})})(t,s,r,n,i,l):((t,s,r,n,i,l)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",onSetup:h(t,i),onAction:()=>t.queryCommandState(n)||""===l?t.execCommand(n):e(t,i,l)})})(t,s,r,n,i,c(l[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{m(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),m(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/anchor/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;ot=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>{const o=e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind,n=u(e)(t);return()=>{o(),n()}}}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t,onSetup:u(e)})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/autolink/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=4&&b.substr(0,4)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/autoresize/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),g=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},l=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},a=(e,o,r,c)=>{var d;const u=e.dom,h=e.getDoc();if(!h)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void g(e,!0);const m=h.documentElement,f=c?c():i(e),p=null!==(d=n(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=l(u,m,"margin-top",!0),v=l(u,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+f;C<0&&(C=0);const H=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+H>p&&(y=C+H);const b=s(e);b&&y>b?(y=b,g(e,!0)):g(e,!1);const w=o.get();if(w.set&&(e.dom.setStyles(e.getDoc().documentElement,{"min-height":0}),e.dom.setStyles(e.getBody(),{"min-height":"inherit"})),y!==w.totalHeight&&(C-f!==w.contentHeight||!w.set)){const n=y-w.totalHeight;if(u.setStyle(e.getContainer(),"height",y+"px"),o.set({totalHeight:y,contentHeight:C,set:!0}),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t={totalHeight:0,contentHeight:0,set:!1};return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{const n=()=>r(e);e.on("init",(s=>{const r=i(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,s,n)})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{a(e,o,t,n)}))})(e,o)}}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/autosave/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/code/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/directionality/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(11),y=(t,e)=>{t.dom.removeAttribute(e)},p=t=>d(t.dom.host),w=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=(t=>d(t.dom.getRootNode()))(t);return v(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=w,i=p,t=>r(i(t))));var r,i},b=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||w(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",S=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r{const o=t.length,r=new Array(o);for(let n=0;nh(t,e))))(t),N=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const A=(t,e,n)=>{u(e,(e=>{const c=d(e),m=N(c),f=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(c,m);var v;(v=f,(t=>a.from(t.dom.parentNode).map(d))(v).filter(g)).each((e=>{if(t.setStyle(f.dom,"direction",null),b(e)===n?y(f,"dir"):((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(f,"dir",n),b(f)!==n&&t.setStyle(f.dom,"direction",n),m){const e=S(f,"li[dir],li[style]");u(e,(e=>{y(e,"dir"),t.setStyle(e.dom,"direction",null)}))}}))}))},T=(t,e)=>{t.selection.isEditable()&&(A(t.dom,t.selection.getSelectedBlocks(),e),t.nodeChanged())},C=(t,e)=>o=>{const r=r=>{const n=d(r.element);o.setActive(b(n)===e),o.setEnabled(t.selection.isEditable())};return t.on("NodeChange",r),o.setEnabled(t.selection.isEditable()),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{T(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{T(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:C(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:C(t,"rtl")})})(t)}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/da.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.da', 2 | '

Start tastaturnavigation

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
Fokuser på menulinjen
\n' + 6 | '
Windows eller Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
Fokuser på værktøjslinjen
\n' + 9 | '
Windows eller Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
Fokuser på sidefoden
\n' + 12 | '
Windows eller Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
Fokuser på meddelelsen
\n' + 15 | '
Windows eller Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
Fokuser på kontekstuel værktøjslinje
\n' + 18 | '
Windows, Linux eller macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

Navigationen starter ved det første UI-element, som fremhæves eller understreges hvad angår det første element i\n' + 22 | ' sidefodens sti til elementet.

\n' + 23 | '\n' + 24 | '

Naviger mellem UI-sektioner

\n' + 25 | '\n' + 26 | '

Gå fra én UI-sektion til den næste ved at trykke på Tab.

\n' + 27 | '\n' + 28 | '

Gå fra én UI-sektion til den forrige ved at trykke på Shift+Tab.

\n' + 29 | '\n' + 30 | '

Tab-rækkefølgen af disse UI-sektioner er:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. Menulinje
  2. \n' + 34 | '
  3. Hver værktøjsgruppe
  4. \n' + 35 | '
  5. Sidepanel
  6. \n' + 36 | '
  7. Sti til elementet i sidefoden
  8. \n' + 37 | '
  9. Til/fra-knap for ordoptælling i sidefoden
  10. \n' + 38 | '
  11. Brandinglink i sidefoden
  12. \n' + 39 | '
  13. Tilpasningshåndtag for editor i sidefoden
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

Hvis en UI-sektion ikke er til stede, springes den over.

\n' + 43 | '\n' + 44 | '

Hvis sidefoden har fokus til tastaturnavigation, og der ikke er noget synligt sidepanel, kan der trykkes på Shift+Tab\n' + 45 | ' for at flytte fokus til den første værktøjsgruppe, ikke den sidste.

\n' + 46 | '\n' + 47 | '

Naviger inden for UI-sektioner

\n' + 48 | '\n' + 49 | '

Gå fra ét UI-element til det næste ved at trykke på den relevante piletast.

\n' + 50 | '\n' + 51 | '

Venstre og højre piletast

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • flytter mellem menuerne i menulinjen.
  • \n' + 55 | '
  • åbner en undermenu i en menu.
  • \n' + 56 | '
  • flytter mellem knapperne i en værktøjsgruppe.
  • \n' + 57 | '
  • flytter mellem elementer i sidefodens sti til elementet.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

Pil ned og op

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • flytter mellem menupunkterne i en menu.
  • \n' + 64 | '
  • flytter mellem punkterne i en genvejsmenu i værktøjslinjen.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

Piletasterne kører rundt inden for UI-sektionen, der fokuseres på.

\n' + 68 | '\n' + 69 | '

For at lukke en åben menu, en åben undermenu eller en åben genvejsmenu trykkes der på Esc-tasten.

\n' + 70 | '\n' + 71 | "

Hvis det aktuelle fokus er i 'toppen' af en bestemt UI-sektion, vil tryk på Esc-tasten også afslutte\n" + 72 | ' tastaturnavigationen helt.

\n' + 73 | '\n' + 74 | '

Udfør et menupunkt eller en værktøjslinjeknap

\n' + 75 | '\n' + 76 | '

Når det ønskede menupunkt eller den ønskede værktøjslinjeknap er fremhævet, trykkes der på Retur, Enter\n' + 77 | ' eller mellemrumstasten for at udføre elementet.

\n' + 78 | '\n' + 79 | '

Naviger i ikke-faneopdelte dialogbokse

\n' + 80 | '\n' + 81 | '

I ikke-faneopdelte dialogbokse får den første interaktive komponent fokus, når dialogboksen åbnes.

\n' + 82 | '\n' + 83 | '

Naviger mellem interaktive dialogbokskomponenter ved at trykke på Tab eller Shift+Tab.

\n' + 84 | '\n' + 85 | '

Naviger i faneopdelte dialogbokse

\n' + 86 | '\n' + 87 | '

I faneopdelte dialogbokse får den første knap i fanemenuen fokus, når dialogboksen åbnes.

\n' + 88 | '\n' + 89 | '

Naviger mellem interaktive komponenter i denne dialogboksfane ved at trykke på Tab eller\n' + 90 | ' Shift+Tab.

\n' + 91 | '\n' + 92 | '

Skift til en anden dialogboksfane ved at fokusere på fanemenuen og derefter trykke på den relevante piletast\n' + 93 | ' for at køre igennem de tilgængelige faner.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/en.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.en', 2 | '

Begin keyboard navigation

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
Focus the Menu bar
\n' + 6 | '
Windows or Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
Focus the Toolbar
\n' + 9 | '
Windows or Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
Focus the footer
\n' + 12 | '
Windows or Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
Focus the notification
\n' + 15 | '
Windows or Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
Focus a contextual toolbar
\n' + 18 | '
Windows, Linux or macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

Navigation will start at the first UI item, which will be highlighted, or underlined in the case of the first item in\n' + 22 | ' the Footer element path.

\n' + 23 | '\n' + 24 | '

Navigate between UI sections

\n' + 25 | '\n' + 26 | '

To move from one UI section to the next, press Tab.

\n' + 27 | '\n' + 28 | '

To move from one UI section to the previous, press Shift+Tab.

\n' + 29 | '\n' + 30 | '

The Tab order of these UI sections is:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. Menu bar
  2. \n' + 34 | '
  3. Each toolbar group
  4. \n' + 35 | '
  5. Sidebar
  6. \n' + 36 | '
  7. Element path in the footer
  8. \n' + 37 | '
  9. Word count toggle button in the footer
  10. \n' + 38 | '
  11. Branding link in the footer
  12. \n' + 39 | '
  13. Editor resize handle in the footer
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

If a UI section is not present, it is skipped.

\n' + 43 | '\n' + 44 | '

If the footer has keyboard navigation focus, and there is no visible sidebar, pressing Shift+Tab\n' + 45 | ' moves focus to the first toolbar group, not the last.

\n' + 46 | '\n' + 47 | '

Navigate within UI sections

\n' + 48 | '\n' + 49 | '

To move from one UI element to the next, press the appropriate Arrow key.

\n' + 50 | '\n' + 51 | '

The Left and Right arrow keys

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • move between menus in the menu bar.
  • \n' + 55 | '
  • open a sub-menu in a menu.
  • \n' + 56 | '
  • move between buttons in a toolbar group.
  • \n' + 57 | '
  • move between items in the footer’s element path.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

The Down and Up arrow keys

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • move between menu items in a menu.
  • \n' + 64 | '
  • move between items in a toolbar pop-up menu.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

Arrow keys cycle within the focused UI section.

\n' + 68 | '\n' + 69 | '

To close an open menu, an open sub-menu, or an open pop-up menu, press the Esc key.

\n' + 70 | '\n' + 71 | '

If the current focus is at the ‘top’ of a particular UI section, pressing the Esc key also exits\n' + 72 | ' keyboard navigation entirely.

\n' + 73 | '\n' + 74 | '

Execute a menu item or toolbar button

\n' + 75 | '\n' + 76 | '

When the desired menu item or toolbar button is highlighted, press Return, Enter,\n' + 77 | ' or the Space bar to execute the item.

\n' + 78 | '\n' + 79 | '

Navigate non-tabbed dialogs

\n' + 80 | '\n' + 81 | '

In non-tabbed dialogs, the first interactive component takes focus when the dialog opens.

\n' + 82 | '\n' + 83 | '

Navigate between interactive dialog components by pressing Tab or Shift+Tab.

\n' + 84 | '\n' + 85 | '

Navigate tabbed dialogs

\n' + 86 | '\n' + 87 | '

In tabbed dialogs, the first button in the tab menu takes focus when the dialog opens.

\n' + 88 | '\n' + 89 | '

Navigate between interactive components of this dialog tab by pressing Tab or\n' + 90 | ' Shift+Tab.

\n' + 91 | '\n' + 92 | '

Switch to another dialog tab by giving the tab menu focus and then pressing the appropriate Arrow\n' + 93 | ' key to cycle through the available tabs.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/fa.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.fa', 2 | '

شروع پیمایش صفحه‌کلید

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
تمرکز بر نوار منو
\n' + 6 | '
Windows یا Linux:‎‏: Alt+F9
\n' + 7 | '
‎‏macOS: ⌥F9‎‏
\n' + 8 | '
تمرکز بر نوار ابزار
\n' + 9 | '
Windows یا Linux‎‏: Alt+F10
\n' + 10 | '
‎‏macOS: ⌥F10‎‏
\n' + 11 | '
تمرکز بر پانویس
\n' + 12 | '
Windows یا Linux‎‏: Alt+F11
\n' + 13 | '
‎‏macOS: ⌥F11‎‏
\n' + 14 | '
تمرکز اعلان
\n' + 15 | '
ویندوز یا لینوکس: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
تمرکز بر نوار ابزار بافتاری
\n' + 18 | '
Windows ،Linux یا macOS:‏ Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

پیمایش در اولین مورد رابط کاربری شروع می‌شود و درخصوص اولین مورد در\n' + 22 | ' مسیر عنصر پانویس، برجسته یا زیرخط‌دار می‌شود.

\n' + 23 | '\n' + 24 | '

پیمایش بین بخش‌های رابط کاربری

\n' + 25 | '\n' + 26 | '

برای جابجایی از یک بخش رابط کاربری به بخش بعدی، Tab را فشار دهید.

\n' + 27 | '\n' + 28 | '

برای جابجایی از یک بخش رابط کاربری به بخش قبلی، Shift+Tab را فشار دهید.

\n' + 29 | '\n' + 30 | '

ترتیب Tab این بخش‌های رابط کاربری عبارتند از:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. نوار منو
  2. \n' + 34 | '
  3. هر گروه نوار ابزار
  4. \n' + 35 | '
  5. نوار کناری
  6. \n' + 36 | '
  7. مسیر عنصر در پانویس
  8. \n' + 37 | '
  9. دکمه تغییر وضعیت تعداد کلمات در پانویس
  10. \n' + 38 | '
  11. پیوند نمانام‌سازی در پانویس
  12. \n' + 39 | '
  13. دسته تغییر اندازه ویرایشگر در پانویس
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

اگر بخشی از رابط کاربری موجود نباشد، رد می‌شود.

\n' + 43 | '\n' + 44 | '

اگر پانویس دارای تمرکز بر پیمایش صفحه‌کلید باشد،‌ و نوار کناری قابل‌مشاهده وجود ندارد، فشردن Shift+Tab\n' + 45 | ' تمرکز را به گروه نوار ابزار اول می‌برد، نه آخر.

\n' + 46 | '\n' + 47 | '

پیمایش در بخش‌های رابط کاربری

\n' + 48 | '\n' + 49 | '

برای جابجایی از یک عنصر رابط کاربری به بعدی، کلید جهت‌نمای مناسب را فشار دهید.

\n' + 50 | '\n' + 51 | '

کلیدهای جهت‌نمای چپ و راست

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • جابجایی بین منوها در نوار منو.
  • \n' + 55 | '
  • باز کردن منوی فرعی در یک منو.
  • \n' + 56 | '
  • جابجایی بین دکمه‌ها در یک گروه نوار ابزار.
  • \n' + 57 | '
  • جابجایی بین موارد در مسیر عنصر پانویس.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

کلیدهای جهت‌نمای پایین و بالا

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • جابجایی بین موارد منو در یک منو.
  • \n' + 64 | '
  • جابجایی بین موارد در یک منوی بازشوی نوار ابزار.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

کلیدهایجهت‌نما در بخش رابط کاربری متمرکز می‌چرخند.

\n' + 68 | '\n' + 69 | '

برای بستن یک منوی باز، یک منوی فرعی باز، یا یک منوی بازشوی باز، کلید Esc را فشار دهید.

\n' + 70 | '\n' + 71 | '

اگر تمرکز فعلی در «بالای» یک بخش رابط کاربری خاص است، فشردن کلید Esc نیز موجب\n' + 72 | ' خروج کامل از پیمایش صفحه‌کلید می‌شود.

\n' + 73 | '\n' + 74 | '

اجرای یک مورد منو یا دکمه نوار ابزار

\n' + 75 | '\n' + 76 | '

وقتی مورد منو یا دکمه نوار ابزار مورد نظر هایلایت شد، دکمه بازگشت، Enter،\n' + 77 | ' یا نوار Space را فشار دهید تا مورد را اجرا کنید.

\n' + 78 | '\n' + 79 | '

پیمایش در کادرهای گفتگوی بدون زبانه

\n' + 80 | '\n' + 81 | '

در کادرهای گفتگوی بدون زبانه، وقتی کادر گفتگو باز می‌شود، اولین جزء تعاملی متمرکز می‌شود.

\n' + 82 | '\n' + 83 | '

با فشردن Tab یا Shift+Tab، بین اجزای کادر گفتگوی تعاملی پیمایش کنید.

\n' + 84 | '\n' + 85 | '

پیمایش کادرهای گفتگوی زبانه‌دار

\n' + 86 | '\n' + 87 | '

در کادرهای گفتگوی زبانه‌دار، وقتی کادر گفتگو باز می‌شود، اولین دکمه در منوی زبانه متمرکز می‌شود.

\n' + 88 | '\n' + 89 | '

با فشردن Tab یا\n' + 90 | ' Shift+Tab، بین اجزای تعاملی این زبانه کادر گفتگو پیمایش کنید.

\n' + 91 | '\n' + 92 | '

با دادن تمرکز به منوی زبانه و سپس فشار دادن کلید جهت‌نمای\n' + 93 | ' مناسب برای چرخش میان زبانه‌های موجود، به زبانه کادر گفتگوی دیگری بروید.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/he_IL.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.he_IL', 2 | '

התחל ניווט במקלדת

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
התמקד בשורת התפריטים
\n' + 6 | '
Windows או Linux:‏ Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
העבר מיקוד לסרגל הכלים
\n' + 9 | '
Windows או Linux:‏ Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
העבר מיקוד לכותרת התחתונה
\n' + 12 | '
Windows או Linux:‏ Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
העבר מיקוד להודעה
\n' + 15 | '
Windows או Linux:‏ Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
העבר מיקוד לסרגל כלים הקשרי
\n' + 18 | '
Windows‏, Linux או macOS:‏ Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

הניווט יתחיל ברכיב הראשון במשך, שיודגש או שיהיה מתחתיו קו תחתון במקרה של הפריט הראשון\n' + 22 | ' הנתיב של רכיב הכותרת התחתונה.

\n' + 23 | '\n' + 24 | '

עבור בין מקטעים במסך

\n' + 25 | '\n' + 26 | '

כדי לעבור בין המקטעים במסך, הקש Tab.

\n' + 27 | '\n' + 28 | '

כדי לעבור למקטע הקודם במסך, הקש Shift+Tab.

\n' + 29 | '\n' + 30 | '

הסדר מבחינת מקש Tab של הרכיבים במסך:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. שורת התפריטים
  2. \n' + 34 | '
  3. כל קבוצה בסרגל הכלים
  4. \n' + 35 | '
  5. הסרגל הצידי
  6. \n' + 36 | '
  7. נתיב של רכיב בכותרת התחתונה
  8. \n' + 37 | '
  9. לחצן לספירת מילים בכותרת התחתונה
  10. \n' + 38 | '
  11. קישור של המותג בכותרת התחתונה
  12. \n' + 39 | '
  13. ידית לשינוי גודל עבור העורך בכותרת התחתונה
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

אם רכיב כלשהו במסך לא מופיע, המערכת תדלג עליו.

\n' + 43 | '\n' + 44 | '

אם בכותרת התחתונה יש מיקוד של ניווט במקלדת, ולא מופיע סרגל בצד, יש להקיש Shift+Tab\n' + 45 | ' מעביר את המיקוד לקבוצה הראשונה בסרגל הכלים, לא האחרונה.

\n' + 46 | '\n' + 47 | '

עבור בתוך מקטעים במסך

\n' + 48 | '\n' + 49 | '

כדי לעבור מרכיב אחד לרכיב אחר במסך, הקש על מקש החץ המתאים.

\n' + 50 | '\n' + 51 | '

מקשי החיצים שמאלה וימינה

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • עבור בין תפריטים בשורת התפריטים.
  • \n' + 55 | '
  • פתח תפריט משני בתפריט.
  • \n' + 56 | '
  • עבור בין לחצנים בקבוצה בסרגל הכלים.
  • \n' + 57 | '
  • עבור בין פריטים ברכיב בכותרת התחתונה.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

מקשי החיצים למטה ולמעלה

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • עבור בין פריטים בתפריט.
  • \n' + 64 | '
  • עבור בין פריטים בחלון הקובץ של סרגל הכלים.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

מקשי החצים משתנים בתוך המקטע במסך שעליו נמצא המיקוד.

\n' + 68 | '\n' + 69 | '

כדי לסגור תפריט פתוח, תפריט משני פתוח או חלון קופץ, הקש על Esc.

\n' + 70 | '\n' + 71 | "

אם המיקוד הוא על החלק 'העליון' של מקטע מסוים במסך, הקשה על Esc מביאה גם ליציאה\n" + 72 | ' מהניווט במקלדת לחלוטין.

\n' + 73 | '\n' + 74 | '

הפעל פריט בתפריט או לחצן בסרגל הכלים

\n' + 75 | '\n' + 76 | '

כאשר הפריט הרצוי בתפריט או הלחצן בסרגל הכלים מודגשים, הקש על Return, Enter,\n' + 77 | ' או על מקש הרווח כדי להפעיל את הפריט.

\n' + 78 | '\n' + 79 | '

ניווט בחלונות דו-שיח בלי כרטיסיות

\n' + 80 | '\n' + 81 | '

בחלונות דו-שיח בלי כרטיסיות, הרכיב האינטראקטיבי הראשון מקבל את המיקוד כאשר החלון נפתח.

\n' + 82 | '\n' + 83 | '

עבור בין רכיבים אינטראקטיביים בחלון על ידי הקשה על Tab או Shift+Tab.

\n' + 84 | '\n' + 85 | '

ניווט בחלונות דו-שיח עם כרטיסיות

\n' + 86 | '\n' + 87 | '

בחלונות דו-שיח עם כרטיסיות, הלחצן הראשון בתפריט מקבל את המיקוד כאשר החלון נפתח.

\n' + 88 | '\n' + 89 | '

עבור בין רכיבים אינטראקטיביים בחלון על ידי הקשה על Tab או\n' + 90 | ' Shift+Tab.

\n' + 91 | '\n' + 92 | '

עבור לכרטיסיה אחרת בחלון על ידי העברת המיקוד לתפריט הכרטיסיות והקשה על החץהמתאים\n' + 93 | ' כדי לעבור בין הכרטיסיות הזמינות.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/hi.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.hi', 2 | '

कीबोर्ड नेविगेशन शुरू करें

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
मेन्यू बार पर फ़ोकस करें
\n' + 6 | '
Windows या Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
टूलबार पर फ़ोकस करें
\n' + 9 | '
Windows या Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
फ़ुटर पर फ़ोकस करें
\n' + 12 | '
Windows या Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
नोटिफ़िकेशन फ़ोकस
\n' + 15 | '
Windows या Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
प्रासंगिक टूलबार पर फ़ोकस करें
\n' + 18 | '
Windows, Linux या macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

नेविगेशन पहले UI आइटम पर शुरू होगा, जिसे हाइलाइट किया जाएगा या पहले आइटम के मामले में फ़ुटर तत्व पथ में\n' + 22 | ' रेखांकित किया जाएगा।

\n' + 23 | '\n' + 24 | '

UI सेक्शन के बीच नेविगेट करें

\n' + 25 | '\n' + 26 | '

एक UI सेक्शन से दूसरे सेक्शन में जाने के लिए, Tab दबाएं।

\n' + 27 | '\n' + 28 | '

एक UI सेक्शन से पिछले सेक्शन में जाने के लिए, Shift+Tab दबाएं।

\n' + 29 | '\n' + 30 | '

इन UI सेक्शन का Tab क्रम नीचे दिया गया है:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. मेन्यू बार
  2. \n' + 34 | '
  3. प्रत्येक टूलबार समूह
  4. \n' + 35 | '
  5. साइडबार
  6. \n' + 36 | '
  7. फ़ुटर में तत्व पथ
  8. \n' + 37 | '
  9. फ़ुटर में शब्द गणना टॉगल बटन
  10. \n' + 38 | '
  11. फ़ुटर में ब्रांडिंग लिंक
  12. \n' + 39 | '
  13. फ़ुटर में संपादक का आकार बदलने का हैंडल
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

अगर कोई UI सेक्शन मौजूद नहीं है, तो उसे छोड़ दिया जाता है।

\n' + 43 | '\n' + 44 | '

अगर फ़ुटर में कीबोर्ड नेविगेशन फ़ोकस है, और कोई दिखा देने वाला साइडबार नहीं है, तो Shift+Tab दबाने से\n' + 45 | ' फ़ोकस पहले टूलबार समूह पर चला जाता है, पिछले पर नहीं।

\n' + 46 | '\n' + 47 | '

UI सेक्शन के भीतर नेविगेट करें

\n' + 48 | '\n' + 49 | '

एक UI तत्व से दूसरे में जाने के लिए उपयुक्त ऐरो कुंजी दबाएं।

\n' + 50 | '\n' + 51 | '

बाएं और दाएं ऐरो कुंजियां

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • मेन्यू बार में मेन्यू के बीच ले जाती हैं।
  • \n' + 55 | '
  • मेन्यू में एक सब-मेन्यू खोलें।
  • \n' + 56 | '
  • टूलबार समूह में बटनों के बीच ले जाएं।
  • \n' + 57 | '
  • फ़ुटर के तत्व पथ में आइटम के बीच ले जाएं।
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

नीचे और ऊपर ऐरो कुंजियां

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • मेन्यू में मेन्यू आइटम के बीच ले जाती हैं।
  • \n' + 64 | '
  • टूलबार पॉप-अप मेन्यू में आइटम के बीच ले जाएं।
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

फ़ोकस वाले UI सेक्शन के भीतर ऐरो कुंजियां चलाती रहती हैं।

\n' + 68 | '\n' + 69 | '

कोई खुला मेन्यू, कोई खुला सब-मेन्यू या कोई खुला पॉप-अप मेन्यू बंद करने के लिए Esc कुंजी दबाएं।

\n' + 70 | '\n' + 71 | "

अगर मौजूदा फ़ोकस किसी विशेष UI सेक्शन के 'शीर्ष' पर है, तो Esc कुंजी दबाने से भी\n" + 72 | ' कीबोर्ड नेविगेशन पूरी तरह से बाहर हो जाता है।

\n' + 73 | '\n' + 74 | '

मेन्यू आइटम या टूलबार बटन निष्पादित करें

\n' + 75 | '\n' + 76 | '

जब वांछित मेन्यू आइटम या टूलबार बटन हाइलाइट किया जाता है, तो आइटम को निष्पादित करने के लिए Return, Enter,\n' + 77 | ' या Space bar दबाएं।

\n' + 78 | '\n' + 79 | '

गैर-टैब वाले डायलॉग पर नेविगेट करें

\n' + 80 | '\n' + 81 | '

गैर-टैब वाले डायलॉग में, डायलॉग खुलने पर पहला इंटरैक्टिव घटक फ़ोकस लेता है।

\n' + 82 | '\n' + 83 | '

Tab or Shift+Tab दबाकर इंटरैक्टिव डायलॉग घटकों के बीच नेविगेट करें।

\n' + 84 | '\n' + 85 | '

टैब किए गए डायलॉग पर नेविगेट करें

\n' + 86 | '\n' + 87 | '

टैब किए गए डायलॉग में, डायलॉग खुलने पर टैब मेन्यू में पहला बटन फ़ोकस लेता है।

\n' + 88 | '\n' + 89 | '

इस डायलॉग टैब के इंटरैक्टिव घटकों के बीच नेविगेट करने के लिए Tab या\n' + 90 | ' Shift+Tab दबाएं।

\n' + 91 | '\n' + 92 | '

टैब मेन्यू को फ़ोकस देकर और फिर उपलब्ध टैब में के बीच जाने के लिए उपयुक्त ऐरो\n' + 93 | ' कुंजी दबाकर दूसरे डायलॉग टैब पर स्विच करें।

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/ja.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.ja', 2 | '

キーボード ナビゲーションの開始

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
メニュー バーをフォーカス
\n' + 6 | '
Windows または Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
ツール バーをフォーカス
\n' + 9 | '
Windows または Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
フッターをフォーカス
\n' + 12 | '
Windows または Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
通知にフォーカス
\n' + 15 | '
Windows または Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
コンテキスト ツール バーをフォーカス
\n' + 18 | '
Windows、Linux または macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

ナビゲーションは最初の UI 項目から開始され、強調表示されるか、フッターの要素パスにある最初の項目の場合は\n' + 22 | ' 下線が引かれます。

\n' + 23 | '\n' + 24 | '

UI セクション間の移動

\n' + 25 | '\n' + 26 | '

次の UI セクションに移動するには、Tab を押します。

\n' + 27 | '\n' + 28 | '

前の UI セクションに移動するには、Shift+Tab を押します。

\n' + 29 | '\n' + 30 | '

これらの UI セクションの Tab の順序:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. メニュー バー
  2. \n' + 34 | '
  3. 各ツール バー グループ
  4. \n' + 35 | '
  5. サイド バー
  6. \n' + 36 | '
  7. フッターの要素パス
  8. \n' + 37 | '
  9. フッターの単語数切り替えボタン
  10. \n' + 38 | '
  11. フッターのブランド リンク
  12. \n' + 39 | '
  13. フッターのエディター サイズ変更ハンドル
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

UI セクションが存在しない場合は、スキップされます。

\n' + 43 | '\n' + 44 | '

フッターにキーボード ナビゲーション フォーカスがあり、表示可能なサイド バーがない場合、Shift+Tab を押すと、\n' + 45 | ' フォーカスが最後ではなく最初のツール バー グループに移動します。

\n' + 46 | '\n' + 47 | '

UI セクション内の移動

\n' + 48 | '\n' + 49 | '

次の UI 要素に移動するには、適切な矢印キーを押します。

\n' + 50 | '\n' + 51 | '

左矢印右矢印のキー

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • メニュー バーのメニュー間で移動します。
  • \n' + 55 | '
  • メニュー内のサブメニューを開きます。
  • \n' + 56 | '
  • ツール バー グループのボタン間で移動します。
  • \n' + 57 | '
  • フッターの要素パスの項目間で移動します。
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

下矢印上矢印のキー

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • メニュー内のメニュー項目間で移動します。
  • \n' + 64 | '
  • ツール バー ポップアップ メニュー内のメニュー項目間で移動します。
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

矢印キーで、フォーカスされた UI セクション内で循環します。

\n' + 68 | '\n' + 69 | '

開いたメニュー、開いたサブメニュー、開いたポップアップ メニューを閉じるには、Esc キーを押します。

\n' + 70 | '\n' + 71 | '

現在のフォーカスが特定の UI セクションの「一番上」にある場合、Esc キーを押すと\n' + 72 | ' キーボード ナビゲーションも完全に閉じられます。

\n' + 73 | '\n' + 74 | '

メニュー項目またはツール バー ボタンの実行

\n' + 75 | '\n' + 76 | '

目的のメニュー項目やツール バー ボタンが強調表示されている場合、リターンEnter、\n' + 77 | ' またはスペース キーを押して項目を実行します。

\n' + 78 | '\n' + 79 | '

タブのないダイアログの移動

\n' + 80 | '\n' + 81 | '

タブのないダイアログでは、ダイアログが開くと最初の対話型コンポーネントがフォーカスされます。

\n' + 82 | '\n' + 83 | '

Tab または Shift+Tab を押して、対話型ダイアログ コンポーネント間で移動します。

\n' + 84 | '\n' + 85 | '

タブ付きダイアログの移動

\n' + 86 | '\n' + 87 | '

タブ付きダイアログでは、ダイアログが開くとタブ メニューの最初のボタンがフォーカスされます。

\n' + 88 | '\n' + 89 | '

Tab または\n' + 90 | ' Shift+Tab を押して、このダイアログ タブの対話型コンポーネント間で移動します。

\n' + 91 | '\n' + 92 | '

タブ メニューをフォーカスしてから適切な矢印キーを押して表示可能なタブを循環して、\n' + 93 | ' 別のダイアログに切り替えます。

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/ko_KR.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.ko_KR', 2 | '

키보드 탐색 시작

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
메뉴 모음 포커스 표시
\n' + 6 | '
Windows 또는 Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
도구 모음 포커스 표시
\n' + 9 | '
Windows 또는 Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
푸터 포커스 표시
\n' + 12 | '
Windows 또는 Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
알림 포커스
\n' + 15 | '
Windows 또는 Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
컨텍스트 도구 모음에 포커스 표시
\n' + 18 | '
Windows, Linux 또는 macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

첫 번째 UI 항목에서 탐색이 시작되며, 이때 첫 번째 항목이 강조 표시되거나 푸터 요소 경로에 있는\n' + 22 | ' 경우 밑줄 표시됩니다.

\n' + 23 | '\n' + 24 | '

UI 섹션 간 탐색

\n' + 25 | '\n' + 26 | '

한 UI 섹션에서 다음 UI 섹션으로 이동하려면 Tab(탭)을 누릅니다.

\n' + 27 | '\n' + 28 | '

한 UI 섹션에서 이전 UI 섹션으로 돌아가려면 Shift+Tab(시프트+탭)을 누릅니다.

\n' + 29 | '\n' + 30 | '

이 UI 섹션의 Tab(탭) 순서는 다음과 같습니다.

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. 메뉴 바
  2. \n' + 34 | '
  3. 각 도구 모음 그룹
  4. \n' + 35 | '
  5. 사이드바
  6. \n' + 36 | '
  7. 푸터의 요소 경로
  8. \n' + 37 | '
  9. 푸터의 단어 수 토글 버튼
  10. \n' + 38 | '
  11. 푸터의 브랜딩 링크
  12. \n' + 39 | '
  13. 푸터의 에디터 크기 변경 핸들
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

UI 섹션이 없는 경우 건너뛰기합니다.

\n' + 43 | '\n' + 44 | '

푸터에 키보드 탐색 포커스가 있고 사이드바는 보이지 않는 경우 Shift+Tab(시프트+탭)을 누르면\n' + 45 | ' 포커스 표시가 마지막이 아닌 첫 번째 도구 모음 그룹으로 이동합니다.

\n' + 46 | '\n' + 47 | '

UI 섹션 내 탐색

\n' + 48 | '\n' + 49 | '

한 UI 요소에서 다음 UI 요소로 이동하려면 적절한 화살표 키를 누릅니다.

\n' + 50 | '\n' + 51 | '

왼쪽오른쪽 화살표 키의 용도:

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • 메뉴 모음에서 메뉴 항목 사이를 이동합니다.
  • \n' + 55 | '
  • 메뉴에서 하위 메뉴를 엽니다.
  • \n' + 56 | '
  • 도구 모음 그룹에서 버튼 사이를 이동합니다.
  • \n' + 57 | '
  • 푸터의 요소 경로에서 항목 간에 이동합니다.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

아래 화살표 키의 용도:

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • 메뉴에서 메뉴 항목 사이를 이동합니다.
  • \n' + 64 | '
  • 도구 모음 팝업 메뉴에서 메뉴 항목 사이를 이동합니다.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

화살표 키는 포커스 표시 UI 섹션 내에서 순환됩니다.

\n' + 68 | '\n' + 69 | '

열려 있는 메뉴, 열려 있는 하위 메뉴 또는 열려 있는 팝업 메뉴를 닫으려면 Esc 키를 누릅니다.

\n' + 70 | '\n' + 71 | "

현재 포커스 표시가 특정 UI 섹션 '상단'에 있는 경우 이때도 Esc 키를 누르면\n" + 72 | ' 키보드 탐색이 완전히 종료됩니다.

\n' + 73 | '\n' + 74 | '

메뉴 항목 또는 도구 모음 버튼 실행

\n' + 75 | '\n' + 76 | '

원하는 메뉴 항목 또는 도구 모음 버튼이 강조 표시되어 있을 때 Return(리턴), Enter(엔터),\n' + 77 | ' 또는 Space bar(스페이스바)를 눌러 해당 항목을 실행합니다.

\n' + 78 | '\n' + 79 | '

탭이 없는 대화 탐색

\n' + 80 | '\n' + 81 | '

탭이 없는 대화의 경우, 첫 번째 대화형 요소가 포커스 표시된 상태로 대화가 열립니다.

\n' + 82 | '\n' + 83 | '

대화형 요소들 사이를 이동할 때는 Tab(탭) 또는 Shift+Tab(시프트+탭)을 누릅니다.

\n' + 84 | '\n' + 85 | '

탭이 있는 대화 탐색

\n' + 86 | '\n' + 87 | '

탭이 있는 대화의 경우, 탭 메뉴에서 첫 번째 버튼이 포커스 표시된 상태로 대화가 열립니다.

\n' + 88 | '\n' + 89 | '

이 대화 탭의 대화형 요소들 사이를 이동할 때는 Tab(탭) 또는\n' + 90 | ' Shift+Tab(시프트+탭)을 누릅니다.

\n' + 91 | '\n' + 92 | '

다른 대화 탭으로 이동하려면 탭 메뉴를 포커스 표시한 다음 적절한 화살표\n' + 93 | ' 키를 눌러 사용 가능한 탭들을 지나 원하는 탭으로 이동합니다.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/ms.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.ms', 2 | '

Mulakan navigasi papan kekunci

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
Fokus bar Menu
\n' + 6 | '
Windows atau Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
Fokus Bar Alat
\n' + 9 | '
Windows atau Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
Fokus pengaki
\n' + 12 | '
Windows atau Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
Tumpu kepada pemberitahuan
\n' + 15 | '
Windows atau Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
Fokus bar alat kontekstual
\n' + 18 | '
Windows, Linux atau macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

Navigasi akan bermula pada item UI pertama, yang akan diserlahkan atau digaris bawah dalam saiz item pertama dalam\n' + 22 | ' laluan elemen Pengaki.

\n' + 23 | '\n' + 24 | '

Navigasi antara bahagian UI

\n' + 25 | '\n' + 26 | '

Untuk bergerak dari satu bahagian UI ke yang seterusnya, tekan Tab.

\n' + 27 | '\n' + 28 | '

Untuk bergerak dari satu bahagian UI ke yang sebelumnya, tekan Shift+Tab.

\n' + 29 | '\n' + 30 | '

Tertib Tab bahagian UI ini ialah:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. Bar menu
  2. \n' + 34 | '
  3. Setiap kumpulan bar alat
  4. \n' + 35 | '
  5. Bar sisi
  6. \n' + 36 | '
  7. Laluan elemen dalam pengaki
  8. \n' + 37 | '
  9. Butang togol kiraan perkataan dalam pengaki
  10. \n' + 38 | '
  11. Pautan penjenamaan dalam pengaki
  12. \n' + 39 | '
  13. Pemegang saiz semula editor dalam pengaki
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

Jika bahagian UI tidak wujud, ia dilangkau.

\n' + 43 | '\n' + 44 | '

Jika pengaki mempunyai fokus navigasi papan kekunci dan tiada bar sisi kelihatan, menekan Shift+Tab\n' + 45 | ' akan mengalihkan fokus ke kumpulan bar alat pertama, bukannya yang terakhir.

\n' + 46 | '\n' + 47 | '

Navigasi dalam bahagian UI

\n' + 48 | '\n' + 49 | '

Untuk bergerak dari satu elemen UI ke yang seterusnya, tekan kekunci Anak Panah yang bersesuaian.

\n' + 50 | '\n' + 51 | '

Kekunci anak panah Kiri dan Kanan

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • bergerak antara menu dalam bar menu.
  • \n' + 55 | '
  • membukan submenu dalam menu.
  • \n' + 56 | '
  • bergerak antara butang dalam kumpulan bar alat.
  • \n' + 57 | '
  • Laluan elemen dalam pengaki.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

Kekunci anak panah Bawah dan Atas

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • bergerak antara item menu dalam menu.
  • \n' + 64 | '
  • bergerak antara item dalam menu timbul bar alat.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

Kekunci Anak Panah berkitar dalam bahagian UI difokuskan.

\n' + 68 | '\n' + 69 | '

Untuk menutup menu buka, submenu terbuka atau menu timbul terbuka, tekan kekunci Esc.

\n' + 70 | '\n' + 71 | "

Jika fokus semasa berada di bahagian 'atas' bahagian UI tertentu, menekan kekunci Esc juga akan keluar daripada\n" + 72 | ' navigasi papan kekunci sepenuhnya.

\n' + 73 | '\n' + 74 | '

Laksanakan item menu atau butang bar alat

\n' + 75 | '\n' + 76 | '

Apabila item menu atau butang bar alat yang diinginkan diserlahkan, tekan Return, Enter,\n' + 77 | ' atau bar Space untuk melaksanakan item.

\n' + 78 | '\n' + 79 | '

Navigasi ke dialog tidak bertab

\n' + 80 | '\n' + 81 | '

Dalam dialog tidak bertab, komponen interaksi pertama difokuskan apabila dialog dibuka.

\n' + 82 | '\n' + 83 | '

Navigasi antara komponen dialog interaktif dengan menekan Tab atau Shift+Tab.

\n' + 84 | '\n' + 85 | '

Navigasi ke dialog bertab

\n' + 86 | '\n' + 87 | '

Dalam dialog bertab, butang pertama dalam menu tab difokuskan apabila dialog dibuka.

\n' + 88 | '\n' + 89 | '

Navigasi antara komponen interaktif tab dialog ini dengan menekan Tab atau\n' + 90 | ' Shift+Tab.

\n' + 91 | '\n' + 92 | '

Tukar kepada tab dialog lain dengan memfokuskan menu tab, kemudian menekan kekunci Anak Panah yang bersesuaian\n' + 93 | ' untuk berkitar menerusi tab yang tersedia.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/sv_SE.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.sv_SE', 2 | '

Påbörja tangentbordsnavigering

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
Fokusera på menyraden
\n' + 6 | '
Windows eller Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
Fokusera på verktygsraden
\n' + 9 | '
Windows eller Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
Fokusera på verktygsraden
\n' + 12 | '
Windows eller Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
Fokusera aviseringen
\n' + 15 | '
Windows eller Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
Fokusera på en snabbverktygsrad
\n' + 18 | '
Windows, Linux eller macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

Navigeringen börjar vid det första gränssnittsobjektet, vilket är markerat eller understruket om det gäller det första objektet i\n' + 22 | ' sidfotens elementsökväg.

\n' + 23 | '\n' + 24 | '

Navigera mellan UI-avsnitt

\n' + 25 | '\n' + 26 | '

Flytta från ett UI-avsnitt till nästa genom att trycka på Tabb.

\n' + 27 | '\n' + 28 | '

Flytta från ett UI-avsnitt till det föregående genom att trycka på Skift+Tabb.

\n' + 29 | '\n' + 30 | '

Tabb-ordningen för dessa UI-avsnitt är:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. Menyrad
  2. \n' + 34 | '
  3. Varje verktygsradsgrupp
  4. \n' + 35 | '
  5. Sidoruta
  6. \n' + 36 | '
  7. Elementsökväg i sidfoten
  8. \n' + 37 | '
  9. Växlingsknapp för ordantal i sidfoten
  10. \n' + 38 | '
  11. Varumärkeslänk i sidfoten
  12. \n' + 39 | '
  13. Storlekshandtag för redigeraren i sidfoten
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

Om ett UI-avsnitt inte finns hoppas det över.

\n' + 43 | '\n' + 44 | '

Om sidfoten har fokus på tangentbordsnavigering, och det inte finns någon synlig sidoruta, flyttas fokus till den första verktygsradsgruppen\n' + 45 | ' när du trycker på Skift+Tabb, inte till den sista.

\n' + 46 | '\n' + 47 | '

Navigera i UI-avsnitt

\n' + 48 | '\n' + 49 | '

Flytta från ett UI-element till nästa genom att trycka på motsvarande piltangent.

\n' + 50 | '\n' + 51 | '

Vänsterpil och högerpil

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • flytta mellan menyer på menyraden.
  • \n' + 55 | '
  • öppna en undermeny på en meny.
  • \n' + 56 | '
  • flytta mellan knappar i en verktygsradgrupp.
  • \n' + 57 | '
  • flytta mellan objekt i sidfotens elementsökväg.
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

Nedpil och uppil

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • flytta mellan menyalternativ på en meny.
  • \n' + 64 | '
  • flytta mellan alternativ på en popup-meny på verktygsraden.
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

Piltangenterna cirkulerar inom det fokuserade UI-avsnittet.

\n' + 68 | '\n' + 69 | '

Tryck på Esc-tangenten om du vill stänga en öppen meny, undermeny eller popup-meny.

\n' + 70 | '\n' + 71 | '

Om det aktuella fokuset är högst upp i ett UI-avsnitt avlutas även tangentbordsnavigeringen helt när\n' + 72 | ' du trycker på Esc-tangenten.

\n' + 73 | '\n' + 74 | '

Köra ett menyalternativ eller en verktygfältsknapp

\n' + 75 | '\n' + 76 | '

När menyalternativet eller verktygsradsknappen är markerad trycker du på Retur, Enter\n' + 77 | ' eller blanksteg för att köra alternativet.

\n' + 78 | '\n' + 79 | '

Navigera i dialogrutor utan flikar

\n' + 80 | '\n' + 81 | '

I dialogrutor utan flikar är den första interaktiva komponenten i fokus när dialogrutan öppnas.

\n' + 82 | '\n' + 83 | '

Navigera mellan interaktiva dialogkomponenter genom att trycka på Tabb eller Skift+Tabb.

\n' + 84 | '\n' + 85 | '

Navigera i dialogrutor med flikar

\n' + 86 | '\n' + 87 | '

I dialogrutor utan flikar är den första knappen på flikmenyn i fokus när dialogrutan öppnas.

\n' + 88 | '\n' + 89 | '

Navigera mellan interaktiva komponenter på dialogrutefliken genom att trycka på Tabb eller\n' + 90 | ' Skift+Tabb.

\n' + 91 | '\n' + 92 | '

Växla till en annan dialogruta genom att fokusera på flikmenyn och sedan trycka på motsvarande piltangent\n' + 93 | ' för att cirkulera mellan de tillgängliga flikarna.

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/th_TH.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.th_TH', 2 | '

เริ่มต้นการนำทางด้วยแป้นพิมพ์

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
โฟกัสที่แถบเมนู
\n' + 6 | '
Windows หรือ Linux: Alt+F9
\n' + 7 | '
macOS: ⌥F9
\n' + 8 | '
โฟกัสที่แถบเครื่องมือ
\n' + 9 | '
Windows หรือ Linux: Alt+F10
\n' + 10 | '
macOS: ⌥F10
\n' + 11 | '
โฟกัสที่ส่วนท้าย
\n' + 12 | '
Windows หรือ Linux: Alt+F11
\n' + 13 | '
macOS: ⌥F11
\n' + 14 | '
โฟกัสไปที่การแจ้งเตือน
\n' + 15 | '
Windows หรือ Linux: Alt+F12
\n' + 16 | '
macOS: ⌥F12
\n' + 17 | '
โฟกัสที่แถบเครื่องมือตามบริบท
\n' + 18 | '
Windows, Linux หรือ macOS: Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

การนำทางจะเริ่มที่รายการ UI แรก ซึ่งจะมีการไฮไลต์หรือขีดเส้นใต้ไว้ในกรณีที่รายการแรกอยู่ใน\n' + 22 | ' พาธองค์ประกอบส่วนท้าย

\n' + 23 | '\n' + 24 | '

การนำทางระหว่างส่วนต่างๆ ของ UI

\n' + 25 | '\n' + 26 | '

ในการย้ายจากส่วน UI หนึ่งไปยังส่วนถัดไป ให้กด Tab

\n' + 27 | '\n' + 28 | '

ในการย้ายจากส่วน UI หนึ่งไปยังส่วนก่อนหน้า ให้กด Shift+Tab

\n' + 29 | '\n' + 30 | '

ลำดับแท็บของส่วนต่างๆ ของ UI คือ:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. แถบเมนู
  2. \n' + 34 | '
  3. แต่ละกลุ่มแถบเครื่องมือ
  4. \n' + 35 | '
  5. แถบข้าง
  6. \n' + 36 | '
  7. พาธองค์ประกอบในส่วนท้าย
  8. \n' + 37 | '
  9. ปุ่มสลับเปิด/ปิดจำนวนคำในส่วนท้าย
  10. \n' + 38 | '
  11. ลิงก์ชื่อแบรนด์ในส่วนท้าย
  12. \n' + 39 | '
  13. จุดจับปรับขนาดของตัวแก้ไขในส่วนท้าย
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

หากส่วน UI ไม่ปรากฏ แสดงว่าถูกข้ามไป

\n' + 43 | '\n' + 44 | '

หากส่วนท้ายมีการโฟกัสการนำทางแป้นพิมพ์และไม่มีแถบข้างปรากฏ การกด Shift+Tab\n' + 45 | ' จะย้ายการโฟกัสไปที่กลุ่มแถบเครื่องมือแรก ไม่ใช่สุดท้าย

\n' + 46 | '\n' + 47 | '

การนำทางภายในส่วนต่างๆ ของ UI

\n' + 48 | '\n' + 49 | '

ในการย้ายจากองค์ประกอบ UI หนึ่งไปยังองค์ประกอบส่วนถัดไป ให้กดปุ่มลูกศรที่เหมาะสม

\n' + 50 | '\n' + 51 | '

ปุ่มลูกศรซ้ายและขวา

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • ย้ายไปมาระหว่างเมนูต่างๆ ในแถบเมนู
  • \n' + 55 | '
  • เปิดเมนูย่อยในเมนู
  • \n' + 56 | '
  • ย้ายไปมาระหว่างปุ่มต่างๆ ในกลุ่มแถบเครื่องมือ
  • \n' + 57 | '
  • ย้ายไปมาระหว่างรายการต่างๆ ในพาธองค์ประกอบของส่วนท้าย
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

ปุ่มลูกศรลงและขึ้น

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • ย้ายไปมาระหว่างรายการเมนูต่างๆ ในเมนู
  • \n' + 64 | '
  • ย้ายไปมาระหว่างรายการต่างๆ ในเมนูป๊อบอัพแถบเครื่องมือ
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

ปุ่มลูกศรจะเลื่อนไปมาภายในส่วน UI ที่โฟกัส

\n' + 68 | '\n' + 69 | '

ในการปิดเมนูที่เปิดอยู่ เมนูย่อยที่เปิดอยู่ หรือเมนูป๊อบอัพที่เปิดอยู่ ให้กดปุ่ม Esc

\n' + 70 | '\n' + 71 | '

หากโฟกัสปัจจุบันอยู่ที่ ‘ด้านบนสุด’ ของส่วน UI เฉพาะ การกดปุ่ม Esc จะทำให้ออกจาก\n' + 72 | ' การนำทางด้วยแป้นพิมพ์ทั้งหมดเช่นกัน

\n' + 73 | '\n' + 74 | '

การดำเนินการรายการเมนูหรือปุ่มในแถบเครื่องมือ

\n' + 75 | '\n' + 76 | '

เมื่อไฮไลต์รายการเมนูหรือปุ่มในแถบเครื่องมือที่ต้องการ ให้กด Return, Enter\n' + 77 | ' หรือ Space bar เพื่อดำเนินการรายการดังกล่าว

\n' + 78 | '\n' + 79 | '

การนำทางสำหรับกล่องโต้ตอบที่ไม่อยู่ในแท็บ

\n' + 80 | '\n' + 81 | '

ในกล่องโต้ตอบที่ไม่อยู่ในแท็บ จะโฟกัสที่ส่วนประกอบเชิงโต้ตอบแรกเมื่อกล่องโต้ตอบเปิด

\n' + 82 | '\n' + 83 | '

นำทางระหว่างส่วนประกอบเชิงโต้ตอบต่างๆ ของกล่องโต้ตอบ โดยการกด Tab หรือ Shift+Tab

\n' + 84 | '\n' + 85 | '

การนำทางสำหรับกล่องโต้ตอบที่อยู่ในแท็บ

\n' + 86 | '\n' + 87 | '

ในกล่องโต้ตอบที่อยู่ในแท็บ จะโฟกัสที่ปุ่มแรกในเมนูแท็บเมื่อกล่องโต้ตอบเปิด

\n' + 88 | '\n' + 89 | '

นำทางระหว่างส่วนประกอบเชิงโต้ตอบต่างๆ ของแท็บกล่องโต้ตอบนี้โดยการกด Tab หรือ\n' + 90 | ' Shift+Tab

\n' + 91 | '\n' + 92 | '

สลับไปยังแท็บกล่องโต้ตอบอื่นโดยการเลือกโฟกัสที่เมนูแท็บ แล้วกดปุ่มลูกศรที่เหมาะสม\n' + 93 | ' เพื่อเลือกแท็บที่ใช้ได้

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/zh_CN.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.zh_CN', 2 | '

开始键盘导航

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
使菜单栏处于焦点
\n' + 6 | '
Windows 或 Linux:Alt+F9
\n' + 7 | '
macOS:⌥F9
\n' + 8 | '
使工具栏处于焦点
\n' + 9 | '
Windows 或 Linux:Alt+F10
\n' + 10 | '
macOS:⌥F10
\n' + 11 | '
使页脚处于焦点
\n' + 12 | '
Windows 或 Linux:Alt+F11
\n' + 13 | '
macOS:⌥F11
\n' + 14 | '
使通知处于焦点
\n' + 15 | '
Windows 或 Linux:Alt+F12
\n' + 16 | '
macOS:⌥F12
\n' + 17 | '
使上下文工具栏处于焦点
\n' + 18 | '
Windows、Linux 或 macOS:Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

导航将在第一个 UI 项上开始,其中突出显示该项,或者对于页脚元素路径中的第一项,将为其添加下划线。

\n' + 22 | '\n' + 23 | '

在 UI 部分之间导航

\n' + 24 | '\n' + 25 | '

要从一个 UI 部分移至下一个,请按 Tab

\n' + 26 | '\n' + 27 | '

要从一个 UI 部分移至上一个,请按 Shift+Tab

\n' + 28 | '\n' + 29 | '

这些 UI 部分的 Tab 顺序为:

\n' + 30 | '\n' + 31 | '
    \n' + 32 | '
  1. 菜单栏
  2. \n' + 33 | '
  3. 每个工具栏组
  4. \n' + 34 | '
  5. 边栏
  6. \n' + 35 | '
  7. 页脚中的元素路径
  8. \n' + 36 | '
  9. 页脚中的字数切换按钮
  10. \n' + 37 | '
  11. 页脚中的品牌链接
  12. \n' + 38 | '
  13. 页脚中的编辑器调整大小图柄
  14. \n' + 39 | '
\n' + 40 | '\n' + 41 | '

如果不存在某个 UI 部分,则跳过它。

\n' + 42 | '\n' + 43 | '

如果键盘导航焦点在页脚,并且没有可见的边栏,则按 Shift+Tab 将焦点移至第一个工具栏组而非最后一个。

\n' + 44 | '\n' + 45 | '

在 UI 部分内导航

\n' + 46 | '\n' + 47 | '

要从一个 UI 元素移至下一个,请按相应的箭头键。

\n' + 48 | '\n' + 49 | '

箭头键

\n' + 50 | '\n' + 51 | '
    \n' + 52 | '
  • 在菜单栏中的菜单之间移动。
  • \n' + 53 | '
  • 打开菜单中的子菜单。
  • \n' + 54 | '
  • 在工具栏组中的按钮之间移动。
  • \n' + 55 | '
  • 在页脚的元素路径中的各项之间移动。
  • \n' + 56 | '
\n' + 57 | '\n' + 58 | '

箭头键

\n' + 59 | '\n' + 60 | '
    \n' + 61 | '
  • 在菜单中的菜单项之间移动。
  • \n' + 62 | '
  • 在工具栏弹出菜单中的各项之间移动。
  • \n' + 63 | '
\n' + 64 | '\n' + 65 | '

箭头键在具有焦点的 UI 部分内循环。

\n' + 66 | '\n' + 67 | '

要关闭打开的菜单、打开的子菜单或打开的弹出菜单,请按 Esc 键。

\n' + 68 | '\n' + 69 | '

如果当前的焦点在特定 UI 部分的“顶部”,则按 Esc 键还将完全退出键盘导航。

\n' + 70 | '\n' + 71 | '

执行菜单项或工具栏按钮

\n' + 72 | '\n' + 73 | '

当突出显示所需的菜单项或工具栏按钮时,按 ReturnEnter空格以执行该项。

\n' + 74 | '\n' + 75 | '

在非标签页式对话框中导航

\n' + 76 | '\n' + 77 | '

在非标签页式对话框中,当对话框打开时,第一个交互组件获得焦点。

\n' + 78 | '\n' + 79 | '

通过按 TabShift+Tab,在交互对话框组件之间导航。

\n' + 80 | '\n' + 81 | '

在标签页式对话框中导航

\n' + 82 | '\n' + 83 | '

在标签页式对话框中,当对话框打开时,标签页菜单中的第一个按钮获得焦点。

\n' + 84 | '\n' + 85 | '

通过按 TabShift+Tab,在此对话框的交互组件之间导航。

\n' + 86 | '\n' + 87 | '

通过将焦点移至另一对话框标签页的菜单,然后按相应的箭头键以在可用的标签页间循环,从而切换到该对话框标签页。

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/help/js/i18n/keynav/zh_TW.js: -------------------------------------------------------------------------------- 1 | tinymce.Resource.add('tinymce.html-i18n.help-keynav.zh_TW', 2 | '

開始鍵盤瀏覽

\n' + 3 | '\n' + 4 | '
\n' + 5 | '
跳至功能表列
\n' + 6 | '
Windows 或 Linux:Alt+F9
\n' + 7 | '
macOS:⌥F9
\n' + 8 | '
跳至工具列
\n' + 9 | '
Windows 或 Linux:Alt+F10
\n' + 10 | '
macOS:⌥F10
\n' + 11 | '
跳至頁尾
\n' + 12 | '
Windows 或 Linux:Alt+F11
\n' + 13 | '
macOS:⌥F11
\n' + 14 | '
跳至通知
\n' + 15 | '
Windows 或 Linux:Alt+F12
\n' + 16 | '
macOS:⌥F12
\n' + 17 | '
跳至關聯式工具列
\n' + 18 | '
Windows、Linux 或 macOS:Ctrl+F9
\n' + 19 | '
\n' + 20 | '\n' + 21 | '

瀏覽會從第一個 UI 項目開始,該項目會反白顯示,但如果是「頁尾」元素路徑的第一項,\n' + 22 | ' 則加底線。

\n' + 23 | '\n' + 24 | '

在 UI 區段之間瀏覽

\n' + 25 | '\n' + 26 | '

從 UI 區段移至下一個,請按 Tab

\n' + 27 | '\n' + 28 | '

從 UI 區段移回上一個,請按 Shift+Tab

\n' + 29 | '\n' + 30 | '

這些 UI 區段的 Tab 順序如下:

\n' + 31 | '\n' + 32 | '
    \n' + 33 | '
  1. 功能表列
  2. \n' + 34 | '
  3. 各個工具列群組
  4. \n' + 35 | '
  5. 側邊欄
  6. \n' + 36 | '
  7. 頁尾中的元素路徑
  8. \n' + 37 | '
  9. 頁尾中字數切換按鈕
  10. \n' + 38 | '
  11. 頁尾中的品牌連結
  12. \n' + 39 | '
  13. 頁尾中編輯器調整大小控點
  14. \n' + 40 | '
\n' + 41 | '\n' + 42 | '

如果 UI 區段未顯示,表示已略過該區段。

\n' + 43 | '\n' + 44 | '

如果鍵盤瀏覽跳至頁尾,但沒有顯示側邊欄,則按下 Shift+Tab\n' + 45 | ' 會跳至第一個工具列群組,而不是最後一個。

\n' + 46 | '\n' + 47 | '

在 UI 區段之內瀏覽

\n' + 48 | '\n' + 49 | '

在兩個 UI 元素之間移動,請按適當的方向鍵。

\n' + 50 | '\n' + 51 | '

向左向右方向鍵

\n' + 52 | '\n' + 53 | '
    \n' + 54 | '
  • 在功能表列中的功能表之間移動。
  • \n' + 55 | '
  • 開啟功能表中的子功能表。
  • \n' + 56 | '
  • 在工具列群組中的按鈕之間移動。
  • \n' + 57 | '
  • 在頁尾的元素路徑中項目之間移動。
  • \n' + 58 | '
\n' + 59 | '\n' + 60 | '

向下向上方向鍵

\n' + 61 | '\n' + 62 | '
    \n' + 63 | '
  • 在功能表中的功能表項目之間移動。
  • \n' + 64 | '
  • 在工具列快顯功能表中的項目之間移動。
  • \n' + 65 | '
\n' + 66 | '\n' + 67 | '

方向鍵會在所跳至 UI 區段之內循環。

\n' + 68 | '\n' + 69 | '

若要關閉已開啟的功能表、已開啟的子功能表,或已開啟的快顯功能表,請按 Esc 鍵。

\n' + 70 | '\n' + 71 | '

如果目前已跳至特定 UI 區段的「頂端」,則按 Esc 鍵也會結束\n' + 72 | ' 整個鍵盤瀏覽。

\n' + 73 | '\n' + 74 | '

執行功能表列項目或工具列按鈕

\n' + 75 | '\n' + 76 | '

當想要的功能表項目或工具列按鈕已反白顯示時,按 ReturnEnter、\n' + 77 | ' 或空白鍵即可執行該項目。

\n' + 78 | '\n' + 79 | '

瀏覽非索引標籤式對話方塊

\n' + 80 | '\n' + 81 | '

在非索引標籤式對話方塊中,開啟對話方塊時會跳至第一個互動元件。

\n' + 82 | '\n' + 83 | '

TabShift+Tab 即可在互動式對話方塊元件之間瀏覽。

\n' + 84 | '\n' + 85 | '

瀏覽索引標籤式對話方塊

\n' + 86 | '\n' + 87 | '

在索引標籤式對話方塊中,開啟對話方塊時會跳至索引標籤式功能表中的第一個按鈕。

\n' + 88 | '\n' + 89 | '

若要在此對話方塊的互動式元件之間瀏覽,請按 Tab 或\n' + 90 | ' Shift+Tab

\n' + 91 | '\n' + 92 | '

先跳至索引標籤式功能表,然後按適當的方向鍵,即可切換至另一個對話方塊索引標籤,\n' + 93 | ' 以循環瀏覽可用的索引標籤。

\n'); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/importcss/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),g=p("importcss_file_filter"),_=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),M=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s{const s=e.length,r=new Array(s);for(let o=0;oa.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=_(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/",c=e.editorManager.suffix;return t===o+"/content"+(e.inline?".inline":"")+`${c}.css`||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet&&e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(g(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),M(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/insertdatetime/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),n=t("insertdatetime_timeformat"),r=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let n;n=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const r=e.dom.getParent(e.selection.getStart(),"time");r?((e,t,a,n)=>{const r=e.dom.create("time",{datetime:a},n);e.dom.replace(r,t),e.selection.select(r,!0),e.selection.collapse(!1)})(e,r,n,a):e.insertContent('")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");const g=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,n)=>{u(e,null!=n?n:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:n(e))}))})(e),(e=>{const t=r(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=r(e);return t.length>0?t[0]:n(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)},onSetup:g(e)});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)}))),onSetup:g(e)})})(e)}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/nonbreaking/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,o=e("boolean"),a=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),s=t("nonbreaking_wrap"),r=(n,e)=>{let o="";for(let a=0;a{const o=s(n)||n.plugins.visualchars?`${r(" ",e)}`:r(" ",e);n.undoManager.transact((()=>n.insertContent(o)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");const u=n=>e=>{const o=()=>{e.setEnabled(n.selection.isEditable())};return n.on("NodeChange",o),o(),()=>{n.off("NodeChange",o)}};n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>o(n)?{value:n?3:0,valid:!0}:a(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e,onSetup:u(n)}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e,onSetup:u(n)})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(o=>{if(o.keyCode===l.TAB&&!o.isDefaultPrevented()){if(o.shiftKey)return;o.preventDefault(),o.stopImmediatePropagation(),c(n,e)}}))})(n)}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/pagebreak/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),n=t("pagebreak_separator"),o=t("pagebreak_split_block"),r="mce-pagebreak",s=e=>{const t=``;return e?`

${t}

`:t},c=e=>a=>{const t=()=>{a.setEnabled(e.selection.isEditable())};return e.on("NodeChange",t),t(),()=>{e.off("NodeChange",t)}};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(o(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a,onSetup:c(e)}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a,onSetup:c(e)})})(e),(e=>{const a=n(e),t=()=>o(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(n=>{let o,s,c=n.length;for(;c--;)if(o=n[c],s=o.attr("class"),s&&-1!==s.indexOf(r)){const n=o.parent;if(n&&e.schema.getBlockElements()[n.name]&&t()){n.type=3,n.value=a,n.raw=!0,o.remove();continue}o.type=3,o.value=a,o.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,r)&&(a.name="pagebreak")}))})(e)}))}(); -------------------------------------------------------------------------------- /public/static/tinymce/plugins/preview/plugin.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TinyMCE version 7.3.0 (2024-08-07) 3 | */ 4 | !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='"})),d&&(l+='");const y=r(e),u=c(e),v=' 20 | 21 | 32 | -------------------------------------------------------------------------------- /src/api/article.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | addArticle: (data: object) => { 5 | return request({ 6 | url: '/article/article/add', 7 | method: 'post', 8 | data 9 | }) 10 | }, 11 | editArticle: (data: object) => { 12 | return request({ 13 | url: '/article/article/edit', 14 | method: 'post', 15 | data 16 | }) 17 | }, 18 | deleteArticle: (data: object) => { 19 | return request({ 20 | url: '/article/article/delete', 21 | method: 'post', 22 | data 23 | }) 24 | }, 25 | getArticleList: (data: object) => { 26 | return request({ 27 | url: '/article/article/list', 28 | method: 'post', 29 | data 30 | }) 31 | }, 32 | 33 | addCategory: (data: object) => { 34 | return request({ 35 | url: '/article/category/add', 36 | method: 'post', 37 | data 38 | }) 39 | }, 40 | editCategory: (data: object) => { 41 | return request({ 42 | url: '/article/category/edit', 43 | method: 'post', 44 | data 45 | }) 46 | }, 47 | deleteCategory: (data: object) => { 48 | return request({ 49 | url: '/article/category/delete', 50 | method: 'post', 51 | data 52 | }) 53 | }, 54 | 55 | getCategoryList: (data: object) => { 56 | return request({ 57 | url: '/article/category/list', 58 | method: 'post', 59 | data 60 | }) 61 | }, 62 | uploadImg: (data: object) => { 63 | return request({ 64 | url: '/article/article/upload', 65 | method: 'post', 66 | data 67 | }) 68 | }, 69 | }) -------------------------------------------------------------------------------- /src/api/express.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | addCompany: (data: object) => { 5 | return request({ 6 | url: '/express/company/add', 7 | method: 'post', 8 | data 9 | }) 10 | }, 11 | editCompany: (data: object) => { 12 | return request({ 13 | url: '/express/company/edit', 14 | method: 'post', 15 | data 16 | }) 17 | }, 18 | deleteCompany: (data: object) => { 19 | return request({ 20 | url: '/express/company/delete', 21 | method: 'post', 22 | data 23 | }) 24 | }, 25 | getCompanyList: (data: object) => { 26 | return request({ 27 | url: '/express/company/list', 28 | method: 'post', 29 | data 30 | }) 31 | }, 32 | editFreeRule: (data: object) => { 33 | return request({ 34 | url: '/express/freeRule/edit', 35 | method: 'post', 36 | data 37 | }) 38 | }, 39 | getFreeRule: () => { 40 | return request({ 41 | url: '/express/freeRule/get', 42 | method: 'post' 43 | }) 44 | }, 45 | editFeeRule: (data: object) => { 46 | return request({ 47 | url: '/express/feeRule/edit', 48 | method: 'post', 49 | data 50 | }) 51 | }, 52 | getFeeRule: () => { 53 | return request({ 54 | url: '/express/feeRule/get', 55 | method: 'post' 56 | }) 57 | }, 58 | }) -------------------------------------------------------------------------------- /src/api/goods.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | addBrand: (data: object) => { 5 | return request({ 6 | url: '/goods/brand/add', 7 | method: 'post', 8 | data 9 | }) 10 | }, 11 | editBrand: (data: object) => { 12 | return request({ 13 | url: '/goods/brand/edit', 14 | method: 'post', 15 | data 16 | }) 17 | }, 18 | deleteBrand: (data: object) => { 19 | return request({ 20 | url: '/goods/brand/delete', 21 | method: 'post', 22 | data 23 | }) 24 | }, 25 | getBrandList: (data: object) => { 26 | return request({ 27 | url: '/goods/brand/list', 28 | method: 'post', 29 | data 30 | }) 31 | }, 32 | 33 | addCategory: (data: object) => { 34 | return request({ 35 | url: '/goods/category/add', 36 | method: 'post', 37 | data 38 | }) 39 | }, 40 | editCategory: (data: object) => { 41 | return request({ 42 | url: '/goods/category/edit', 43 | method: 'post', 44 | data 45 | }) 46 | }, 47 | deleteCategory: (data: object) => { 48 | return request({ 49 | url: '/goods/category/delete', 50 | method: 'post', 51 | data 52 | }) 53 | }, 54 | 55 | getCategoryList: (data: object) => { 56 | return request({ 57 | url: '/goods/category/list', 58 | method: 'post', 59 | data 60 | }) 61 | }, 62 | 63 | 64 | addGoods: (data: object) => { 65 | return request({ 66 | url: '/goods/goods/add', 67 | method: 'post', 68 | data 69 | }) 70 | }, 71 | editGoods: (data: object) => { 72 | return request({ 73 | url: '/goods/goods/edit', 74 | method: 'post', 75 | data 76 | }) 77 | }, 78 | deleteGoods: (data: object) => { 79 | return request({ 80 | url: '/goods/goods/delete', 81 | method: 'post', 82 | data 83 | }) 84 | }, 85 | getGoods: (data: object) => { 86 | return request({ 87 | url: '/goods/goods/get', 88 | method: 'post', 89 | data 90 | }) 91 | }, 92 | getGoodsList: (data: object) => { 93 | return request({ 94 | url: '/goods/goods/list', 95 | method: 'post', 96 | data 97 | }) 98 | }, 99 | 100 | uploadGoodsImg: (data: object) => { 101 | return request({ 102 | url: '/goods/goods/upload', 103 | method: 'post', 104 | data 105 | }) 106 | }, 107 | 108 | addSpec: (data: object) => { 109 | return request({ 110 | url: '/goods/spec/add', 111 | method: 'post', 112 | data 113 | }) 114 | }, 115 | editSpec: (data: object) => { 116 | return request({ 117 | url: '/goods/spec/edit', 118 | method: 'post', 119 | data 120 | }) 121 | }, 122 | deleteSpec: (data: object) => { 123 | return request({ 124 | url: '/goods/spec/delete', 125 | method: 'post', 126 | data 127 | }) 128 | }, 129 | getSpecList: (data: object) => { 130 | return request({ 131 | url: '/goods/spec/list', 132 | method: 'post', 133 | data 134 | }) 135 | }, 136 | editTemplate: (data: object) => { 137 | return request({ 138 | url: '/goods/template/edit', 139 | method: 'post', 140 | data 141 | }) 142 | }, 143 | getTemplate: () => { 144 | return request({ 145 | url: '/goods/template/get', 146 | method: 'post' 147 | }) 148 | }, 149 | uploadTemplateImg: (data: object) => { 150 | return request({ 151 | url: '/goods/template/upload', 152 | method: 'post', 153 | data 154 | }) 155 | }, 156 | 157 | }) -------------------------------------------------------------------------------- /src/api/main.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | const mainApi = { 4 | /** get RSA public key */ 5 | getRsaPubKey: () => { 6 | return request({ 7 | url: '/main/rsaPubKey', 8 | method: 'post' 9 | }) 10 | }, 11 | 12 | /** 登录api */ 13 | login(data: object) { 14 | return request({ 15 | url: '/main/login', 16 | method: 'post', 17 | data 18 | }) 19 | }, 20 | 21 | /** 退出登录Api */ 22 | logout: () => { 23 | return request({ 24 | url: '/main/logout', 25 | method: 'post' 26 | }) 27 | }, 28 | 29 | /** get user info */ 30 | getInfo: () => { 31 | return request({ 32 | url: '/main/info', 33 | method: 'post' 34 | }) 35 | }, 36 | 37 | } 38 | export default mainApi -------------------------------------------------------------------------------- /src/api/order.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | addOrder: (data: object) => { 5 | return request({ 6 | url: '/order/order/add', 7 | method: 'post', 8 | data 9 | }) 10 | }, 11 | editOrder: (data: object) => { 12 | return request({ 13 | url: '/order/order/edit', 14 | method: 'post', 15 | data 16 | }) 17 | }, 18 | deleteOrder: (data: object) => { 19 | return request({ 20 | url: '/order/order/delete', 21 | method: 'post', 22 | data 23 | }) 24 | }, 25 | getOrder: (data: object) => { 26 | return request({ 27 | url: '/order/order/get', 28 | method: 'post', 29 | data 30 | }) 31 | }, 32 | getOrderList: (data: object) => { 33 | return request({ 34 | url: '/order/order/list', 35 | method: 'post', 36 | data 37 | }) 38 | }, 39 | orderCancelOrder: (data: object) => { 40 | return request({ 41 | url: '/order/order/cancelOrder', 42 | method: 'post', 43 | data 44 | }) 45 | }, 46 | orderCancelShip: (data: object) => { 47 | return request({ 48 | url: '/order/order/cancelShip', 49 | method: 'post', 50 | data 51 | }) 52 | }, 53 | orderConfirm: (data: object) => { 54 | return request({ 55 | url: '/order/order/confirm', 56 | method: 'post', 57 | data 58 | }) 59 | }, 60 | 61 | orderPay: (data: object) => { 62 | return request({ 63 | url: '/order/order/pay', 64 | method: 'post', 65 | data 66 | }) 67 | }, 68 | orderRefund: (data: object) => { 69 | return request({ 70 | url: '/order/order/refund', 71 | method: 'post', 72 | data 73 | }) 74 | }, 75 | orderShip: (data: object) => { 76 | return request({ 77 | url: '/order/order/ship', 78 | method: 'post', 79 | data 80 | }) 81 | }, 82 | 83 | 84 | }) -------------------------------------------------------------------------------- /src/api/other.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | editCarousel: (data: object) => { 5 | return request({ 6 | url: '/other/carousel/edit', 7 | method: 'post', 8 | data 9 | }) 10 | }, 11 | getCarousel: () => { 12 | return request({ 13 | url: '/other/carousel/get', 14 | method: 'post' 15 | }) 16 | }, 17 | editStaticRes: (data: object) => { 18 | return request({ 19 | url: '/other/staticRes/edit', 20 | method: 'post', 21 | data 22 | }) 23 | }, 24 | getStaticRes: () => { 25 | return request({ 26 | url: '/other/staticRes/get', 27 | method: 'post' 28 | }) 29 | }, 30 | }) -------------------------------------------------------------------------------- /src/api/system.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | 5 | getConfig: () => { 6 | return request({ 7 | url: '/system/config', 8 | method: 'post' 9 | }) 10 | }, 11 | 12 | editConfig: (data: object) => { 13 | return request({ 14 | url: '/system/config/edit', 15 | method: 'post', 16 | data 17 | }) 18 | }, 19 | 20 | getSystemInfo: () => { 21 | return request({ 22 | url: '/system/info/get', 23 | method: 'post' 24 | }) 25 | }, 26 | 27 | getLogList: (data: object) => { 28 | return request({ 29 | url: '/system/log/list', 30 | method: 'post', 31 | data 32 | }) 33 | }, 34 | addManager: (data: object) => { 35 | return request({ 36 | url: '/system/manager/add', 37 | method: 'post', 38 | data 39 | }) 40 | }, 41 | 42 | deleteManager: (data: object) => { 43 | return request({ 44 | url: '/system/manager/delete', 45 | method: 'post', 46 | data 47 | }) 48 | }, 49 | 50 | editManager: (data: object) => { 51 | return request({ 52 | url: '/system/manager/edit', 53 | method: 'post', 54 | data 55 | }) 56 | }, 57 | 58 | getManagerList: (data: object) => { 59 | return request({ 60 | url: '/system/manager/list', 61 | method: 'post', 62 | data 63 | }) 64 | }, 65 | 66 | 67 | addMenu: (data: object) => { 68 | return request({ 69 | url: '/system/menu/add', 70 | method: 'post', 71 | data 72 | }) 73 | }, 74 | 75 | deleteMenu: (data: object) => { 76 | return request({ 77 | url: '/system/menu/delete', 78 | method: 'post', 79 | data 80 | }) 81 | }, 82 | 83 | editMenu: (data: object) => { 84 | return request({ 85 | url: '/system/menu/edit', 86 | method: 'post', 87 | data 88 | }) 89 | }, 90 | 91 | getMenuList: (data: object) => { 92 | return request({ 93 | url: '/system/menu/list', 94 | method: 'post', 95 | data 96 | }) 97 | }, 98 | 99 | getPaymentList: (data: object) => { 100 | return request({ 101 | url: '/system/payment/list', 102 | method: 'post', 103 | data 104 | }) 105 | }, 106 | getPayment: (data: object) => { 107 | return request({ 108 | url: '/system/payment/get', 109 | method: 'post', 110 | data 111 | }) 112 | }, 113 | editPayment: (data: object) => { 114 | return request({ 115 | url: '/system/payment/edit', 116 | method: 'post', 117 | data 118 | }) 119 | }, 120 | 121 | addRole: (data: object) => { 122 | return request({ 123 | url: '/system/role/add', 124 | method: 'post', 125 | data 126 | }) 127 | }, 128 | 129 | deleteRole: (data: object) => { 130 | return request({ 131 | url: '/system/role/delete', 132 | method: 'post', 133 | data 134 | }) 135 | }, 136 | 137 | getRoleList: (data: object) => { 138 | return request({ 139 | url: '/system/role/list', 140 | method: 'post', 141 | data 142 | }) 143 | }, 144 | editRole: (data: object) => { 145 | return request({ 146 | url: '/system/role/edit', 147 | method: 'post', 148 | data 149 | }) 150 | }, 151 | 152 | 153 | }) 154 | -------------------------------------------------------------------------------- /src/api/user.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/system/request' 2 | 3 | export default ({ 4 | getBalanceLogList: (data: object) => { 5 | return request({ 6 | url: '/user/balanceLog/list', 7 | method: 'post', 8 | data 9 | }) 10 | }, 11 | 12 | changeBalance: (data: object) => { 13 | return request({ 14 | url: '/user/user/changeBalance', 15 | method: 'post', 16 | data 17 | }) 18 | }, 19 | changePassword: (data: object) => { 20 | return request({ 21 | url: '/user/user/changePassword', 22 | method: 'post', 23 | data 24 | }) 25 | }, 26 | 27 | getUser: (data: object) => { 28 | return request({ 29 | url: '/user/user/get', 30 | method: 'post', 31 | data 32 | }) 33 | }, 34 | 35 | getUserList: (data: object) => { 36 | return request({ 37 | url: '/user/user/list', 38 | method: 'post', 39 | data 40 | }) 41 | } 42 | }) -------------------------------------------------------------------------------- /src/assets/images/401.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/assets/images/401.gif -------------------------------------------------------------------------------- /src/assets/images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/assets/images/404.png -------------------------------------------------------------------------------- /src/assets/images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/assets/images/404_cloud.png -------------------------------------------------------------------------------- /src/assets/login/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/assets/login/bg.png -------------------------------------------------------------------------------- /src/assets/login/left.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/assets/login/left.jpg -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/style/common.scss: -------------------------------------------------------------------------------- 1 | @import './transition.scss'; 2 | @import '@/theme/index.scss'; 3 | 4 | .layout-container { 5 | background-color: var(--system-container-main-background); 6 | width: calc(100% - 30px); 7 | height: calc(100% - 30px); 8 | margin: 15px; 9 | display: flex; 10 | flex-direction: column; 11 | overflow-y: auto; 12 | 13 | &-form { 14 | display: flex; 15 | justify-content: space-between; 16 | padding: 15px 15px 0; 17 | 18 | &-handle { 19 | display: flex; 20 | justify-content: flex-start; 21 | 22 | .export-excel-btn { 23 | margin-left: 15px; 24 | } 25 | } 26 | 27 | &-search { 28 | display: flex; 29 | justify-content: flex-end; 30 | 31 | .search-btn { 32 | margin-left: 15px; 33 | } 34 | } 35 | 36 | .el-form-item { 37 | margin-bottom: 0; 38 | } 39 | } 40 | 41 | &-table { 42 | flex: 1; 43 | height: 100%; 44 | padding: 15px; 45 | overflow: auto; 46 | } 47 | } 48 | 49 | .flex-box { 50 | display: flex; 51 | flex-direction: column; 52 | width: 100%; 53 | height: 100%; 54 | padding: 15px; 55 | box-sizing: border-box; 56 | } 57 | 58 | .flex { 59 | display: flex; 60 | } 61 | 62 | .center { 63 | justify-content: center; 64 | align-items: center; 65 | text-align: center; 66 | } 67 | 68 | a { 69 | text-decoration: none; 70 | } 71 | 72 | /** element-plus **/ 73 | .el-icon { 74 | text-align: center; 75 | } 76 | 77 | /** 用于提示信息 **/ 78 | .my-tip { 79 | background-color: #f1f1f1; 80 | padding: 5px 10px; 81 | text-align: left; 82 | border-radius: 4px; 83 | } 84 | 85 | .system-scrollbar { 86 | &::-webkit-scrollbar { 87 | display: none; 88 | width: 6px; 89 | } 90 | 91 | &::-webkit-scrollbar-thumb { 92 | border-radius: 10px; 93 | background: rgba(144, 147, 153, 0.3); 94 | } 95 | 96 | &:hover { 97 | &::-webkit-scrollbar { 98 | display: block; 99 | } 100 | 101 | &::-webkit-scrollbar-thumb { 102 | border-radius: 10px; 103 | background: rgba(144, 147, 153, 0.3); 104 | 105 | &:hover { 106 | background: rgba(144, 147, 153, 0.5); 107 | } 108 | } 109 | } 110 | } 111 | 112 | .el-form--inline { 113 | .el-form-item { 114 | 115 | &>.el-input, 116 | .el-cascader, 117 | .el-select, 118 | .el-date-editor, 119 | .el-autocomplete { 120 | width: 196px; 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /src/assets/style/transition.scss: -------------------------------------------------------------------------------- 1 | /* fade-transform */ 2 | .fade-transform-leave-active, 3 | .fade-transform-enter-active { 4 | transition: all .2s; 5 | } 6 | 7 | .fade-transform-enter-from { 8 | opacity: 0; 9 | transform: translateX(-30px); 10 | transition: all .2s; 11 | } 12 | 13 | .fade-transform-leave-to { 14 | opacity: 0; 15 | transform: translateX(30px); 16 | transition: all .2s; 17 | } 18 | 19 | /* breadcrumb transition */ 20 | .breadcrumb-enter-active, 21 | .breadcrumb-leave-active { 22 | transition: all .2s; 23 | } 24 | 25 | .breadcrumb-enter, 26 | .breadcrumb-leave-active { 27 | opacity: 0; 28 | transform: translateX(80px); 29 | } 30 | 31 | .breadcrumb-move { 32 | transition: all .5s; 33 | } 34 | 35 | .breadcrumb-leave-active { 36 | position: absolute; 37 | } -------------------------------------------------------------------------------- /src/assets/svg/read.md: -------------------------------------------------------------------------------- 1 | 6 | 请在当前文件夹内放入svg文件,并删除当前文件 -------------------------------------------------------------------------------- /src/config/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2023-05-22 20:44:25 3 | * @Description: 4 | */ 5 | const systemTitle = '后台管理系统' // 系统名称,用于显示在左上角模块,登录模块、以及浏览器标题上使用,使用配置项 6 | const systemSubTitle = '时间不在于你拥有多少,而在于你怎样使用。' // 系统提示信息,用于登录模块使用 7 | 8 | export { 9 | systemTitle, 10 | systemSubTitle 11 | } -------------------------------------------------------------------------------- /src/layout/Header/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 39 | 40 | -------------------------------------------------------------------------------- /src/layout/Header/functionList/fullscreen.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | 26 | 36 | -------------------------------------------------------------------------------- /src/layout/Header/functionList/sizeChange.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 47 | 48 | -------------------------------------------------------------------------------- /src/layout/Header/functionList/theme/theme-color.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 48 | 49 | -------------------------------------------------------------------------------- /src/layout/Header/functionList/theme/theme-icon.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 70 | 71 | -------------------------------------------------------------------------------- /src/layout/Header/index.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 91 | 92 | -------------------------------------------------------------------------------- /src/layout/Header/passwordLayer.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 91 | 92 | -------------------------------------------------------------------------------- /src/layout/Logo/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | -------------------------------------------------------------------------------- /src/layout/Menu/Link.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 38 | -------------------------------------------------------------------------------- /src/layout/Menu/MenuItem.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 97 | 98 | -------------------------------------------------------------------------------- /src/layout/Menu/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 45 | 46 | -------------------------------------------------------------------------------- /src/layout/Tabs/item.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 54 | 55 | -------------------------------------------------------------------------------- /src/layout/index.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 77 | 78 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2022-05-22 20:44:25 3 | * @Description: 4 | */ 5 | import { createApp } from 'vue' 6 | import zhCn from 'element-plus/dist/locale/zh-cn.mjs' 7 | import ElementPlus from 'element-plus' 8 | import * as ElementPlusIconsVue from '@element-plus/icons-vue' 9 | import 'element-plus/theme-chalk/display.css' // 引入基于断点的隐藏类 10 | import 'element-plus/dist/index.css' 11 | import 'normalize.css' // css初始化 12 | import './assets/style/common.scss' // 公共css 13 | import './theme/modules/chinese/index.scss' 14 | import App from './App.vue' 15 | import stores from './stores' 16 | import router from './router' 17 | if (import.meta.env.MODE === 'development') { // 开发环境调用 18 | 19 | } 20 | 21 | const app = createApp(App) 22 | app.use(ElementPlus, { locale: zhCn }) 23 | app.use(router) 24 | app.use(stores) 25 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 26 | app.component(key, component) 27 | } 28 | // app.config.performance = true 29 | app.mount('#app') 30 | -------------------------------------------------------------------------------- /src/router/createNode.ts: -------------------------------------------------------------------------------- 1 | // 1. 用于解决keep-alive需要name的问题,动态生成随机name供keep-alive使用 2 | // 2. 用于解决transition动画内部结点只能为根元素的问题,单文件可写多结点 3 | import type { DefineComponent, Component } from 'vue' 4 | import { defineComponent, h, createVNode, ref, nextTick } from 'vue' 5 | import reload from './reload.vue' 6 | import NProgress from '@/utils/system/nprogress' 7 | 8 | export function createNameComponent(component: () => Promise): () => Promise> { 9 | return () => { 10 | return new Promise((resolve) => { 11 | component().then((comm: DefineComponent<{}, {}, any>) => { 12 | const name = (comm.default.name || 'vueAdminBox') + '$' + Date.now(); 13 | const tempComm = defineComponent({ 14 | name, 15 | setup() { 16 | const isReload = ref(false); 17 | let timeOut: any = null; 18 | const handleReload = () => { 19 | isReload.value = true; 20 | timeOut && clearTimeout(timeOut); 21 | NProgress.start(); 22 | timeOut = setTimeout(() => { 23 | nextTick(() => { 24 | NProgress.done(); 25 | isReload.value = false; 26 | }); 27 | }, 260); 28 | }; 29 | return { 30 | isReload, 31 | handleReload 32 | }; 33 | }, 34 | render: function () { 35 | if (this.isReload) { 36 | return h('div', { class: 'el-main-box' }, [h(reload)]); 37 | } else { 38 | return h('div', { class: 'el-main-box' }, [createVNode(comm.default)]); 39 | } 40 | } 41 | }); 42 | resolve(tempComm); 43 | }); 44 | }); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2023-01-25 09:51:12 3 | * @LastEditTime: 2023-01-25 12:25:51 4 | * @Description: 5 | */ 6 | /** 7 | * @description 所有人可使用的参数配置列表 8 | * @params hideMenu: 是否隐藏当前路由结点不在导航中展示 9 | * @params alwayShow: 只有一个子路由时是否总是展示菜单,默认false 10 | */ 11 | import { reactive } from 'vue' 12 | import { createRouter, createWebHashHistory, Router } from 'vue-router' 13 | import NProgress from '@/utils/system/nprogress' 14 | import { changeTitle } from '@/utils/system/title' 15 | import { useUserStore } from '@/stores/user' 16 | import { useAppStore } from '@/stores/app' 17 | import { RouteLocationNormalized } from 'vue-router' 18 | import mainApi from '@/api/main' 19 | 20 | 21 | NProgress.configure({ showSpinner: true }) 22 | 23 | // 引入不需要权限的modules 24 | import System from './modules/system' 25 | 26 | /** 27 | * @name 初始化必须要的路由 28 | * @description 使用reactive属性使得modules可以在路由菜单里面实时响应,搞定菜单回显的问题 29 | * @detail 针对modules的任何修改,均会同步至菜单级别,记住,是针对变量名为:moduels的修改 30 | **/ 31 | let modules = reactive([ 32 | ...System 33 | ]) 34 | 35 | const router: Router = createRouter({ 36 | history: createWebHashHistory(), 37 | routes: modules 38 | }) 39 | 40 | // installed route 41 | const installed: any[] = [] 42 | 43 | // clear router on logout 44 | export const clearRouter = () => { 45 | for (const removeRoute of installed) { 46 | removeRoute() 47 | } 48 | installed.length = 0 49 | modules = reactive([ 50 | ...System 51 | ]) 52 | needLoad = true 53 | } 54 | 55 | // 未授权时可访问的白名单 56 | const whiteList = ['/login'] 57 | 58 | // loaded status 59 | let needLoad: boolean = true 60 | 61 | // 路由跳转前的监听操作 62 | router.beforeEach(async (to, _from, next) => { 63 | const userStore = useUserStore() 64 | // load route 65 | if (needLoad) { 66 | const appStore = useAppStore() 67 | let result: any = await mainApi.getInfo() 68 | if (result.data.name && result.data.name.length > 1) { 69 | userStore.authorize = result.data.authorize 70 | userStore.menu = result.data.menu 71 | userStore.name = result.data.name 72 | userStore.superAdmin = result.data.superAdmin 73 | for (const item of userStore.getRoute()) { 74 | modules.push(item) 75 | installed.push(router.addRoute(item)) 76 | } 77 | needLoad = false 78 | // go to homepage after loaded 79 | if (['', '/', '/login'].includes(appStore.currentPath)) router.replace('/home') 80 | else router.replace(appStore.currentPath) 81 | } 82 | 83 | } 84 | 85 | NProgress.start() 86 | to.meta.title ? (changeTitle(to.meta.title)) : "" // 动态title 87 | if (userStore.name.length > 0) { 88 | next() 89 | } else if (whiteList.includes(to.path)) { 90 | next() 91 | } else { 92 | next("/login"); // 全部重定向到登录页 93 | } 94 | }); 95 | 96 | // 路由跳转后的监听操作 97 | router.afterEach((to: RouteLocationNormalized | any, _from) => { 98 | const userStore = useUserStore() 99 | const name = to.matched[to.matched.length - 1].components.default.name 100 | if (to.meta && to.meta.cache && name && !userStore.cachedComponents.includes(name)) { 101 | useUserStore().cachedComponents.push(name) 102 | } 103 | useAppStore().currentPath = to.fullPath 104 | NProgress.done() 105 | }); 106 | 107 | 108 | export { 109 | modules 110 | } 111 | 112 | export default router 113 | -------------------------------------------------------------------------------- /src/router/index.type.ts: -------------------------------------------------------------------------------- 1 | import type { DefineComponent } from 'vue' 2 | import type { RouteRecordRaw } from 'vue-router' 3 | 4 | /** @name 基础路由类型 */ 5 | export type Route = { 6 | /** @name 访问路径 */ 7 | path: string 8 | /** @name 需要使用的组件 @description 两种类型,第一种是默认的Vue文件类型,第二种是通过createNameComponent搞出来的,凡是一个组件需要keep-alive,必须使用createNameComponent来搞定 */ 9 | component: DefineComponent<{}, {}, any> | (() => Promise>) 10 | /** @name 基础元数据 */ 11 | meta: Meta 12 | 13 | /** @name 路由名称,全局唯一,可以不填 */ 14 | name?: string 15 | /** @name 需要重定向的地址,可选 */ 16 | redirect?: string 17 | /** @name 总是显示菜单,可选 @description 大部分时候针对二级三级四级菜单的根结点,不设置的话,子元素只有一个的时候默认显示子元素,隐藏父元素 @default false */ 18 | alwayShow?: boolean 19 | /** @name 是否隐藏菜单,可选 @description 这个属性通常用于详情页面、404、401页面等不需要显示在总菜单里面的 @default false */ 20 | hideMenu?: boolean 21 | /** @name 路由子集,和Route类型一致的数组,可选 */ 22 | children?: Route[] 23 | } & RouteRecordRaw 24 | 25 | /** @name 基础元数据的类型说明 */ 26 | export interface Meta { 27 | /** @name 标题 @description 可供很多地方使用,在国际化版本中使用i18n对应的值,非国际化版本中使用真实的路由值 */ 28 | title: string 29 | /** @name 使用的icon的值,可选 @description 对应自己Iconfont链接库进来,通常只在一级菜单使用,但二级三级使用也没问题 */ 30 | icon?: string 31 | /** @name 是否需要缓存页面,目前仅支持二级菜单缓存,多级菜单缓存会在未来支持,可选 @default false */ 32 | cache?: boolean 33 | /** @name 是否隐藏标签页,可选 @default false */ 34 | hideTabs?: boolean 35 | /** @name 左侧菜单强制聚焦时的路由,比如新增、编辑一类页面,可能需要使用 */ 36 | activeMenu?: string 37 | /** @name 任意值 @description 供自行扩展使用,但推荐在上面自己定义好 */ 38 | [key: string]: any 39 | } -------------------------------------------------------------------------------- /src/router/modules/dashboard.ts: -------------------------------------------------------------------------------- 1 | import type { Route } from '../index.type' 2 | import Layout from '@/layout/index.vue' 3 | import { createNameComponent } from '../createNode' 4 | const route: Route[] = [ 5 | { 6 | path: '/', 7 | component: Layout, 8 | redirect: '/dashboard', 9 | meta: { title: 'dashboard', icon: 'sfont system-home' }, 10 | children: [ 11 | { 12 | path: 'dashboard', 13 | component: createNameComponent(() => import('@/views/main/dashboard/index.vue')), 14 | meta: { cache: true, title: '首页', icon: 'sfont system-home', hideClose: true } 15 | } 16 | ] 17 | }, 18 | { 19 | path: "/system", 20 | component: Layout, 21 | meta: { title: "系统管理", icon: "sfont system-document" }, 22 | children: [ 23 | { 24 | path: "menu", 25 | meta: { cache: true, title: "菜单管理" }, 26 | component: createNameComponent(() => import('@/views/system/menu.vue')) 27 | }, 28 | { 29 | path: "log", 30 | meta: { cache: true, title: "管理日志" }, 31 | component: createNameComponent(() => import('@/views/system/log.vue')) 32 | }, 33 | { 34 | path: "info", 35 | meta: { cache: true, title: "系统信息" }, 36 | component: createNameComponent(() => import('@/views/system/info.vue')) 37 | }, 38 | ] 39 | } 40 | ] 41 | 42 | export default route -------------------------------------------------------------------------------- /src/router/modules/system.ts: -------------------------------------------------------------------------------- 1 | import type { Route } from '../index.type' 2 | import Layout from '@/layout/index.vue' 3 | import { createNameComponent } from '../createNode' 4 | const route: Route[] = [ 5 | { 6 | path: '/system', 7 | component: Layout, 8 | redirect: '/404', 9 | hideMenu: true, 10 | meta: { title: '系统目录' }, 11 | children: [ 12 | { 13 | path: '/404', 14 | component: createNameComponent(() => import('@/views/main/404.vue')), 15 | meta: { title: '404', hideTabs: true } 16 | }, 17 | { 18 | path: '/401', 19 | component: createNameComponent(() => import('@/views/main/401.vue')), 20 | meta: { title: '401', hideTabs: true } 21 | }, 22 | { 23 | path: '/redirect/:path(.*)', 24 | component: createNameComponent(() => import('@/views/main/redirect.vue')), 25 | meta: { title: '重定向页面', hideTabs: true } 26 | } 27 | ] 28 | }, 29 | { 30 | path: '/login', 31 | component: createNameComponent(() => import('@/views/main/login.vue')), 32 | hideMenu: true, 33 | meta: { title: '登录', hideTabs: true } 34 | }, 35 | { 36 | // 找不到路由重定向到404页面 37 | path: "/:pathMatch(.*)", 38 | component: Layout, 39 | redirect: "/404", 40 | hideMenu: true, 41 | meta: { title: '' }, 42 | children: [] 43 | } 44 | ] 45 | 46 | export default route -------------------------------------------------------------------------------- /src/router/permission/front.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 前端路由管理 3 | **/ 4 | 5 | /** 路由类型 */ 6 | import type { Route } from '../index.type' 7 | 8 | /** 引入需要权限的Modules */ 9 | import Dashboard from '../modules/dashboard' 10 | 11 | /** 登录后需要动态加入的本地路由 */ 12 | const FrontRoutes: Route[] = [ 13 | ...Dashboard, 14 | ] 15 | 16 | export default FrontRoutes -------------------------------------------------------------------------------- /src/router/reload.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /src/stores/app.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | 3 | 4 | export const useAppStore = defineStore('app', { 5 | persist: true, 6 | state: () => { 7 | return { 8 | currentPath: '' as string, // 当前页面路径 9 | isCollapse: false as boolean, // 侧边栏是否收缩展示 10 | contentFullScreen: false as boolean, // 内容是否可全屏展示 11 | showLogo: true as boolean, // 是否显示Logo 12 | fixedTop: false as boolean, // 是否固定顶部, todo,暂未使用 13 | showTabs: true as boolean, // 是否显示导航历史 14 | expandOneMenu: true as boolean, // 一次是否只能展开一个菜单 15 | elementSize: "default" as "" | "default" | "small" | "large", // element默认尺寸,支持官网'large / default /small'小参数 16 | lang: '', // 默认采用的国际化方案,初次进入,采用浏览器当前设置的语言,默认采用中文 17 | theme: { 18 | style: 'default', 19 | primaryColor: '#409eff', 20 | menuType: 'side' 21 | }, 22 | tabs: [] as any[] // 标签列表 23 | 24 | } 25 | }, 26 | getters: { 27 | }, 28 | actions: { 29 | }, 30 | }) -------------------------------------------------------------------------------- /src/stores/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from "pinia" 2 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' 3 | 4 | const stores = createPinia() 5 | stores.use(piniaPluginPersistedstate) 6 | 7 | export default stores -------------------------------------------------------------------------------- /src/stores/user.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import mainApi from '@/api/main' 3 | 4 | import router, { clearRouter } from '@/router' 5 | import Layout from '@/layout/index.vue' 6 | import { createNameComponent } from '../router/createNode' 7 | import { useAppStore } from './app' 8 | 9 | export const useUserStore = defineStore('user', { 10 | state: () => { 11 | return { 12 | authorize: [] as string[], 13 | cachedComponents: [] as string[], 14 | menu: [] as any[], 15 | name: '' as string, 16 | superAdmin: false as boolean 17 | } 18 | }, 19 | getters: { 20 | 21 | }, 22 | actions: { 23 | /** 24 | * get route 25 | * @returns route 26 | */ 27 | getRoute() { 28 | const recurse = (items: any[], level: number = 1) => { 29 | const result: any[] = [] 30 | for (const item of items) { 31 | const obj = { ...item } 32 | obj.meta = Object.assign({}, item.meta) 33 | if (level === 1) { 34 | if (item.path == undefined) continue; 35 | obj.component = Layout 36 | obj.children = recurse(item.children, level + 1) 37 | } else if (level === 2) { 38 | /* 39 | * 不支持完全的动态文件名,webpack 的工作原理是对文件进行静态扫描,然后根据一定规则处理的。 40 | * webpack 在扫描到“import()”语法时,会将变量转换成正则表达式的“.*”,然后根据这个规则匹配文件名,对匹配上的文件独立 chunk 输出 41 | */ 42 | if (item.component == undefined || item.path == undefined) continue; 43 | const path: string[] = item.component.split("/") 44 | obj.component = null 45 | switch (path.length) { 46 | case 1: obj.component = createNameComponent(() => import(`@/views/${path[0]}.vue`)) 47 | break; 48 | case 2: obj.component = createNameComponent(() => import(`@/views/${path[0]}/${path[1]}.vue`)) 49 | break; 50 | case 3: obj.component = createNameComponent(() => import(`@/views/${path[0]}/${path[1]}/${path[2]}.vue`)) 51 | break; 52 | } 53 | if (obj.component === null) { 54 | throw new Error('component error: ' + item.component) 55 | } 56 | } 57 | result.push(obj) 58 | } 59 | return result 60 | } 61 | 62 | const route = recurse(this.menu) 63 | return route 64 | }, 65 | hasAuthorize(name: string): boolean { 66 | if (this.superAdmin) return true 67 | return this.authorize.includes(name) 68 | }, 69 | login(loginParam: any) { 70 | return new Promise((resolve, reject) => { 71 | mainApi.login(loginParam) 72 | .then(res => { 73 | this.name = res.data.name 74 | useAppStore().tabs = [] 75 | resolve(res.data) 76 | }).catch(err => { 77 | reject(err) 78 | }) 79 | }) 80 | }, 81 | logout() { 82 | mainApi.logout().then(() => { 83 | this.$reset() 84 | useAppStore().tabs = [] 85 | clearRouter() 86 | router.replace('/login') 87 | }) 88 | 89 | }, 90 | }, 91 | }) -------------------------------------------------------------------------------- /src/theme/index.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | // 主题色 3 | --system-primary-color: #409eff; // 可做背景色和文本色,用做背景色时,需要和--system-primary-text-color配合使用,避免文件颜色和主题色冲突 4 | --system-primary-text-color: #fff; // 主题色作为背景色时使用 5 | 6 | // logo颜色相关 7 | --system-logo-color: #f1f1f1; 8 | --system-logo-background: #263445; 9 | 10 | // 菜单颜色相关 11 | --system-menu-text-color: #bfcbd9; 12 | --system-menu-background: #181f31; 13 | --system-menu-children-background: #1f2d3d; 14 | --system-menu-submenu-active-color: #fff; 15 | --system-menu-hover-background: #203448; 16 | 17 | // header区域 18 | --system-header-background: #fff; 19 | --system-header-text-color: #303133; 20 | --system-header-breadcrumb-text-color: #606266; 21 | --system-header-item-hover-color: rgba(0,0,0,.06); 22 | --system-header-border-color: #d8dce5; 23 | --system-header-tab-background: #fff; 24 | 25 | // contaier区域,父框架 26 | --system-container-background: #f0f2f5; 27 | --system-container-main-background: #fff; 28 | 29 | // 页面区域, 这一块是你在自己写的文件中使用主题,核心需要关注的地方 30 | --system-page-background: #fff; // 主背景 31 | --system-page-color: #303133; // 主要的文本颜色 32 | --system-page-tip-color: rgba(0, 0, 0, 0.45); // 协助展示的文本颜色 33 | --system-page-border-color: #ebeef5; // 通用的边框配置色,便于主题扩展 34 | 35 | // element主题色修改 36 | --el-color-primary: var(--system-primary-color); 37 | } 38 | 39 | // 进度条颜色修改为主题色 40 | body #nprogress .bar { 41 | background-color: var(--system-primary-color); 42 | } 43 | body #nprogress .peg { 44 | box-shadow: 0 0 10px var(--system-primary-color), 0 0 5px var(--system-primary-color); 45 | } 46 | body #nprogress .spinner-icon { 47 | border-top-color: var(--system-primary-color); 48 | border-left-color: var(--system-primary-color); 49 | } 50 | 51 | @import './modules/dark.scss'; -------------------------------------------------------------------------------- /src/theme/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface Colors { 3 | name: '' // 非国际化版本直接写字符串,如:默认菜单风格 4 | menu: { 5 | textColor: string 6 | background: string 7 | childrenBackground: string 8 | hoverBackground: string 9 | submenuActiveColor: string 10 | } 11 | logo: { 12 | color: string 13 | background: string 14 | } 15 | header: { 16 | background: string 17 | textColor: string 18 | itemHoverColor: string 19 | breadcrumbTextColor: string 20 | borderColor: string 21 | tabBackground: string 22 | } 23 | container: { 24 | background: string 25 | mainBackground: string 26 | } 27 | page: { 28 | background: string 29 | color: string 30 | tipColor: string 31 | borderColor: string 32 | } 33 | } 34 | 35 | export interface Style { 36 | default: Colors 37 | light: Colors 38 | dark: Colors, 39 | [propName: string]: Colors 40 | } 41 | export const style: Style = { 42 | 'default': { 43 | name: '默认菜单风格', 44 | menu: { 45 | textColor: '#bfcbd9', 46 | background: '#181f31', 47 | childrenBackground: '#1f2d3d', 48 | hoverBackground: '#203448', 49 | submenuActiveColor: '#fff' 50 | }, 51 | logo: { 52 | color: '#f1f1f1', 53 | background: '#263445' 54 | }, 55 | header: { 56 | background: '#fff', 57 | textColor: '#303133', 58 | itemHoverColor: 'rgba(0,0,0,.06)', 59 | breadcrumbTextColor: '#606266', 60 | borderColor: '#d8dce5', 61 | tabBackground: '#fff' 62 | }, 63 | container: { 64 | background: '#f0f2f5', 65 | mainBackground: '#fff' 66 | }, 67 | page: { 68 | background: '#fff', 69 | color: '#303133', 70 | tipColor: 'rgba(0, 0, 0, 0.45)', 71 | borderColor: '#ebeef5' 72 | } 73 | }, 74 | 'light': { 75 | name: '亮色菜单风格', 76 | menu: { 77 | textColor: '#272727', 78 | background: '#fff', 79 | childrenBackground: '#fff', 80 | hoverBackground: '#f1f1f1', 81 | submenuActiveColor: 'var(--system-primary-color)' 82 | }, 83 | logo: { 84 | color: '#000', 85 | background: '#fff' 86 | }, 87 | header: { 88 | background: '#fff', 89 | textColor: '#303133', 90 | itemHoverColor: 'rgba(0,0,0,.025)', 91 | breadcrumbTextColor: '#606266', 92 | borderColor: '#d8dce5', 93 | tabBackground: '#fff' 94 | }, 95 | container: { 96 | background: '#f0f2f5', 97 | mainBackground: '#fff' 98 | }, 99 | page: { 100 | background: '#fff', 101 | color: '#303133', 102 | tipColor: 'rgba(0, 0, 0, 0.45)', 103 | borderColor: '#ebeef5' 104 | } 105 | }, 106 | 'chinese': { 107 | name: '中国水墨风', 108 | menu: { 109 | textColor: '#c7c7c7', 110 | background: '#232323', 111 | childrenBackground: '#292929', 112 | hoverBackground: '#1d1d1d', 113 | submenuActiveColor: 'var(--system-primary-color)' 114 | }, 115 | logo: { 116 | color: '#fff', 117 | background: '#232323' 118 | }, 119 | header: { 120 | background: '#f1f0ed', 121 | textColor: '#303133', 122 | itemHoverColor: 'rgba(0,0,0,.025)', 123 | breadcrumbTextColor: '#606266', 124 | borderColor: '#d8dce5', 125 | tabBackground: 'rgba(216, 216, 216, 0.51)' 126 | }, 127 | container: { 128 | background: 'rgba(255, 255, 255, 0.92)', 129 | mainBackground: 'rgba(255, 255, 255, 0.92)' 130 | }, 131 | page: { 132 | background: 'rgba(255, 255, 255, 0.92)', 133 | color: '#303133', 134 | tipColor: 'rgba(0, 0, 0, 0.45)', 135 | borderColor: '#ebeef5' 136 | } 137 | }, 138 | 'dark': { 139 | name: '暗色菜单风格', 140 | menu: { 141 | textColor: '#bbb', 142 | background: '#18181c', 143 | childrenBackground: '#18181c', 144 | hoverBackground: '#000', 145 | submenuActiveColor: '#fff' 146 | }, 147 | logo: { 148 | color: '#fff', 149 | background: '#18181c' 150 | }, 151 | header: { 152 | background: '#18181c', 153 | textColor: '#e3e3e4', 154 | itemHoverColor: '#000', 155 | breadcrumbTextColor: '#fff', 156 | borderColor: '#3e3e3e', 157 | tabBackground: '#1b1b1b' 158 | }, 159 | container: { 160 | background: '#000', 161 | mainBackground: '#18181c' 162 | }, 163 | page: { 164 | background: '#18181c', 165 | color: '#c7c7c7', 166 | tipColor: 'rgba(255, 255, 255, 0.45)', 167 | borderColor: '#3e3e3e' 168 | } 169 | } 170 | } -------------------------------------------------------------------------------- /src/theme/modules/chinese/index.scss: -------------------------------------------------------------------------------- 1 | // 带有本地背景图片的主题需要在main.ts里面主动引入,否则无法正常解析 2 | [data-theme='chinese'] { 3 | .el-main { 4 | background-image: url("./screen.png"); 5 | background-size: 100% 100%; 6 | } 7 | } -------------------------------------------------------------------------------- /src/theme/modules/chinese/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swq8/vue-manage/f6182714ef62c96184e62d74808681544347320b/src/theme/modules/chinese/screen.png -------------------------------------------------------------------------------- /src/theme/modules/dark.scss: -------------------------------------------------------------------------------- 1 | [data-theme="dark"] { 2 | // 通用 3 | p, h1, h2, h3, h4, h5, h6, article { 4 | color: var(--system-page-color); 5 | } 6 | .el-tree { 7 | background-color: var(--system-page-background); 8 | --el-color-primary-light-9: #272727; 9 | .el-tree-node__content:hover { 10 | background-color: #272727; 11 | } 12 | } 13 | .el-card { 14 | background-color: var(--system-page-background); 15 | color: var(--system-page-color); 16 | border-color: var(--system-page-border-color); 17 | .el-card__header { 18 | border-color: var(--system-page-border-color); 19 | } 20 | } 21 | // 页面内部样式修改 22 | 23 | } -------------------------------------------------------------------------------- /src/types/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.bmp' 2 | declare module '*.gif' 3 | declare module '*.jpg' 4 | declare module '*.jpeg' 5 | declare module '*.png' 6 | declare module '*.svg' 7 | declare module '*.tiff' 8 | declare module '*.webp' -------------------------------------------------------------------------------- /src/types/main.d.ts: -------------------------------------------------------------------------------- 1 | interface GeneralDto { 2 | id?: number, 3 | ip?: string, 4 | keyword?: string, 5 | name?: string, 6 | pass?: string, 7 | page?: number, 8 | pageSize?: number, 9 | q?: string, 10 | sort?: string 11 | } -------------------------------------------------------------------------------- /src/types/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | // 国际化声明 7 | declare module 'element-plus/dist/locale/*.mjs'; 8 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import * as math from 'mathjs' 2 | /** 3 | * 从目标对象中拷贝已有的属性 4 | * 5 | * @param objA 6 | * @param objB 7 | */ 8 | export const objAssign = (objA: any, objB: any): void => { 9 | let keysA = Object.keys(objA) 10 | let keysB = Object.keys(objB) 11 | //交集 12 | let arr = keysA.filter(item => keysB.indexOf(item) > -1) 13 | for (const key of arr) { 14 | objA[key] = objB[key] 15 | } 16 | 17 | } 18 | 19 | export const priceToNumber = (price: number | string): number => { 20 | return parseInt(math.multiply(math.bignumber(price), math.bignumber(100)).toString()) 21 | } 22 | 23 | /** 24 | * price format, like this: 1020 -> 10.20 25 | * 26 | * @param 27 | */ 28 | export const priceFormat = (price: number | string): string => { 29 | const num = Number(price) 30 | if (num < 10) { 31 | return "0.0" + price; 32 | } else if (num < 100) { 33 | return "0." + num; 34 | } 35 | let rem = num % 100; 36 | let i = Math.floor(num / 100); 37 | if (rem < 10) { 38 | return i + ".0" + rem; 39 | } else { 40 | return i + "." + rem; 41 | } 42 | } -------------------------------------------------------------------------------- /src/utils/system/nprogress.ts: -------------------------------------------------------------------------------- 1 | import NProgress from "nprogress" 2 | import "nprogress/nprogress.css" 3 | 4 | NProgress.configure({ 5 | easing: 'ease', // 动画方式 6 | speed: 500, // 递增进度条的速度 7 | showSpinner: true, // 是否显示加载ico 8 | trickleSpeed: 200, // 自动递增间隔 9 | minimum: 0.3 // 初始化时的最小百分比 10 | }) 11 | 12 | export default NProgress -------------------------------------------------------------------------------- /src/utils/system/request.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosError, AxiosResponse, AxiosInstance, InternalAxiosRequestConfig } from 'axios' 2 | import { useUserStore } from '@/stores/user' 3 | import { ElMessage } from 'element-plus' 4 | const baseURL: any = import.meta.env.VITE_BASE_URL 5 | 6 | const service: AxiosInstance = axios.create({ 7 | baseURL: baseURL, 8 | timeout: 10000 9 | }) 10 | 11 | // 请求前的统一处理 12 | service.interceptors.request.use( 13 | (config: InternalAxiosRequestConfig) => { 14 | // JWT鉴权处理 15 | const userStore = useUserStore() 16 | if (userStore.name) { 17 | config.headers['name'] = userStore.name 18 | } 19 | return config 20 | }, 21 | (error: AxiosError) => { 22 | console.log(error) // for debug 23 | return Promise.reject(error) 24 | } 25 | ) 26 | 27 | /** 28 | * response.code mean 29 | * SUCCESS = 1 30 | * FORBIDDEN = 2 31 | * NO_PERMISSIONS = 3 32 | * BAD_REQUEST = 4 33 | * ERROR = 5 34 | */ 35 | 36 | service.interceptors.response.use( 37 | (response: AxiosResponse) => { 38 | const res = response.data 39 | if (res.code === 1) { 40 | return res 41 | } else { 42 | showError(res) 43 | return Promise.reject(res) 44 | } 45 | }, 46 | (error: AxiosError) => { 47 | console.log(error) // for debug 48 | const badMessage: any = error.message || error 49 | const code = parseInt(badMessage.toString().replace('Error: Request failed with status code ', '')) 50 | showError({ code, message: badMessage }) 51 | return Promise.reject(error) 52 | } 53 | ) 54 | 55 | // 错误处理 56 | function showError(error: any) { 57 | // token过期,清除本地数据,并跳转至登录页面 58 | if (error.code === 2) { 59 | // to login 60 | useUserStore().logout() 61 | 62 | } else { 63 | ElMessage({ 64 | message: error.msg || error.message || '服务异常', 65 | type: 'error', 66 | duration: 3000 67 | }) 68 | } 69 | 70 | } 71 | 72 | export default service -------------------------------------------------------------------------------- /src/utils/system/statistics.ts: -------------------------------------------------------------------------------- 1 | // 百度统计代码,需自行更换 2 | export function baidu() { 3 | const script = document.createElement('script') 4 | script.type = 'text/javascript' 5 | script.text = ` 6 | var _hmt = _hmt || []; 7 | (function() { 8 | var hm = document.createElement("script"); 9 | hm.src = "https://hm.baidu.com/hm.js?bd78bc908e66174e7dde385bf37cb4c1"; 10 | var s = document.getElementsByTagName("script")[0]; 11 | s.parentNode.insertBefore(hm, s); 12 | })(); 13 | ` 14 | document.getElementsByTagName('head')[0].appendChild(script) 15 | } -------------------------------------------------------------------------------- /src/utils/system/title.ts: -------------------------------------------------------------------------------- 1 | import { systemTitle } from '@/config' 2 | 3 | export function changeTitle(name: any) { 4 | document.title = `${name}-${systemTitle}` 5 | } 6 | -------------------------------------------------------------------------------- /src/utils/tab/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Date: 2022-09-25 20:05:01 3 | * @Description: tab面板的操作方法 4 | */ 5 | 6 | /** 关闭当前标签 */ 7 | export const closeCurrentTab = (nextPath?: string) => { 8 | /** 拿到tab组件 */ 9 | const tab = document.getElementById('vueAdminBoxTabCloseSelf') 10 | if (nextPath) { 11 | /** 设置下一个tab的路径 */ 12 | tab?.setAttribute('nextpath', nextPath) 13 | } 14 | /** 触发tab事件点击 */ 15 | tab?.click() 16 | if (nextPath) { 17 | setTimeout(() => { 18 | /** 清除下一个tab的路径 */ 19 | tab?.removeAttribute('nextpath') 20 | }, 100) 21 | } 22 | } 23 | 24 | /** 关闭其他标签 */ 25 | export const closeOtherTab = () => { 26 | /** 拿到tab组件 */ 27 | const tab = document.getElementById('vueAdminBoxTabCloseOther') 28 | /** 触发tab事件点击 */ 29 | tab?.click() 30 | } 31 | 32 | /** 关闭所有标签 */ 33 | export const closeAllTab = () => { 34 | /** 拿到tab组件 */ 35 | const tab = document.getElementById('vueAdminBoxTabCloseAll') 36 | /** 触发tab事件点击 */ 37 | tab?.click() 38 | } 39 | 40 | /** 刷新当前标签 */ 41 | export const refreshCurrentTab = () => { 42 | /** 拿到tab组件 */ 43 | const tab = document.getElementById('vueAdminBoxTabRefresh') 44 | /** 触发tab事件点击 */ 45 | tab?.click() 46 | } -------------------------------------------------------------------------------- /src/views/express/freeRule.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 74 | 75 | -------------------------------------------------------------------------------- /src/views/goods/template.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 108 | 109 | -------------------------------------------------------------------------------- /src/views/main/redirect.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/views/other/staticRes.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 67 | 68 | -------------------------------------------------------------------------------- /src/views/system/components/ElIconPicker.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 76 | 77 | -------------------------------------------------------------------------------- /src/views/user/balanceLog.vue: -------------------------------------------------------------------------------- 1 | 28 | 115 | 116 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "target": "esnext", 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "esModuleInterop": true, 12 | "lib": [ 13 | "esnext", 14 | "dom" 15 | ], 16 | "types": [ 17 | "element-plus/global", 18 | "vite/client", 19 | "node" 20 | ], 21 | "typeRoots": [ 22 | "node_modules", 23 | "node_modules/@types" 24 | ], 25 | "baseUrl": "./", 26 | "paths": { 27 | "@/*": [ 28 | "src/*" 29 | ] 30 | } 31 | }, 32 | "include": [ 33 | "src/**/*.ts", 34 | "src/**/*.d.ts", 35 | "src/**/*.tsx", 36 | "src/**/*.vue" 37 | ] 38 | } -------------------------------------------------------------------------------- /vite.config.mts: -------------------------------------------------------------------------------- 1 | import { ConfigEnv, UserConfigExport } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import { vitePluginSvg } from "@webxrd/vite-plugin-svg" 4 | import { resolve } from 'path' 5 | 6 | const pathResolve = (dir: string): any => { 7 | return resolve(__dirname, ".", dir) 8 | } 9 | 10 | const alias: Record = { 11 | '@': pathResolve("src") 12 | } 13 | 14 | /** 15 | * @description-en vite document address 16 | * @description-cn vite官网 17 | * https://vitejs.cn/config/ */ 18 | export default ({ command }: ConfigEnv): UserConfigExport => { 19 | return { 20 | base: './', 21 | build: { 22 | chunkSizeWarningLimit: 20_000 23 | }, 24 | // optimized dependencies changed 25 | optimizeDeps: { 26 | include: ['@tinymce/tinymce-vue', 'mathjs'] 27 | }, 28 | server: { 29 | host: '0.0.0.0', 30 | proxy: { 31 | // 接口地址代理 32 | '/adminApi': { 33 | target: 'http://127.0.0.1:8080', 34 | changeOrigin: true, // 跨域 35 | // rewrite: path => path.replace(/^\/demo/, '/demo') 36 | }, 37 | // 图片资源代理 38 | '/img': { 39 | target: 'http://127.0.0.1:8080', 40 | changeOrigin: true, // 跨域 41 | }, 42 | } 43 | }, 44 | resolve: { 45 | alias 46 | }, 47 | plugins: [ 48 | vue(), 49 | vitePluginSvg({ 50 | // 必要的。必须是绝对路径组成的数组。 51 | iconDirs: [ 52 | resolve(__dirname, 'src/assets/svg'), 53 | ], 54 | // 必要的。入口script 55 | main: resolve(__dirname, 'src/main.js'), 56 | symbolIdFormat: 'icon-[name]' 57 | }), 58 | ], 59 | css: { 60 | postcss: { 61 | plugins: [ 62 | { 63 | postcssPlugin: 'internal:charset-removal', 64 | AtRule: { 65 | charset: (atRule) => { 66 | if (atRule.name === 'charset') { 67 | atRule.remove(); 68 | } 69 | } 70 | } 71 | } 72 | ], 73 | }, 74 | } 75 | }; 76 | } 77 | --------------------------------------------------------------------------------