├── example
├── allaw.cur
└── default.html
├── .gitignore
├── src
├── assets
│ ├── allaw.cur
│ ├── audio.png
│ ├── bigtext.png
│ ├── close.png
│ ├── cursor.png
│ ├── pointer.png
│ ├── reset.png
│ ├── speed.png
│ ├── zoomin.png
│ ├── zoomout.png
│ ├── audio-close.png
│ ├── audio-hover.png
│ ├── close-hover.png
│ ├── cursor-hover.png
│ ├── pointeread.png
│ ├── reset-hover.png
│ ├── speed-hover.png
│ ├── speed-quick.png
│ ├── zoomin-hover.png
│ ├── bigtext-hover.png
│ ├── pointer-hover.png
│ ├── zoomout-hover.png
│ ├── audio-close-hover.png
│ ├── pointeread-hover.png
│ └── speed-quick-hover.png
├── config.json
├── modules
│ ├── CursorAuto
│ │ ├── index.scss
│ │ └── index.js
│ ├── hack.js
│ ├── PointerFllow
│ │ ├── index.tmpl.js
│ │ ├── index.scss
│ │ └── index.js
│ ├── Audio
│ │ ├── index.tmpl.js
│ │ ├── index.scss
│ │ └── index.js
│ ├── BigText
│ │ ├── index.tmpl.js
│ │ ├── index.scss
│ │ └── index.js
│ ├── constans.js
│ ├── pubSub.js
│ ├── TopBar
│ │ ├── index.scss
│ │ ├── index.js
│ │ └── index.tmpl.js
│ ├── ZoomPage.js
│ ├── base.js
│ └── utils.js
├── assist-entry.js
└── assist.js
├── DEVELOPER.md
├── package.json
├── rollup.config.js
└── README.md
/example/allaw.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/example/allaw.cur
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # system ignore
3 | .DS_Store
4 | node_modules
5 | node_modules/
6 | .tmpl
--------------------------------------------------------------------------------
/src/assets/allaw.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/allaw.cur
--------------------------------------------------------------------------------
/src/assets/audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/audio.png
--------------------------------------------------------------------------------
/src/assets/bigtext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/bigtext.png
--------------------------------------------------------------------------------
/src/assets/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/close.png
--------------------------------------------------------------------------------
/src/assets/cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/cursor.png
--------------------------------------------------------------------------------
/src/assets/pointer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/pointer.png
--------------------------------------------------------------------------------
/src/assets/reset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/reset.png
--------------------------------------------------------------------------------
/src/assets/speed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/speed.png
--------------------------------------------------------------------------------
/src/assets/zoomin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/zoomin.png
--------------------------------------------------------------------------------
/src/assets/zoomout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/zoomout.png
--------------------------------------------------------------------------------
/src/assets/audio-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/audio-close.png
--------------------------------------------------------------------------------
/src/assets/audio-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/audio-hover.png
--------------------------------------------------------------------------------
/src/assets/close-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/close-hover.png
--------------------------------------------------------------------------------
/src/assets/cursor-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/cursor-hover.png
--------------------------------------------------------------------------------
/src/assets/pointeread.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/pointeread.png
--------------------------------------------------------------------------------
/src/assets/reset-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/reset-hover.png
--------------------------------------------------------------------------------
/src/assets/speed-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/speed-hover.png
--------------------------------------------------------------------------------
/src/assets/speed-quick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/speed-quick.png
--------------------------------------------------------------------------------
/src/assets/zoomin-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/zoomin-hover.png
--------------------------------------------------------------------------------
/src/assets/bigtext-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/bigtext-hover.png
--------------------------------------------------------------------------------
/src/assets/pointer-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/pointer-hover.png
--------------------------------------------------------------------------------
/src/assets/zoomout-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/zoomout-hover.png
--------------------------------------------------------------------------------
/src/assets/audio-close-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/audio-close-hover.png
--------------------------------------------------------------------------------
/src/assets/pointeread-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/pointeread-hover.png
--------------------------------------------------------------------------------
/src/assets/speed-quick-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duheng/assist/HEAD/src/assets/speed-quick-hover.png
--------------------------------------------------------------------------------
/src/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "namespace": "mozi-assist",
3 | "domain": "",
4 | "url": "//tts.baidu.com/text2audio"
5 | }
--------------------------------------------------------------------------------
/src/modules/CursorAuto/index.scss:
--------------------------------------------------------------------------------
1 | * {
2 | cursor:url("./allaw.cur"),auto !important;
3 | }
4 | a {
5 | cursor:url("./linkaw.cur"),auto !important;
6 | }
--------------------------------------------------------------------------------
/src/assist-entry.js:
--------------------------------------------------------------------------------
1 | import Assist from './assist.js';
2 | import config from './config.json';
3 |
4 | const AssistEntry = new Assist(config)
5 | export default AssistEntry;
--------------------------------------------------------------------------------
/src/modules/hack.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | ie10 不支持 location.origin,以下是hack方法
4 | */
5 |
6 | if (!window.location.origin) {
7 | window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/src/modules/PointerFllow/index.tmpl.js:
--------------------------------------------------------------------------------
1 | const PointerFllowHtml = () => {
2 | return `
`
6 | }
7 |
8 | export default PointerFllowHtml;
--------------------------------------------------------------------------------
/src/modules/Audio/index.tmpl.js:
--------------------------------------------------------------------------------
1 | const BigTextHtml = (namespace) => {
2 | return `
6 | `
7 | }
8 |
9 | export default BigTextHtml;
--------------------------------------------------------------------------------
/src/modules/PointerFllow/index.scss:
--------------------------------------------------------------------------------
1 | @mixin pointer {
2 | z-index: 99999999999;
3 | transform: none;
4 | transform-origin: 0px 0px;
5 | position:fixed; top:0;left:0; background-color:#ff0000 !important; width:100%; height:4px;
6 | }
7 | .pointer-follow-html {
8 | &-x,&-y {
9 | @include pointer;
10 | }
11 | &-y { height:100%; width:4px; }
12 | }
--------------------------------------------------------------------------------
/DEVELOPER.md:
--------------------------------------------------------------------------------
1 | ## 开发者需关注的
2 |
3 | #### 基础配置(src/config.json)
4 | 1 - namespace 给插件起一个命名空间
5 |
6 | 2 - domain 在你的具体项目中你需要设置如 .mozi.com 的 domain 来保持你网站多页面之间的状态保持
7 |
8 | 3 - url 文本转语音的api接口,目前用的是百度免费的,如用于生产环境你需要自行开发
9 |
10 | ```
11 | {
12 | "namespace": "mozi-assist",
13 | "domain": "",
14 | "url": "//tts.baidu.com/text2audio"
15 | }
16 | ```
17 |
18 | #### 开发
19 |
20 | ```
21 | npm i
22 | npm start (启动开发)
23 | ```
24 | 访问 http://localhost:3000/example/default.html
--------------------------------------------------------------------------------
/src/modules/BigText/index.tmpl.js:
--------------------------------------------------------------------------------
1 | const BigTextHtml = (namespace) => {
2 | return ``
8 | }
9 |
10 | const BigTextBone = () => {
11 | return ``
12 | }
13 |
14 | export {
15 | BigTextHtml,
16 | BigTextBone
17 | };
--------------------------------------------------------------------------------
/src/modules/constans.js:
--------------------------------------------------------------------------------
1 | const audioTabText = {
2 | pointeread: '已开启指读模式',
3 | bigtextOpen: '大字幕已开启',
4 | bigtextClose: '大字幕已关闭',
5 | pointerFollowOpen: '十字线已开启',
6 | pointerFollowClose: '十字线已关闭',
7 | cursorAutoOpen: '大鼠标已开启',
8 | cursorAutoClose: '大鼠标已关闭',
9 | zoomOut: '页面已放大',
10 | zoomOutEnd: '页面已放到最大',
11 | zoomMin: '页面已缩小',
12 | zoomMinEnd: '页面已缩至最小',
13 | speedQuick: '语速已加快',
14 | speedMiddle: '语速已正常',
15 | audioOpen: '声音已开启',
16 | audioClose: '声音关闭',
17 | reset: '已重置',
18 | }
19 | export const symbolsReg = new RegExp("[]")
20 | export default audioTabText
21 |
22 |
--------------------------------------------------------------------------------
/src/modules/Audio/index.scss:
--------------------------------------------------------------------------------
1 | @mixin pointer {
2 | z-index: 99999999999;
3 | transform: none;
4 | transform-origin: 0px 0px;
5 |
6 | position:fixed; top:0;left:0; background-color:blue !important; width:100%; height:2px;
7 | }
8 | .bigtext-html {
9 | z-index: 99999999999;
10 | height: 150px;
11 | text-align: center;
12 | position: fixed;
13 | bottom: 0;
14 | right: 0;
15 | left: 0;
16 | border-top: 1px solid #505050;
17 | &-content {
18 | height: 100%;
19 | background-color: #FFFFFF;
20 | font-size: 53px;
21 | color: #333 !important;
22 | text-align: center;
23 | font-weight: bold;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/modules/pubSub.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | list: {},
4 | subscribe: function(key, fn) {
5 | if (!this.list[key]) this.list[key] = [];
6 |
7 | this.list[key].push(fn);
8 | },
9 | unsubscribe: function(key, fn) {
10 | let fnList = this.list[key];
11 |
12 | if (!fnList) return false;
13 |
14 | if (!fn) { // 不传入指定的方法,清空所用 key 下的订阅
15 | fnList && (fnList.length = 0);
16 | } else {
17 | fnList.forEach((item, index) => {
18 | item === fn && fnList.splice(index, 1);
19 | });
20 | }
21 | },
22 | publish: function(key, ...args) {
23 | let fnList = this.list[key];
24 | if (!fnList) return false;
25 |
26 | for (let fn of this.list[key]) {
27 | !!fn && fn.call(this, ...args);
28 | }
29 |
30 | }
31 | }
--------------------------------------------------------------------------------
/example/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 墨子工程
6 |
7 |
8 | 无障碍
9 |
10 |
15 |
16 |
17 |
18 |
无障碍role标注
19 |
跳转到 墨子工程
20 |

21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/modules/BigText/index.scss:
--------------------------------------------------------------------------------
1 | @mixin pointer {
2 | z-index: 99999999999;
3 | transform: none;
4 | transform-origin: 0px 0px;
5 |
6 | position:fixed; top:0;left:0; background-color:blue !important; width:100%; height:2px;
7 | }
8 | .bigtext-html {
9 | z-index: 99999999999;
10 | height: 150px;
11 | text-align: center;
12 | position: fixed;
13 | bottom: 0;
14 | right: 0;
15 | left: 0;
16 | border-top: 1px solid #797F8D;
17 | background-color: #FFFFFF;
18 | &-content {
19 | height: 100%;
20 | background-color: #FFFFFF;
21 | font-size: 53px;
22 | color: #333 !important;
23 | text-align: center;
24 | font-weight: bold;
25 | width: 93%;
26 | margin: 0 auto;
27 | }
28 |
29 | &-btn {
30 | width: 20px;
31 | height: 20px;
32 | background-color: red;
33 | position: absolute;
34 | right: 20px;
35 | top: 20px;
36 | border-radius: 10px;
37 | color: #FFFFFF;
38 | cursor: pointer;
39 | }
40 |
41 | &-bone {
42 | width: 100%;
43 | height: 151px;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/assist.js:
--------------------------------------------------------------------------------
1 | import './modules/hack';
2 | import Base from './modules/base';
3 | import TopBar from './modules/TopBar';
4 | import Audio from './modules/Audio';
5 | import ZoomPage from './modules/ZoomPage';
6 | import PointerFllow from './modules/PointerFllow';
7 | import CursorAuto from './modules/CursorAuto';
8 | import BigText from './modules/BigText';
9 |
10 | const InitModules = [ TopBar, Audio, ZoomPage, PointerFllow, CursorAuto, BigText ]
11 | class Assist extends Base {
12 |
13 | constructor(opts = {}) {
14 | super(opts);
15 | // 合并参数
16 | this.mergeConfig(opts);
17 | // 初始化插件
18 | this.init();
19 | this.isShow();
20 | this.resetAction = this.reset
21 | }
22 |
23 | init() {
24 | // 初始化dom
25 | InitModules.map(item=>this.use(item))
26 | this.registeStyle()
27 | this.registeHtml()
28 | // 初始化事件
29 | InitModules.map(item=>this.useEvent(item))
30 | // 格式化大段文本
31 | this.formatLongText()
32 |
33 | }
34 |
35 | reset() {
36 | Audio.reset()
37 | ZoomPage.reset()
38 | CursorAuto.reset(this)
39 | PointerFllow.reset(this)
40 | BigText.reset(this)
41 | }
42 |
43 | }
44 | export default Assist;
45 |
--------------------------------------------------------------------------------
/src/modules/TopBar/index.scss:
--------------------------------------------------------------------------------
1 |
2 | .topbar-html {
3 | width: 100%;
4 | background: #797F8D;
5 | overflow: hidden;
6 | z-index: 2147483645;
7 | position: fixed;
8 | top: 0;
9 | box-shadow: 0 0 10px 2px #999;
10 | left: 0;
11 | right: 0;
12 | &-mright {
13 | margin-right: 50px !important;
14 | }
15 | &-margin0 {
16 | margin: 0 !important;
17 | }
18 | &-content {
19 | width: 1080px;
20 | height: 100px;
21 | margin: 0 auto;
22 | display: flex;
23 | justify-content: center;
24 | &-item {
25 | cursor: pointer;
26 | margin: 0 6px;
27 | display: flex;
28 | flex-direction: column;
29 | align-items: center;
30 | span {
31 | height: 30px;
32 | line-height: 30px;
33 | color: #FFFFFF;
34 | font-size: 16px;
35 | font-weight: 500;
36 | font-family: PingFangSC-Medium;
37 | }
38 |
39 | img {
40 | height: 52px;
41 | width: 52px;
42 | border-radius: 5px;
43 | display: block;
44 | }
45 |
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/modules/CursorAuto/index.js:
--------------------------------------------------------------------------------
1 | import { cookie, removeNode } from '../utils'
2 | import audioTabText from '../constans'
3 | import Audio from '../Audio';
4 |
5 | import styles from './index.scss'
6 |
7 | const CursorAuto = {
8 | init(core) {
9 | const { namespace } = core.config
10 |
11 | },
12 | setEvents(core) {
13 | const { namespace } = core.config
14 | if(cookie.get('cursor',namespace)) {
15 | core.creatStyle('cursor-auto-style',styles,true)
16 | }
17 | const tabBarBtn = document.getElementById(`${namespace}-cursor-auto`)
18 | tabBarBtn.onclick = () => {
19 | const activeBtn = document.getElementById(`${namespace}-cursor-auto-style`)
20 | if(activeBtn) {
21 | removeNode(activeBtn)
22 | cookie.set('cursor', false, namespace)
23 | Audio.playAudio(audioTabText.cursorAutoClose)
24 | } else {
25 | cookie.set('cursor', true, namespace)
26 | core.creatStyle('cursor-auto-style',styles,true)
27 | Audio.playAudio(audioTabText.cursorAutoOpen)
28 | }
29 | }
30 | },
31 | reset(core) {
32 | const { namespace } = core.config
33 | const activeBtn = document.getElementById(`${namespace}-cursor-auto-style`)
34 | activeBtn && removeNode(activeBtn)
35 | }
36 |
37 | };
38 |
39 | export default CursorAuto;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assist",
3 | "version": "0.0.1",
4 | "description": "盲人辅助工具",
5 | "scripts": {
6 | "start": "export ENV=development && rollup --config rollup.config.js --watch",
7 | "build": "rollup --config rollup.config.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/duheng/assist.git"
12 | },
13 | "author": "墨子",
14 | "license": "MIT",
15 | "bugs": {
16 | "url": "https://github.com/duheng/assist/issues"
17 | },
18 | "browserslist": [
19 | "> 1%",
20 | "last 2 versions",
21 | "ie 6-11"
22 | ],
23 | "homepage": "https://github.com/duheng/assist#readme",
24 | "devDependencies": {
25 | "@babel/core": "^7.8.7",
26 | "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
27 | "@babel/plugin-transform-async-to-generator": "^7.10.1",
28 | "@babel/plugin-transform-classes": "^7.13.0",
29 | "@babel/preset-env": "^7.14.2",
30 | "@rollup/plugin-commonjs": "^12.0.0",
31 | "@rollup/plugin-image": "^2.0.6",
32 | "@rollup/plugin-json": "^4.0.2",
33 | "@rollup/plugin-node-resolve": "^8.0.0",
34 | "core-js": "^3.12.1",
35 | "eslint": "^6.8.0",
36 | "eslint-config-airbnb": "^18.1.0",
37 | "eslint-plugin-import": "^2.20.1",
38 | "lerna": "^3.5.1",
39 | "rollup": "^2.0.6",
40 | "rollup-plugin-babel": "^4.4.0",
41 | "rollup-plugin-copy": "^3.4.0",
42 | "rollup-plugin-eslint": "^7.0.0",
43 | "rollup-plugin-hash": "^1.3.0",
44 | "rollup-plugin-sass": "^1.2.2",
45 | "rollup-plugin-serve": "^1.1.0",
46 | "rollup-plugin-terser": "^7.0.2"
47 | },
48 | "dependencies": {
49 | "es6-proxy-polyfill": "^2.1.1",
50 | "js-cookie": "^2.2.1"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/modules/ZoomPage.js:
--------------------------------------------------------------------------------
1 | import { cookie, addEvent, removeEvent } from './utils'
2 | import audioTabText from './constans'
3 | import Audio from './Audio';
4 |
5 | const ZoomPage = {
6 | init(core) {
7 | const { namespace } = core.config
8 | this.size = cookie.get('zomm',namespace) || 1.0
9 | this.ignore = ['LINK','SCRIPT']
10 | this.namespace = namespace
11 | this.set()
12 |
13 | },
14 | setEvents(core) {
15 | const { namespace } = core.config
16 | document.getElementById(`${namespace}-zoom-out`).onclick = () => {
17 | this.zoomOut(core)
18 | }
19 |
20 | document.getElementById(`${namespace}-zoom-min`).onclick = () => {
21 | this.zoomMin(core)
22 | }
23 | addEvent(window,'DOMContentLoaded',()=>{
24 | this.updateZoomState(core)
25 | })
26 | },
27 | updateZoomState(core) {
28 | let { message } = core
29 | message.publish('zoomState',this.size)
30 | },
31 | zoomOut(core) {
32 | if(this.size >= 1.3) {
33 | console.log('已最大')
34 | Audio.playAudio(audioTabText.zoomOutEnd)
35 | this.updateZoomState(core)
36 | return
37 | }
38 | this.size = parseFloat((this.size+0.1).toFixed(10));
39 | this.updateZoomState(core)
40 | this.set();
41 | Audio.playAudio(audioTabText.zoomOut)
42 | },
43 | zoomMin(core) {
44 | if(this.size <= 1.0) {
45 | console.log('已最小')
46 | Audio.playAudio(audioTabText.zoomMinEnd)
47 | this.updateZoomState(core)
48 | return
49 | }
50 | this.size = parseFloat((this.size-0.1).toFixed(10));
51 | this.updateZoomState(core)
52 | this.set();
53 | Audio.playAudio(audioTabText.zoomMin)
54 | },
55 | set() {
56 | [].forEach.call( document.body.children, (el)=> {
57 | const __el = el.tagName.toUpperCase()
58 | if(this.ignore.indexOf(__el) > -1 || el.id == this.namespace) {
59 | return
60 | }
61 | el.style.zoom = this.size;
62 | // el.style.transform = `scale(${this.size})`
63 | //el.style.transformOrigin = '0px 0px'
64 | });
65 | cookie.set('zomm', this.size, this.namespace)
66 | },
67 | reset() {
68 | this.size = 1.0
69 | this.set()
70 | }
71 |
72 | };
73 |
74 | export default ZoomPage;
--------------------------------------------------------------------------------
/src/modules/PointerFllow/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { cookie, addEvent, removeEvent } from '../utils'
3 | import audioTabText from '../constans'
4 | import Audio from '../Audio';
5 |
6 | import styles from './index.scss'
7 | import tmpl from './index.tmpl.js'
8 | const PointerFllow = {
9 | init(core) {
10 | const { namespace } = core.config
11 | this.body = document.body
12 | core.creatStyle('pointer-follow-style',styles)
13 | core.creatHtml('pointer-follow-html',tmpl)
14 |
15 | },
16 | setEvents(core) {
17 | const { namespace } = core.config
18 | if(cookie.get('pointer',namespace)) {
19 | this.show(core)
20 | }
21 | this.togglePointer(core, namespace)
22 | },
23 | addEventMove() {
24 | addEvent(this.body,'mousemove',this.mouseMove)
25 | },
26 | removeEventMove() {
27 | removeEvent(this.body,'mousemove',this.mouseMove)
28 | },
29 | togglePointer(core, namespace) {
30 | const tabBarBtn = document.getElementById(`${namespace}-pointer-follow`)
31 | const activeBtn = document.getElementById(`${namespace}-pointer-follow-html`)
32 | tabBarBtn.onclick = () => {
33 | if( activeBtn.style.display == 'block' ) {
34 | this.reset(core)
35 | Audio.playAudio(audioTabText.pointerFollowClose)
36 | } else {
37 | this.show(core)
38 | Audio.playAudio(audioTabText.pointerFollowOpen)
39 | }
40 | }
41 | },
42 | mouseMove(event){
43 | var event = window.event || event;
44 | var pointerX = document.getElementById("pointer-follow-html-x"),
45 | pointerY = document.getElementById("pointer-follow-html-y");
46 | pointerX.style.top = event.clientY - 10 + "px";
47 | pointerY.style.left = event.clientX - 10 + "px";
48 | },
49 | show(core) {
50 | const { namespace } = core.config
51 | const activeBtn = document.getElementById(`${namespace}-pointer-follow-html`)
52 | activeBtn.style.display = 'block'
53 | this.addEventMove()
54 | cookie.set('pointer',true,namespace)
55 | },
56 | reset(core) {
57 | const { namespace } = core.config
58 | const activeBtn = document.getElementById(`${namespace}-pointer-follow-html`)
59 | activeBtn.style.display = 'none'
60 | this.removeEventMove()
61 | cookie.set('pointer',false,namespace)
62 | }
63 | };
64 |
65 | export default PointerFllow;
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const babelPlugin = require('rollup-plugin-babel');
4 | const json = require('@rollup/plugin-json');
5 |
6 | //const { eslint } = require('rollup-plugin-eslint');
7 | const cwd = process.cwd();
8 | import sass from 'rollup-plugin-sass';
9 | import resolve from '@rollup/plugin-node-resolve';
10 | import commonjs from '@rollup/plugin-commonjs';
11 | import image from '@rollup/plugin-image';
12 | import { terser } from "rollup-plugin-terser";
13 | import serve from "rollup-plugin-serve";
14 |
15 | // import hash from 'rollup-plugin-hash';
16 |
17 | import copy from 'rollup-plugin-copy'
18 |
19 | const entry = {
20 | assist: './src/assist.js',
21 | 'assist-entry':'./src/assist-entry.js'
22 | }
23 |
24 | const mark = `/**
25 | * 欢迎来到墨子工程
26 | * 邮箱: duheng1100@163.com
27 | * github: https://github.com/duheng/
28 | **/`
29 |
30 | function generateWebConfig(isBrowser,input) {
31 | return {
32 | input,
33 | output: {
34 | banner: mark,
35 | dir: 'dist',
36 | format: isBrowser ? 'umd' : 'cjs',
37 | name: 'AssistEntry'
38 | },
39 | plugins: [
40 | sass(),
41 | json(),
42 | image(),
43 | babelPlugin({
44 | exclude: 'node_modules/**',
45 | presets: [
46 | [
47 | '@babel/env',
48 | {
49 | modules: false,
50 | targets: {
51 | browsers: [
52 | "> 1%",
53 | "last 2 versions",
54 | "ie 9-11"
55 | ],
56 | // node: 8
57 | },
58 | corejs: 3, // 声明corejs版本
59 | useBuiltIns: 'usage'
60 | }
61 | ]
62 | ],
63 | plugins: [
64 | '@babel/plugin-proposal-object-rest-spread',
65 | '@babel/plugin-transform-classes',
66 | ],
67 | }),
68 | resolve({
69 | browser: isBrowser,
70 | }),
71 | commonjs(),
72 | // terser({ compress: { drop_console: true } })
73 | copy({
74 | targets: [
75 | { src: 'src/assets/allaw.cur', dest: 'example' }
76 | ]
77 | }),
78 | process.env.ENV === "development" ? serve({
79 | port: 3000,
80 | contentBase: ["./"], // 静态资源所在目录
81 | }) : null
82 | ],
83 | };
84 | }
85 |
86 | const build = () => {
87 | return Object.keys(entry).map(item=>{
88 | return generateWebConfig(true,entry[item])
89 | })
90 | }
91 | module.exports = build();
--------------------------------------------------------------------------------
/src/modules/TopBar/index.js:
--------------------------------------------------------------------------------
1 | import { cookie, addEvent,isFirefox, removeEvent } from '../utils'
2 | import styles from './index.scss'
3 | import tmpl from './index.tmpl.js'
4 | const TopBar = {
5 | init(core) {
6 | const { namespace } = core.config
7 | this.namespace = namespace
8 | core.creatStyle('topbar-style',styles)
9 | core.creatHtml('topbar-html',tmpl)
10 | },
11 | setEvents(core) {
12 | const { namespace } = core.config
13 | const BtnClose = document.getElementById(`${namespace}-close`)
14 | const BtnReset = document.getElementById(`${namespace}-reset`)
15 | const HoverItem = document.getElementById(`${namespace}-topbar-html-content`)
16 |
17 | BtnClose.onclick = () => {
18 | core.close()
19 | }
20 |
21 | BtnReset.onclick = () => {
22 | core.resetAction()
23 | }
24 |
25 | if(isFirefox()) {
26 | document.getElementById(`${namespace}-zoom-out`).style.display = 'none'
27 | document.getElementById(`${namespace}-zoom-min`).style.display = 'none'
28 | }
29 |
30 | [].forEach.call( HoverItem.children, (el)=> {
31 | addEvent(el,'mouseover',this.mouseOver)
32 | addEvent(el,'mouseout',this.mouseOut)
33 | });
34 |
35 |
36 | },
37 | mouseOver(event){
38 | var event = window.event || event;
39 | var target = event.target || event.srcElement;
40 | if(target.tagName !== 'IMG') {
41 | return
42 | }
43 | const __name = target.getAttribute('name')
44 | const __hover = target.getAttribute('hover-src')
45 |
46 | if(__name == 'audio') {
47 | if(cookie.get('audio',TopBar.namespace)) {
48 | target.src = __hover
49 | } else {
50 | target.src = target.getAttribute('selected-hover-src')
51 | }
52 |
53 | } else if (__name == 'speed') {
54 | if(cookie.get('speed',TopBar.namespace) == 'fast' ) {
55 | target.src = target.getAttribute('selected-hover-src')
56 | } else {
57 | target.src = __hover
58 | }
59 | } else {
60 | target.src = __hover
61 | }
62 |
63 |
64 | },
65 | mouseOut(event) {
66 | var event = window.event || event;
67 | var target = event.target || event.srcElement;
68 | if(target.tagName !== 'IMG') {
69 | return
70 | }
71 | const __name = target.getAttribute('name')
72 | const __source = target.getAttribute('source-src')
73 | if(__name == 'audio') {
74 | if(cookie.get('audio',TopBar.namespace)) {
75 | target.src = __source
76 | } else {
77 | target.src = target.getAttribute('selected-src')
78 | }
79 |
80 | } else if (__name == 'speed') {
81 | if(cookie.get('speed',TopBar.namespace) == 'fast' ) {
82 | target.src = target.getAttribute('selected-src')
83 | } else {
84 | target.src = __source
85 | }
86 | } else {
87 | target.src = __source
88 | }
89 | }
90 | };
91 |
92 | export default TopBar;
--------------------------------------------------------------------------------
/src/modules/BigText/index.js:
--------------------------------------------------------------------------------
1 | import { cookie, addEvent, removeEvent, parseTagText } from '../utils'
2 | import audioTabText,{ symbolsReg } from '../constans'
3 | import Audio from '../Audio';
4 |
5 | import styles from './index.scss'
6 | import { BigTextHtml, BigTextBone } from './index.tmpl.js'
7 |
8 | const BigText = {
9 | init(core) {
10 | const { namespace } = core.config
11 | this.body = document.body
12 | this.namespace = namespace
13 | core.creatStyle('bigtext-style',styles)
14 | core.creatHtml('bigtext-html',BigTextHtml)
15 | core.creatHtml('bigtext-bone',BigTextBone)
16 | },
17 | setEvents(core) {
18 | const { namespace } = core.config
19 | addEvent(window,'DOMContentLoaded',()=>{
20 | if(cookie.get('bigtext',namespace)) {
21 | this.show(core)
22 | }
23 | })
24 | this.toggleBigText(core, namespace)
25 | },
26 | addEventMove() {
27 | addEvent(this.body,'mouseover',this.mouseOver)
28 | },
29 | removeEventMove() {
30 | removeEvent(this.body,'mouseover',this.mouseOver)
31 | },
32 | toggleBigText(core, namespace) {
33 | const tabBarBtn = document.getElementById(`${namespace}-bigtext`)
34 | const tabBarBtnClose = document.getElementById(`${namespace}-bigtext-close`)
35 | tabBarBtn.onclick = () => {
36 | const activeBtn = document.getElementById(`${namespace}-bigtext-html`)
37 | if( activeBtn.style.display == 'block' ) {
38 | this.reset(core)
39 | Audio.playAudio(audioTabText.bigtextClose)
40 | } else {
41 | this.show(core)
42 | Audio.playAudio(audioTabText.bigtextOpen)
43 | }
44 | }
45 |
46 | tabBarBtnClose.onclick = ()=> {
47 | this.reset(core)
48 | Audio.playAudio(audioTabText.bigtextClose)
49 | }
50 | },
51 | mouseOver(event){
52 | var event = window.event || event;
53 | var target = event.target || event.srcElement;
54 | const { namespace } = BigText
55 | var __parentNodeId = target.parentNode.id
56 | var __isAssist = __parentNodeId.indexOf(namespace) > -1
57 | const activeBtn = document.getElementById(`${namespace}-bigtext-content`)
58 | activeBtn.innerText = parseTagText(target).replace(symbolsReg,'');
59 | if(__isAssist || activeBtn.innerText == '文本') {
60 | activeBtn.innerText = ''
61 | return
62 | }
63 | },
64 | show(core) {
65 | const { namespace } = core.config
66 | const activeBtn = document.getElementById(`${namespace}-bigtext-html`)
67 | const tabBar = document.getElementById(`${namespace}-bigtext-bone`)
68 | activeBtn.style.display = 'block'
69 | tabBar.style.display = 'block'
70 | this.addEventMove()
71 | cookie.set('bigtext', true, namespace)
72 | core.message.publish('bigTextState',true)
73 | },
74 | reset(core) {
75 | const { namespace } = core.config
76 | const activeBtn = document.getElementById(`${namespace}-bigtext-html`)
77 | const tabBar = document.getElementById(`${namespace}-bigtext-bone`)
78 | activeBtn.style.display = 'none'
79 | tabBar.style.display = 'none'
80 | this.removeEventMove()
81 | cookie.set('bigtext', false, namespace)
82 | core.message.publish('bigTextState',false)
83 | }
84 | };
85 |
86 | export default BigText;
--------------------------------------------------------------------------------
/src/modules/TopBar/index.tmpl.js:
--------------------------------------------------------------------------------
1 | import reset from '../../assets/reset.png';
2 | import audio from '../../assets/audio.png';
3 | import speed from '../../assets/speed.png';
4 | import zoomout from '../../assets/zoomout.png';
5 | import zoomin from '../../assets/zoomin.png';
6 | import cursor from '../../assets/cursor.png';
7 | import pointer from '../../assets/pointer.png';
8 | import bigtext from '../../assets/bigtext.png';
9 | import pointeread from '../../assets/pointeread.png';
10 | import close from '../../assets/close.png';
11 |
12 | import resetHover from '../../assets/reset-hover.png';
13 | import audioHover from '../../assets/audio-hover.png';
14 | import speedHover from '../../assets/speed-hover.png';
15 | import zoomoutHover from '../../assets/zoomout-hover.png';
16 | import zoominHover from '../../assets/zoomin-hover.png';
17 | import cursorHover from '../../assets/cursor-hover.png';
18 | import pointerHover from '../../assets/pointer-hover.png';
19 | import bigtextHover from '../../assets/bigtext-hover.png';
20 | import pointereadHover from '../../assets/pointeread-hover.png';
21 | import closeHover from '../../assets/close-hover.png';
22 |
23 | import closeAudio from '../../assets/audio-close.png';
24 | import speedQuick from '../../assets/speed-quick.png';
25 |
26 | import closeAudioHover from '../../assets/audio-close-hover.png';
27 | import speedQuickHover from '../../assets/speed-quick-hover.png';
28 |
29 | const topBarHtml = (namespace) => {
30 | return `
31 |
32 |
重置
33 |

34 |
35 |
36 |
声音开关
37 |

38 |
39 |
40 |
语速
41 |

42 |
43 |
44 |
放大
45 |

46 |
47 |
48 |
缩小
49 |

50 |
51 |
52 |
鼠标样式
53 |

54 |
55 |
56 |
十字线
57 |

58 |
59 |
60 |
大字幕
61 |

62 |
63 |
64 |
指读
65 |

66 |
67 |
68 |
退出服务
69 |

70 |
71 |
`
72 | }
73 |
74 | export default topBarHtml;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 无障碍插件
2 | > 这是一个针对于 有视障、听说障碍、读写障碍、肢体障碍,机体功能衰退的老年人群开发的一个辅助插件使用网站的js插件
3 |
4 | **项目演示**
5 |
6 | ---
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ---
15 | ### 插件接入方式:
16 | * 1 - 在页面合适的地方如banner处加入id为 assist-open 的标签
17 | * 2 - 在页面底部 body 之前引入插件;
18 | * 3 - 如果需要特殊处理的地方使用后面的API做对应处理;
19 |
20 | ```
21 |
22 |
23 |
24 |
25 | 墨子工程
26 |
27 |
28 | 无障碍
29 |
30 |
31 |
32 | ```
33 |
34 | [开发者关注](./DEVELOPER.md "开发者关注")
35 |
36 | ## API
37 |
38 | - showTag; 用于打开无障碍标识,(点击无障碍后并不在当前页面打开,而是跳转到其他没有调用showTag的页面打开)
39 | ```
40 |
41 |
42 |
43 |
44 | 墨子工程
45 |
46 |
47 | 无障碍
48 |
49 |
54 |
55 |
56 | ```
57 | - zoomState; 返回页面放大倍数
58 | ```
59 |
60 |
61 |
62 |
63 | 墨子工程
64 |
65 |
66 | 无障碍
67 |
68 |
75 |
76 |
77 | ```
78 | - openState; 返回插件打开状态
79 |
80 | ```
81 |
82 |
83 |
84 |
85 | 墨子工程
86 |
87 |
88 | 无障碍
89 |
90 |
97 |
98 |
99 | ```
100 |
101 | - bigTextState; 大字幕开启状态
102 |
103 |
104 | ```
105 |
106 |
107 |
108 |
109 | 墨子工程
110 |
111 |
112 | 无障碍
113 |
114 |
121 |
122 |
123 | ```
124 |
125 |
126 | ### 页面标注:
127 | > 对于插件无法识别或识别不准的标签需业务自行标注,标注规范如下
128 |
129 | 1 - 对于img标签,需设置 alt ,如
130 |
131 | ```
132 |
133 |
134 |
135 |
136 | 墨子工程
137 |
138 |
139 |
140 |
141 |
142 | ```
143 |
144 | 2 - 对于其他标签,需使用 title 进行标注,如
145 |
146 | ```
147 |
148 |
149 |
150 |
151 |
152 | 墨子工程
153 |
154 |
155 |
156 | 墨子工程无障碍
157 |
158 |
159 |
160 | ```
161 |
162 | 3 - 对于非语意化标签,需加入 role来标注其真实属性,如果不标注title,则取标签内容,如
163 |
164 | ```
165 |
166 |
167 |
168 |
169 | 墨子工程
170 |
171 |
172 |
173 | 提交
174 |
175 |
176 |
177 | ```
178 |
179 | ### 隐藏模块:
180 | > 对业务中需要隐藏的模块加一个class名 qunar-assist-hide ,插件在打开的时候会自动监测这个class名统一隐藏
181 |
182 | ### 页面缩放影响:
183 | > 随着页面放大,部分非自适应或者绝对定位的组件可能会出现错位问题,需业务开发自行调整
184 |
185 | ### 大段文本识别:
186 | > 对于可能出现大段文本的地方,需要在当前标签加一个名为 qunar-assist-long-text 的class,插件会自动对这个class下的内容进行分割
187 |
188 |
189 |
190 |
191 |
192 | ### 兼容性
193 |
194 | - ie10+
195 | - 所有主流浏览器
196 | - 火狐(不支持页面放大功能)
197 |
--------------------------------------------------------------------------------
/src/modules/Audio/index.js:
--------------------------------------------------------------------------------
1 | import { cookie, ajax, addEvent, removeEvent, parseTagText, triggerEvent, trim } from '../utils'
2 | import audioTabText,{ symbolsReg } from '../constans'
3 |
4 | import styles from './index.scss'
5 | import tmpl from './index.tmpl.js'
6 | const Audio = {
7 | init(core) {
8 | const { namespace, url } = core.config
9 | this.body = document.body
10 | this.namespace = namespace
11 | this.AudioApi = url
12 | core.creatStyle('audio-style',styles)
13 | core.creatHtml('audio-html',tmpl)
14 | this.isAudio = cookie.get('audio',namespace)
15 | },
16 | setEvents(core) {
17 | const { namespace } = core.config
18 | this.registeDom(namespace)
19 | this.toggleAudio()
20 | if(this.isAudio) {
21 | this.addEventMove()
22 | addEvent(document,'click',this.forceSafariPlayAudio) // 苹果浏览器需要用户跟浏览器有个交互才可以播放语音
23 | } else {
24 | this.audioTabImg.src = this.audioTabImg.getAttribute('selected-src')
25 | }
26 |
27 | if(this.speed == 'fast') {
28 | this.speedTabImg.src = this.speedTabImg.getAttribute('selected-src')
29 | } else {
30 | this.speedTabImg.src = this.speedTabImg.getAttribute('source-src')
31 | }
32 | },
33 | registeDom(namespace) {
34 | this.audio = document.getElementById(`${namespace}-audio-media`) || ''
35 | this.audioTab = document.getElementById(`${namespace}-audio`) || ''
36 | this.audioTabImg = this.audioTab.getElementsByTagName('img')[0]
37 |
38 | this.speed = cookie.get('speed',namespace)
39 | this.speedTab = document.getElementById(`${namespace}-audio-speed`) || ''
40 | this.speedTabImg = this.speedTab.getElementsByTagName('img')[0]
41 |
42 | this.pointeReadTab = document.getElementById(`${namespace}-pointeread`) || ''
43 | },
44 | toggleAudio() {
45 | const { namespace } = Audio
46 | this.audioTab.onclick = () => {
47 | if(this.isAudio) {
48 | this.closeAudio()
49 | }else {
50 | this.showAudio()
51 | Audio.playAudio(audioTabText.audioOpen)
52 | }
53 | }
54 |
55 | this.speedTab.onclick = () => {
56 | if(this.speed == 'middle') {
57 | this.speed = 'fast'
58 | this.speedTabImg.src = this.speedTabImg.getAttribute('selected-src')
59 | Audio.playAudio(audioTabText.speedQuick)
60 | } else {
61 | this.speed = 'middle'
62 | this.speedTabImg.src = this.speedTabImg.getAttribute('source-src')
63 | Audio.playAudio(audioTabText.speedMiddle)
64 | }
65 | cookie.set('speed', this.speed, namespace)
66 | }
67 |
68 | this.pointeReadTab.onclick = () => {
69 | this.showAudio();
70 | Audio.playAudio(audioTabText.pointeread)
71 | }
72 |
73 |
74 |
75 | },
76 | showAudio() {
77 | const { namespace } = Audio
78 | this.isAudio = true
79 | this.addEventMove()
80 | cookie.set('audio', true, namespace)
81 | this.audioTabImg.src = this.audioTabImg.getAttribute('source-src')
82 | },
83 | closeAudio() {
84 | const { namespace } = Audio
85 | this.isAudio = false
86 | this.audio.pause()
87 | this.removeEventMove()
88 | cookie.set('audio', false, namespace)
89 | this.audioTabImg.src = this.audioTabImg.getAttribute('selected-src')
90 | },
91 | addEventMove() {
92 | addEvent(this.body,'mouseover',this.mouseOver)
93 | },
94 | removeEventMove() {
95 | removeEvent(this.body,'mouseover',this.mouseOver)
96 | },
97 | forceSafariPlayAudio() {
98 | const { audio } = Audio
99 | audio.load();
100 | audio.play();
101 | },
102 | mouseOver(event){
103 | var event = window.event || event;
104 | var target = event.target || event.srcElement;
105 | var __text = parseTagText(target).replace(symbolsReg,'')
106 | var __parentNodeId = target.parentNode.id
107 | var __isAssist = __parentNodeId.indexOf(Audio.namespace) > -1
108 |
109 | if(__text == '' || trim(__text) == '文本' || __isAssist ) {
110 | return
111 | }
112 | Audio.playAudio(__text)
113 | },
114 | playAudio(text) {
115 | const { namespace, AudioApi, isAudio, audio, speed, forceSafariPlayAudio } = Audio
116 |
117 | if(!isAudio) {
118 | return
119 | }
120 |
121 | let __speed = speed == 'middle' ? 5 : 7
122 | let AudioParam = `lan=zh&ie=UTF-8&spd=${__speed}&text=${encodeURI(text)}`
123 | let AudioUrl = `${AudioApi}?${AudioParam}`
124 | audio.src = AudioUrl
125 | document.getElementById(`${namespace}-audio-source`).src = AudioUrl
126 | document.getElementById(`${namespace}-audio-embed`).src = AudioUrl
127 | let playPromise = audio.play();
128 | if(playPromise) {
129 | playPromise.then(_ => {
130 | // audio.pause();
131 | removeEvent(document,'click', forceSafariPlayAudio)
132 | })
133 | .catch(error => {
134 | console.log(error)
135 | });
136 | }
137 | },
138 | reset() {
139 | const { namespace } = Audio
140 | this.closeAudio()
141 | this.speedTabImg.src = this.speedTabImg.getAttribute('source-src')
142 | this.speed = 'middle'
143 | cookie.set('speed', 'middle', namespace)
144 | }
145 |
146 | };
147 |
148 | export default Audio;
--------------------------------------------------------------------------------
/src/modules/base.js:
--------------------------------------------------------------------------------
1 | import { cookie , addEvent, removeEvent } from './utils'
2 | import pubSub from './pubSub'
3 |
4 | export default class Base {
5 | constructor() {
6 | this.config = {
7 | namespace: 'mozi-assist',
8 | domain: '.mozi.com',
9 | url: ''
10 | };
11 | this.message = pubSub
12 | this.tmplStyle = []
13 | this.tmplHtml = []
14 | this.registeOpen()
15 |
16 | }
17 |
18 | mergeConfig(opts) {
19 | this.config = { ...this.config, ...opts };
20 | this.creatContainer()
21 | }
22 |
23 | use(plugin, ...args) {
24 | plugin.init(this, ...args);
25 | }
26 |
27 | useEvent(plugin, ...args) {
28 | plugin.setEvents(this, ...args);
29 | }
30 |
31 | creatContainer() {
32 | const { namespace } = this.config
33 | if(document.getElementById(namespace)) {
34 | return
35 | }
36 | const Container = document.createElement("div");
37 | Container.id = namespace
38 | document.body.appendChild(Container)
39 |
40 | }
41 |
42 | registeOpen() {
43 | addEvent(document,'click',(event)=>{
44 | var event = window.event || event;
45 | var target = event.target || event.srcElement;
46 | if(target.getAttribute('id') == 'assist-open') {
47 | if(!this.existIgnore()) {
48 | this.show()
49 | this.message.publish('openState',true)
50 | } else {
51 | const { namespace } = this.config
52 | cookie.set('show',true, namespace)
53 | const __href = document.getElementById('assist-open').getAttribute('assist-href')
54 | window.location.href = __href
55 | }
56 | }
57 | })
58 | }
59 |
60 | isShow() {
61 | const { namespace } = this.config
62 | addEvent(window,'DOMContentLoaded',()=>{
63 | if(cookie.get('show',namespace) && !this.existIgnore()) {
64 | this.isShowTopBar(true)
65 | this.message.publish('openState',true)
66 | } else {
67 | this.message.publish('openState',false)
68 | }
69 | })
70 | }
71 |
72 | existIgnore() {
73 | const { namespace } = this.config
74 | const { origin, pathname } = location
75 | const __key = `${origin}${pathname}`
76 | return cookie.getTag(namespace).includes(__key)
77 | }
78 |
79 | show() {
80 | this.isShowTopBar(true)
81 | }
82 |
83 | close() {
84 | this.isShowTopBar(false)
85 | }
86 |
87 | showTag() {
88 | const { namespace } = this.config
89 | cookie.setTag(namespace) // 设置忽略
90 | this.resetAction() // 重置插件状态
91 | }
92 |
93 | isShowTopBar(isShow) {
94 | const { namespace } = this.config
95 | const activeBtn = document.getElementById(`${namespace}-topbar-html`)
96 | if(isShow) {
97 | document.body.style.marginTop = '100px'
98 | activeBtn.style.display = 'block'
99 | cookie.set('show',true, namespace)
100 | this.hideModules()
101 | } else {
102 | document.body.style.cssText = ''
103 | //activeBtn.style.display = 'none'
104 | cookie.remove(`${namespace}`)
105 | location.reload()
106 | }
107 |
108 | }
109 |
110 | hideModules() {
111 | const { namespace } = this.config
112 | const classList = document.getElementsByClassName(`${namespace}-hide`)
113 | for(let i=0;i< classList.length;i++){
114 | classList[i].style.display = 'none'
115 | }
116 | }
117 |
118 | creatStyle(id, css, flag = false) {
119 | if(!flag) {
120 | this.tmplStyle.push(css)
121 | } else {
122 | const { namespace } = this.config
123 | let styleNode = document.createElement('style')
124 | styleNode.type = 'text/css'
125 | styleNode.id = `${namespace}-${id}`
126 | styleNode.className = id
127 | if(styleNode.styleSheet) {
128 | styleNode.styleSheet.cssText = css;
129 | } else {
130 | styleNode.innerHTML = css
131 | }
132 | document.getElementsByTagName('head')[0].appendChild(styleNode);
133 | }
134 | }
135 |
136 | creatHtml(id,htmlFn) {
137 | const { namespace } = this.config
138 | const DomContainer = document.createElement("div");
139 | DomContainer.id = `${namespace}-${id}`
140 | DomContainer.className = id
141 | DomContainer.style.display = 'none'
142 | if(typeof(htmlFn) !== 'function') {
143 | console.error('htmlFn不是一个函数')
144 | return
145 | }
146 | const __html = htmlFn(namespace)
147 | DomContainer.innerHTML = __html
148 | this.tmplHtml.push(DomContainer.outerHTML)
149 | }
150 |
151 | registeHtml() {
152 | const { namespace } = this.config
153 | document.getElementById(namespace).innerHTML = this.tmplHtml.join('')
154 | }
155 |
156 | registeStyle() {
157 | const { namespace } = this.config
158 | let styleNode = document.createElement('style')
159 | styleNode.type = 'text/css'
160 | styleNode.id = `${namespace}-style`
161 | let __css = this.tmplStyle.join('\n')
162 | if(styleNode.styleSheet) {
163 | styleNode.styleSheet.cssText = __css;
164 | } else {
165 | styleNode.innerHTML = __css
166 | }
167 | document.getElementsByTagName('head')[0].appendChild(styleNode);
168 | }
169 |
170 | formatLongText() {
171 | const { namespace } = this.config
172 | const longText = document.getElementsByClassName(`${namespace}-long-text`) || [];
173 | [].forEach.call( longText, (el)=> {
174 | const __el = el.innerText.split('。')
175 | let __elItem = []
176 | __el.map(item=> {
177 | __elItem.push(``)
178 | })
179 | el.innerHTML = __elItem.join('。')
180 | });
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/src/modules/utils.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 | import config from '../config.json';
3 | const __domain = config.domain
4 | const cookie = {
5 | set:(key,value, namespace) => {
6 | let memory = {
7 | show: false, // 是否展示无障碍
8 | audio: false, // 是否开启声音
9 | speed: 'middle', // 语速
10 | zomm: 0.1, // 缩放倍数
11 | cursor: false, // 是否替换鼠标样式
12 | pointer: false,// 是否开启十字线
13 | bigtext: false,// 是否开启大字幕
14 | overead: false // 是否开启指读
15 | }
16 |
17 | if(Cookies.get(namespace)) {
18 | memory = JSON.parse(Cookies.get(namespace))
19 | }
20 | memory[key] = value
21 | Cookies.set(namespace, JSON.stringify(memory) , { domain: __domain })
22 | },
23 | get:(key, namespace)=> {
24 | let __key = ''
25 | if(Cookies.get(namespace)) {
26 | __key = JSON.parse(Cookies.get(namespace))[key]
27 | }
28 | return __key
29 | },
30 | remove: (namespace) => {
31 | Cookies.remove(namespace, { domain: __domain})
32 | },
33 | setTag: (namespace) => {
34 | const __key = `${namespace}-ignore`
35 | let __data = []
36 | if(Cookies.get(__key)) {
37 | __data = JSON.parse(Cookies.get(__key))
38 | }
39 | const { origin, pathname } = location
40 | const __ignoreUrl = `${origin}${pathname}`
41 | !__data.includes(__ignoreUrl) && __data.push(`${origin}${pathname}`)
42 | Cookies.set(__key, JSON.stringify(__data) , { domain: __domain })
43 | },
44 | getTag: (namespace) => {
45 | const __key = `${namespace}-ignore`
46 | let __data = []
47 | if(Cookies.get(__key)) {
48 | __data = JSON.parse(Cookies.get(__key))
49 | }
50 | return __data
51 | }
52 | }
53 |
54 | const addEvent = (element, type, callback) => {
55 | const ignore = ['DOMContentLoaded']
56 | let __type = ignore.includes(type) ? type : 'on' + type
57 | if(element.addEventListener){
58 | element.addEventListener(type, callback, false);
59 | } else if(element.attachEvent){
60 | element.attachEvent(__type, callback);
61 | } else {
62 | element[__type] = callback;
63 | }
64 | }
65 |
66 | const removeEvent = (element, type, callback) => {
67 | const ignore = ['DOMContentLoaded']
68 | let __type = ignore.includes(type) ? type : 'on' + type
69 | if(element.removeEventListener){
70 | element.removeEventListener(type, callback);
71 | } else if(element.detachEvent){
72 | element.detachEvent(__type, callback);
73 | } else {
74 | element[__type] = null;
75 | }
76 | }
77 | const ruleType = (target) => {
78 | const __role = !!target.getAttribute('role') && target.getAttribute('role').toUpperCase() || target.tagName.toUpperCase()
79 |
80 | const __roleName = {
81 | IMG: '图片',
82 | BUTTON: '按钮',
83 | INPUT: '输入框',
84 | CHECKBOX: '复选框',
85 | RADIO: '单选框',
86 | OPTION: '下拉框',
87 | A: '链接'
88 | }
89 | if(__role == 'INPUT') {
90 | if(target.type == 'radio') {
91 | return '单选框';
92 | }else if(target.type == 'checkbox') { // button reset file
93 | return '复选框';
94 | } else if(target.type == 'text') { // button reset file
95 | return '文本框';
96 | } else if(target.type == 'submit') {
97 | return '提交按钮';
98 | } else if(target.type == 'reset') {
99 | return '重置按钮';
100 | } else if(target.type == 'password') {
101 | return '密码输入框';
102 | } else {
103 | return '输入框';
104 | }
105 | }
106 | return __roleName[__role] || '文本'
107 | }
108 |
109 | const parseTagText = (target) => {
110 | const __name = ruleType(target)
111 | const __role = !!target.getAttribute('role') && target.getAttribute('role').toUpperCase()
112 |
113 | if (__role === 'A' || target.tagName === 'A') {
114 | console.log('这是一个链接:' + target.alt || target.title || target.innerText);
115 | return `链接 ${target.alt || target.title || target.innerText}`;
116 | }
117 |
118 | if (target.children.length === 0){
119 | if (__role === 'IMG' ||target.tagName === 'IMG') {
120 | console.log('这是一张图片:' + target.alt || target.title);
121 | return `图片 ${target.alt || target.title}`;
122 | }
123 | if (__role === 'BUTTON' ||target.tagName === 'BUTTON') {
124 | console.log('这是一个按钮:' + target.innerText);
125 | return `按钮 ${target.alt || target.title || target.innerText}`;
126 | }
127 | if (__role === 'INPUT' ||target.tagName === 'INPUT') {
128 | console.log(`这是一个${__name}:` + target.alt || target.title || target.value);
129 | return `${__name} ${target.alt || target.title || target.value}`;
130 | }
131 |
132 | if (__role === 'LABEL' ||target.tagName === 'LABEL') {
133 | const __linkId = target.getAttribute('for')
134 | const __linkDom = document.getElementById(__linkId)
135 | if(!!__linkDom && !!__linkDom.type && __linkDom.type == 'radio') {
136 | console.log(`这是一个单选:` + target.alt || target.title || target.innerText);
137 | return `单选 ${target.alt || target.title || target.innerText}`;
138 | }
139 | }
140 |
141 | if (target.alt || target.title || target.innerText){
142 | console.log(`${__name} ${target.alt || target.title || target.innerText}`);
143 | return `${__name} ${target.alt || target.title || target.innerText}`;
144 | }
145 | return ''
146 | }
147 |
148 | if (target.children.length < 5 && (target.alt || target.title || target.innerText)){
149 | console.log(`${__name} ${target.alt || target.title || target.innerText}`);
150 | return `${__name} ${target.alt || target.title || target.innerText}`;
151 | }
152 |
153 | return ''
154 |
155 | }
156 |
157 | const trim = (s) => {
158 | return s.replace(/(^\s*)|(\s*$)/g, "");
159 | }
160 |
161 | const triggerEvent = (element, eventType) =>{
162 | var e;
163 | if(element.dispatchEvent){//正常情况
164 | e = new Event(eventType);
165 | element.dispatchEvent(e);
166 | }else if(element.fireEvent){//IE
167 | e = document.createEventObject();
168 | e.button = 1;
169 | element.fireEvent('on'+eventType,e);
170 | }else if(element['on'+eventType]){
171 | element['on'+eventType].call();
172 | }
173 | }
174 |
175 | const ajax = {
176 | get: (url, fn) => {
177 | // XMLHttpRequest对象用于在后台与服务器交换数据
178 | var xhr = new XMLHttpRequest();
179 | xhr.open('GET', url, true);
180 | xhr.onreadystatechange = () => {
181 | // readyState == 4说明请求已完成
182 | if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) {
183 | // 从服务器获得数据
184 | fn(xhr.responseText);
185 | }
186 | };
187 | xhr.send();
188 | },
189 | // datat应为'a=a1&b=b1'这种字符串格式,在jq里如果data为对象会自动将对象转成这种字符串格式
190 | post: (url, data, fn) => {
191 | var xhr = new XMLHttpRequest();
192 | xhr.open("POST", url, true);
193 | // 添加http头,发送信息至服务器时内容编码类型
194 | xhr.setRequestHeader("Content-Type", "application/json");
195 | xhr.onreadystatechange = () => {
196 | if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
197 | fn(xhr.responseText);
198 | }
199 | };
200 | xhr.send(data);
201 | }
202 | }
203 |
204 | /**
205 | * 判断是否是IE
206 | */
207 | const isIE = () => {
208 | if (!!window.ActiveXobject || "ActiveXObject" in window) {
209 | return true;
210 | } else {
211 | return false;
212 | }
213 | }
214 | /**
215 | * 判断是否是IE11
216 | */
217 | const isIE11 = () => {
218 | if((/Trident\/7\./).test(navigator.userAgent)) {
219 | return true;
220 | } else {
221 | return false;
222 | }
223 | }
224 |
225 | const isFirefox = () => {
226 | const ua = navigator.userAgent
227 | if(ua.indexOf('Firefox') > -1) {
228 | return true
229 | }
230 | return false
231 | }
232 |
233 | const removeNode = (item) => {
234 | if( isIE()||isIE11() ) {
235 | item.removeNode(true);
236 | } else {
237 | item.remove();
238 | }
239 | }
240 | export {
241 | cookie,
242 | addEvent,
243 | removeEvent,
244 | parseTagText,
245 | ajax,
246 | triggerEvent,
247 | removeNode,
248 | isFirefox,
249 | trim
250 | };
--------------------------------------------------------------------------------