wbf
Version:
[](./LICENSE) [](https://github.com/halodong/web-barrier
359 lines (346 loc) • 13.8 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Wbf = factory());
})(this, (function () { 'use strict';
const defaultOptions = {
language: 'zh-CN',
rate: 1,
pitch: 1,
volume: 1
};
const showBarDomId = '$$wsashowbar';
const consoleDomId = '$$wsaConsole';
const emphasizeClassName = 'emphasizeStyle';
const consoleClassName = 'consoleEl';
const optionsArr = ['language', 'rate', 'pitch', 'volume'];
const cnGather = {
a: '链接',
img: '图片',
nav: '链接',
close: '关闭',
continuousRead: '连读',
fingerRead: '指读',
volume: '音量',
rate: '语速'
};
const enGather = {
a: 'Link',
img: 'Image',
nav: 'Link',
close: 'Close',
continuousRead: 'ContinuousRead',
fingerRead: 'FingerRead',
volume: 'Volume',
rate: 'Rate'
};
const lowerCaseImgTagName = 'img';
const modes = ['finger', 'continuous'];
const getGather = (language) => {
let gather = cnGather;
if (language === 'en') {
gather = enGather;
}
return gather;
};
const getElText = (el, language) => {
const tag = descriptionTag(el.tagName, language);
const notContainChildText = getNotContainChildText(el);
const text = tag !== null ? `${tag}: ${notContainChildText}` : notContainChildText;
return text;
};
const descriptionTag = (tagName, language) => {
const tag = tagName.toLowerCase();
const gather = getGather(language);
return gather[tag] !== undefined ? gather[tag] : null;
};
const getNotContainChildText = (el) => {
if (el.tagName.toLowerCase() === lowerCaseImgTagName) {
return el.alt;
}
const notContainChildText = Array.prototype.filter
.call(el.childNodes, (node) => node.nodeType === 3)
.map((node) => node.nodeValue.trim())
.join('');
return notContainChildText;
};
const testReadMode = (mode) => {
return Array.prototype.includes.call(modes, mode);
};
const overHandler = (e, wbf) => {
const notContainChildText = getNotContainChildText(e.target);
if (notContainChildText.length === 0)
return;
if (e.target !== document.body && e.target.tagName.toLowerCase() !== 'html' &&
e.target.id !== showBarDomId) {
wbf.emphasize(e.target);
const text = getElText(e.target, wbf.language);
wbf.readMode === 'finger' && wbf.playAudio(text);
if (wbf.showBarEl != null) {
if (text.length > 150) {
wbf.showBarEl.style.fontSize = '24px';
}
else if (text.length > 100) {
wbf.showBarEl.style.fontSize = '26px';
}
else if (text.length > 50) {
wbf.showBarEl.style.fontSize = '28px';
}
else if (text.length > 20) {
wbf.showBarEl.style.fontSize = '30px';
}
else {
wbf.showBarEl.style.fontSize = '32px';
}
wbf.showBarEl.innerText = text;
}
}
};
const outHandler = (e, wbf) => {
wbf.removeEmphasize(e.target);
};
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = ".emphasizeStyle {\r\n background: black !important;\r\n color: white !important;\r\n}\r\n\r\n.consoleEl {\r\n padding: 10px;\r\n z-index: 9999;\r\n border-bottom: 1px #2f5bb7 solid;\r\n}\r\n\r\n.consoleEl .consoleEl-main {\r\n display: flex;\r\n justify-content: space-around;\r\n flex-wrap: wrap;\r\n margin: 0 auto;\r\n width: 50vw;\r\n}\r\n@media (max-width: 750px) {\r\n .consoleEl .consoleEl-main {\r\n width: 100vw;\r\n }\r\n}\r\n.consoleEl button {\r\n color: white;\r\n background: #4c8ffb;\r\n padding: 5px 10px;\r\n border-radius: 2px;\r\n font-weight: bold;\r\n font-size: 9pt;\r\n outline: none;\r\n box-shadow: inset 0 1px 0 #80b0fb;\r\n}\r\n\r\n.consoleEl button:hover {\r\n border: 1px #2f5bb7 solid;\r\n box-shadow: 0 1px 1px #eaeaea, inset 0 1px 0 #5a94f1;\r\n background: #3f83f1;\r\n}\r\n\r\n.consoleEl #_wbfClose {\r\n border: 1px #f0120b solid;\r\n background-color: #d1341f;\r\n}\r\n.consoleEl #_wbfClose:hover {\r\n background-color: #ad2210;\r\n}\r\n";
styleInject(css_248z);
let instance = null;
let compatible = true;
class Wbf {
opening = false;
readMode = 'finger';
language;
rate;
pitch;
volume;
showBarEl = null;
needConsole = true;
overHandler;
outHandler;
static getInstance = (options) => {
if (instance === null) {
instance = new Wbf(options);
}
return instance;
};
static clearInstance = () => {
instance = null;
};
constructor(options) {
if (typeof SpeechSynthesisUtterance === 'undefined' || typeof speechSynthesis === 'undefined') {
compatible = false;
console.warn('Current browser does not support SpeechSynthesisUtterance and speechSynthesis');
}
if (options == null)
options = defaultOptions;
options?.readMode !== undefined && (this.readMode = options.readMode);
options?.needConsole !== undefined &&
(this.needConsole = options.needConsole);
this.language = options?.language ?? defaultOptions.language;
this.rate = options?.rate ?? defaultOptions.rate;
this.pitch = options?.pitch ?? defaultOptions.pitch;
this.volume = options?.volume ?? defaultOptions.volume;
this.overHandler = (e) => overHandler(e, this);
this.outHandler = (e) => outHandler(e, this);
if (instance != null) {
instance = this;
console.warn('There are currently multiple wbf instances');
}
}
open() {
if (this.opening)
return;
this.changeMode(this.readMode);
if (this.showBarEl == null) {
const showBar = this.createShowBarDom();
this.showBarEl = showBar;
}
this.addHandler();
this.opening = true;
this.needConsole && this.createConsole();
}
close() {
const emphasizeEls = document.querySelectorAll(`.${emphasizeClassName}`);
emphasizeEls.forEach((el) => {
this.removeEmphasize(el);
});
compatible && window.speechSynthesis?.cancel();
document.removeEventListener('mouseover', this.overHandler);
document.removeEventListener('mouseout', this.outHandler);
this.removeShowBarDom();
this.removeConsole();
this.opening = false;
}
setOption(keyName, value) {
if (optionsArr.includes[keyName] === false && this[keyName] !== undefined) {
throw new Error(`${keyName} options do not exist on wbf`);
}
if (keyName === 'opening')
throw new Error(`${keyName} cannot be changed `);
switch (keyName) {
case 'rate':
if (value > 10)
value = 10;
if (value < 0.1)
value = 0.1;
break;
case 'pitch':
if (value > 2)
value = 2;
if (value < 0)
value = 0;
break;
case 'volume':
if (value > 1)
value = 1;
if (value < 0)
value = 0;
break;
}
this[keyName] = value;
}
changeMode(readMode) {
if (!testReadMode(readMode)) {
throw new Error(`readMode not includes this ${readMode}`);
}
this.readMode = readMode;
if (readMode !== 'finger') {
const allText = document.body.innerText;
this.playAudio(allText);
}
}
playAudio(str) {
if (!compatible)
return;
window.speechSynthesis?.cancel();
const msg = this.createUtterance(str);
window.speechSynthesis?.speak(msg);
return msg;
}
emphasize(el) {
el.classList.add(emphasizeClassName);
}
removeEmphasize(el) {
el.classList.remove(emphasizeClassName);
}
addHandler() {
document.addEventListener('mouseover', this.overHandler);
document.addEventListener('mouseout', this.outHandler);
}
createUtterance(str) {
if (!compatible)
return;
const msg = new SpeechSynthesisUtterance();
msg.text = str;
msg.lang = this.language;
msg.pitch = this.pitch;
msg.rate = this.rate;
msg.volume = this.volume;
return msg;
}
createShowBarDom() {
const prev = document.getElementById(showBarDomId);
if (prev != null)
return prev;
const showBar = document.createElement('div');
showBar.id = showBarDomId;
showBar.style.position = 'fixed';
showBar.style.bottom = '0px';
showBar.style.left = '0px';
showBar.style.width = '100%';
showBar.style.minHeight = '50px';
showBar.style.maxHeight = '300px';
showBar.style.fontWeight = 'bold';
showBar.style.textAlign = 'center';
showBar.style.wordBreak = 'break-word;';
showBar.style.overflow = 'hidden';
showBar.style.background = 'white';
showBar.style.border = '2px solid #eee';
document.body.appendChild(showBar);
return showBar;
}
createConsole() {
const prev = document.getElementById(consoleDomId);
if (prev != null)
return;
const consoleEl = document.createElement('div');
consoleEl.id = consoleDomId;
const gather = getGather(this.language);
consoleEl.classList.add(consoleClassName);
consoleEl.innerHTML = `
<div class="${consoleClassName}-main">
<div>
<button id="_wbfClose">${gather.close}</button>
<button id="_wbfContinuousRead">${gather.continuousRead}</button>
<button id="_wbfFingerRead">${gather.fingerRead}</button>
</div>
|
<div>
${gather.volume}
<button id="_wbfAddVolume">+</button>
<button id="_wbfReduceVolume">-</button>
</div>
|
<div>
${gather.rate}
<button id="_wbfAddRate">+</button>
<button id="_wbfReduceRate">-</button>
</div>
</div>`;
document.body.insertBefore(consoleEl, document.body.firstChild);
const closeBtn = document.getElementById('_wbfClose');
const continuousReadBtn = document.getElementById('_wbfContinuousRead');
const fingerReadBtn = document.getElementById('_wbfFingerRead');
const addVolumeBtn = document.getElementById('_wbfAddVolume');
const reduceVolumeBtn = document.getElementById('_wbfReduceVolume');
const addRateBtn = document.getElementById('_wbfAddRate');
const reduceRateBtn = document.getElementById('_wbfReduceRate');
closeBtn != null && (closeBtn.onclick = () => this.close());
continuousReadBtn != null &&
(continuousReadBtn.onclick = () => this.changeMode('continuous'));
fingerReadBtn != null &&
(fingerReadBtn.onclick = () => this.changeMode('finger'));
addVolumeBtn != null &&
(addVolumeBtn.onclick = () => this.setOption('volume', this.volume + 0.1));
reduceVolumeBtn != null &&
(reduceVolumeBtn.onclick = () => this.setOption('volume', this.volume - 0.1));
addRateBtn != null &&
(addRateBtn.onclick = () => this.setOption('rate', this.rate + 0.1));
reduceRateBtn != null &&
(reduceRateBtn.onclick = () => this.setOption('rate', this.rate - 0.1));
}
removeConsole() {
const consoleEl = document.getElementById(consoleDomId);
if (consoleEl != null) {
consoleEl.remove();
}
}
removeShowBarDom() {
if (this.showBarEl != null) {
this.showBarEl.remove();
this.showBarEl = null;
}
}
}
return Wbf;
}));
//# sourceMappingURL=index.js.map