fix: support browsers dont support regexp positive lookbehind
This commit is contained in:
parent
47d85d752f
commit
5a7182fcca
5 changed files with 669 additions and 677 deletions
|
@ -163,6 +163,11 @@
|
||||||
*/
|
*/
|
||||||
function Finder(node, options) {
|
function Finder(node, options) {
|
||||||
|
|
||||||
|
// Add offset to fix browsers which don't support regex lookbehind.
|
||||||
|
if (!options.offset) {
|
||||||
|
options.offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
var preset = options.preset && exposed.PRESETS[options.preset];
|
var preset = options.preset && exposed.PRESETS[options.preset];
|
||||||
|
|
||||||
options.portionMode = options.portionMode || PORTION_MODE_RETAIN;
|
options.portionMode = options.portionMode || PORTION_MODE_RETAIN;
|
||||||
|
@ -349,12 +354,12 @@
|
||||||
endPortion = {
|
endPortion = {
|
||||||
node: curNode,
|
node: curNode,
|
||||||
index: portionIndex++,
|
index: portionIndex++,
|
||||||
text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex),
|
text: curNode.data.substring(match.startIndex - atIndex + this.options.offset, match.endIndex - atIndex),
|
||||||
|
|
||||||
// If it's the first match (atIndex==0) we should just return 0
|
// If it's the first match (atIndex==0) we should just return 0
|
||||||
indexInMatch: atIndex === 0 ? 0 : atIndex - match.startIndex,
|
indexInMatch: atIndex === 0 ? 0 : atIndex - match.startIndex,
|
||||||
|
|
||||||
indexInNode: match.startIndex - atIndex,
|
indexInNode: match.startIndex - atIndex + this.options.offset,
|
||||||
endIndexInNode: match.endIndex - atIndex,
|
endIndexInNode: match.endIndex - atIndex,
|
||||||
isEnd: true
|
isEnd: true
|
||||||
};
|
};
|
||||||
|
@ -376,9 +381,9 @@
|
||||||
node: curNode,
|
node: curNode,
|
||||||
index: portionIndex++,
|
index: portionIndex++,
|
||||||
indexInMatch: 0,
|
indexInMatch: 0,
|
||||||
indexInNode: match.startIndex - atIndex,
|
indexInNode: match.startIndex - atIndex + this.options.offset,
|
||||||
endIndexInNode: match.endIndex - atIndex,
|
endIndexInNode: match.endIndex - atIndex,
|
||||||
text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex)
|
text: curNode.data.substring(match.startIndex - atIndex + this.options.offset, match.endIndex - atIndex)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,52 +660,42 @@
|
||||||
const N = '0-9';
|
const N = '0-9';
|
||||||
const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?';
|
const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?';
|
||||||
const ANS = `${A}${N}${S}`;
|
const ANS = `${A}${N}${S}`;
|
||||||
const HETI_NON_CONTIGUOUS_ELEMENTS = {
|
const HETI_NON_CONTIGUOUS_ELEMENTS = Object.assign({}, findAndReplaceDOMText.NON_CONTIGUOUS_PROSE_ELEMENTS, {
|
||||||
// Block Elements
|
|
||||||
address: 1, article: 1, aside: 1, blockquote: 1, dd: 1, div: 1,
|
|
||||||
dl: 1, fieldset: 1, figcaption: 1, figure: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1,
|
|
||||||
h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1, hr: 1, main: 1, nav: 1, noscript: 1, ol: 1,
|
|
||||||
output: 1, p: 1, pre: 1, section: 1, ul: 1,
|
|
||||||
// Other misc. elements that are not part of continuous inline prose:
|
|
||||||
br: 1, li: 1, summary: 1, dt: 1, details: 1, rp: 1, rt: 1, rtc: 1,
|
|
||||||
// Media / Source elements:
|
|
||||||
script: 1, style: 1, img: 1, video: 1, audio: 1, canvas: 1, svg: 1, map: 1, object: 1,
|
|
||||||
// Input elements
|
|
||||||
input: 1, textarea: 1, select: 1, option: 1, optgroup: 1, button: 1,
|
|
||||||
// Table related elements:
|
|
||||||
table: 1, tbody: 1, thead: 1, th: 1, tr: 1, td: 1, caption: 1, col: 1, tfoot: 1, colgroup: 1,
|
|
||||||
// Inline elements
|
// Inline elements
|
||||||
ins: 1, del: 1, s: 1,
|
ins: 1, del: 1, s: 1,
|
||||||
};
|
});
|
||||||
const HETI_SKIPPED_ELEMENTS = {
|
const HETI_SKIPPED_ELEMENTS = Object.assign({}, findAndReplaceDOMText.NON_PROSE_ELEMENTS, {
|
||||||
br: 1, hr: 1,
|
|
||||||
// Media / Source elements:
|
|
||||||
script: 1, style: 1, img: 1, video: 1, audio: 1, canvas: 1, svg: 1, map: 1, object: 1,
|
|
||||||
// Input elements:
|
|
||||||
input: 1, textarea: 1, select: 1, option: 1, optgroup: 1, button: 1,
|
|
||||||
// Pre elements:
|
|
||||||
pre: 1, code: 1, sup: 1, sub: 1,
|
pre: 1, code: 1, sup: 1, sub: 1,
|
||||||
// Heti elements
|
// Heti elements
|
||||||
'heti-spacing': 1,
|
'heti-spacing': 1,
|
||||||
};
|
});
|
||||||
const HETI_SKIPPED_CLASS = 'heti-skip';
|
const HETI_SKIPPED_CLASS = 'heti-skip';
|
||||||
const hasOwn = {}.hasOwnProperty;
|
const hasOwn = {}.hasOwnProperty;
|
||||||
|
const REG_FULL = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`;
|
||||||
|
const REG_FULL_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`;
|
||||||
|
const REG_START = `([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`;
|
||||||
|
const REG_END = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`;
|
||||||
|
const REG_END_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`;
|
||||||
|
|
||||||
class Heti {
|
class Heti {
|
||||||
constructor (rootSelector) {
|
constructor (rootSelector) {
|
||||||
|
let supportLookBehind = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new RegExp(`(?<=\d)\d`, 'g').test('');
|
new RegExp(`(?<=\d)\d`, 'g').test('');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(err.name, '浏览器尚未实现 RegExp positive lookbehind');
|
console.info(err.name, '该浏览器尚未实现 RegExp positive lookbehind');
|
||||||
return
|
supportLookBehind = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rootSelector = rootSelector || '.heti';
|
this.rootSelector = rootSelector || '.heti';
|
||||||
this.REG_FULL = new RegExp(`(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`, 'g');
|
this.REG_FULL = new RegExp(supportLookBehind ? REG_FULL : REG_FULL_FIX, 'g');
|
||||||
this.REG_START = new RegExp(`([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`, 'g');
|
this.REG_START = new RegExp(REG_START, 'g');
|
||||||
this.REG_END = new RegExp(`(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`, 'g');
|
this.REG_END = new RegExp(supportLookBehind ? REG_END : REG_END_FIX, 'g');
|
||||||
|
this.offsetWidth = supportLookBehind ? 0 : 1;
|
||||||
this.funcForceContext = function forceContext (el) {
|
this.funcForceContext = function forceContext (el) {
|
||||||
return hasOwn.call(HETI_NON_CONTIGUOUS_ELEMENTS, el.nodeName.toLowerCase())
|
return hasOwn.call(HETI_NON_CONTIGUOUS_ELEMENTS, el.nodeName.toLowerCase())
|
||||||
|
// return true
|
||||||
};
|
};
|
||||||
this.funcFilterElements = function filterElements (el) {
|
this.funcFilterElements = function filterElements (el) {
|
||||||
return (
|
return (
|
||||||
|
@ -728,19 +723,21 @@
|
||||||
return $$r
|
return $$r
|
||||||
};
|
};
|
||||||
|
|
||||||
findAndReplaceDOMText($$elm, Object.assign(commonConfig, {
|
findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, {
|
||||||
find: this.REG_FULL,
|
find: this.REG_FULL,
|
||||||
replace: portion => getWrapper('heti-spacing-start heti-spacing-end', portion.text),
|
replace: portion => getWrapper('heti-spacing-start heti-spacing-end', portion.text),
|
||||||
|
offset: this.offsetWidth,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
findAndReplaceDOMText($$elm, Object.assign(commonConfig, {
|
findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, {
|
||||||
find: this.REG_START,
|
find: this.REG_START,
|
||||||
replace: portion => getWrapper('heti-spacing-start', portion.text),
|
replace: portion => getWrapper('heti-spacing-start', portion.text),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
findAndReplaceDOMText($$elm, Object.assign(commonConfig, {
|
findAndReplaceDOMText($$elm, Object.assign({}, commonConfig, {
|
||||||
find: this.REG_END,
|
find: this.REG_END,
|
||||||
replace: portion => getWrapper('heti-spacing-end', portion.text),
|
replace: portion => getWrapper('heti-spacing-end', portion.text),
|
||||||
|
offset: this.offsetWidth,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* Add right spacing between CJK & ANS characters
|
* Add right spacing between CJK & ANS characters
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Finder from 'findandreplacedomtext'
|
import Finder from 'heti-findandreplacedomtext'
|
||||||
|
|
||||||
// 正则表达式来自 pangu.js https://github.com/vinta/pangu.js
|
// 正则表达式来自 pangu.js https://github.com/vinta/pangu.js
|
||||||
const CJK = '\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff'
|
const CJK = '\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff'
|
||||||
|
@ -11,52 +11,42 @@ const A = 'A-Za-z\u0370-\u03ff'
|
||||||
const N = '0-9'
|
const N = '0-9'
|
||||||
const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?'
|
const S = '`~!@#\\$%\\^&\\*\\(\\)-_=\\+\\[\\]{}\\\\\\|;:\'",<.>\\/\\?'
|
||||||
const ANS = `${A}${N}${S}`
|
const ANS = `${A}${N}${S}`
|
||||||
const HETI_NON_CONTIGUOUS_ELEMENTS = {
|
const HETI_NON_CONTIGUOUS_ELEMENTS = Object.assign({}, Finder.NON_CONTIGUOUS_PROSE_ELEMENTS, {
|
||||||
// Block Elements
|
|
||||||
address: 1, article: 1, aside: 1, blockquote: 1, dd: 1, div: 1,
|
|
||||||
dl: 1, fieldset: 1, figcaption: 1, figure: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1,
|
|
||||||
h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1, hr: 1, main: 1, nav: 1, noscript: 1, ol: 1,
|
|
||||||
output: 1, p: 1, pre: 1, section: 1, ul: 1,
|
|
||||||
// Other misc. elements that are not part of continuous inline prose:
|
|
||||||
br: 1, li: 1, summary: 1, dt: 1, details: 1, rp: 1, rt: 1, rtc: 1,
|
|
||||||
// Media / Source elements:
|
|
||||||
script: 1, style: 1, img: 1, video: 1, audio: 1, canvas: 1, svg: 1, map: 1, object: 1,
|
|
||||||
// Input elements
|
|
||||||
input: 1, textarea: 1, select: 1, option: 1, optgroup: 1, button: 1,
|
|
||||||
// Table related elements:
|
|
||||||
table: 1, tbody: 1, thead: 1, th: 1, tr: 1, td: 1, caption: 1, col: 1, tfoot: 1, colgroup: 1,
|
|
||||||
// Inline elements
|
// Inline elements
|
||||||
ins: 1, del: 1, s: 1,
|
ins: 1, del: 1, s: 1,
|
||||||
}
|
})
|
||||||
const HETI_SKIPPED_ELEMENTS = {
|
const HETI_SKIPPED_ELEMENTS = Object.assign({}, Finder.NON_PROSE_ELEMENTS, {
|
||||||
br: 1, hr: 1,
|
|
||||||
// Media / Source elements:
|
|
||||||
script: 1, style: 1, img: 1, video: 1, audio: 1, canvas: 1, svg: 1, map: 1, object: 1,
|
|
||||||
// Input elements:
|
|
||||||
input: 1, textarea: 1, select: 1, option: 1, optgroup: 1, button: 1,
|
|
||||||
// Pre elements:
|
|
||||||
pre: 1, code: 1, sup: 1, sub: 1,
|
pre: 1, code: 1, sup: 1, sub: 1,
|
||||||
// Heti elements
|
// Heti elements
|
||||||
'heti-spacing': 1,
|
'heti-spacing': 1,
|
||||||
}
|
})
|
||||||
const HETI_SKIPPED_CLASS = 'heti-skip'
|
const HETI_SKIPPED_CLASS = 'heti-skip'
|
||||||
const hasOwn = {}.hasOwnProperty
|
const hasOwn = {}.hasOwnProperty
|
||||||
|
const REG_FULL = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`
|
||||||
|
const REG_FULL_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`
|
||||||
|
const REG_START = `([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`
|
||||||
|
const REG_END = `(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`
|
||||||
|
const REG_END_FIX = `(?:[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`
|
||||||
|
|
||||||
class Heti {
|
class Heti {
|
||||||
constructor (rootSelector) {
|
constructor (rootSelector) {
|
||||||
|
let supportLookBehind = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new RegExp(`(?<=\d)\d`, 'g').test('')
|
new RegExp(`(?<=\d)\d`, 'g').test('')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(err.name, '浏览器尚未实现 RegExp positive lookbehind')
|
console.info(err.name, '该浏览器尚未实现 RegExp positive lookbehind')
|
||||||
return
|
supportLookBehind = false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rootSelector = rootSelector || '.heti'
|
this.rootSelector = rootSelector || '.heti'
|
||||||
this.REG_FULL = new RegExp(`(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`, 'g')
|
this.REG_FULL = new RegExp(supportLookBehind ? REG_FULL : REG_FULL_FIX, 'g')
|
||||||
this.REG_START = new RegExp(`([${ANS}]+(?: +[${ANS}]+)* *)(?=[${CJK}])`, 'g')
|
this.REG_START = new RegExp(REG_START, 'g')
|
||||||
this.REG_END = new RegExp(`(?<=[${CJK}])( *[${ANS}]+(?: +[${ANS}]+)*)`, 'g')
|
this.REG_END = new RegExp(supportLookBehind ? REG_END : REG_END_FIX, 'g')
|
||||||
|
this.offsetWidth = supportLookBehind ? 0 : 1
|
||||||
this.funcForceContext = function forceContext (el) {
|
this.funcForceContext = function forceContext (el) {
|
||||||
return hasOwn.call(HETI_NON_CONTIGUOUS_ELEMENTS, el.nodeName.toLowerCase())
|
return hasOwn.call(HETI_NON_CONTIGUOUS_ELEMENTS, el.nodeName.toLowerCase())
|
||||||
|
// return true
|
||||||
}
|
}
|
||||||
this.funcFilterElements = function filterElements (el) {
|
this.funcFilterElements = function filterElements (el) {
|
||||||
return (
|
return (
|
||||||
|
@ -84,19 +74,21 @@ class Heti {
|
||||||
return $$r
|
return $$r
|
||||||
}
|
}
|
||||||
|
|
||||||
Finder($$elm, Object.assign(commonConfig, {
|
Finder($$elm, Object.assign({}, commonConfig, {
|
||||||
find: this.REG_FULL,
|
find: this.REG_FULL,
|
||||||
replace: portion => getWrapper('heti-spacing-start heti-spacing-end', portion.text),
|
replace: portion => getWrapper('heti-spacing-start heti-spacing-end', portion.text),
|
||||||
|
offset: this.offsetWidth,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Finder($$elm, Object.assign(commonConfig, {
|
Finder($$elm, Object.assign({}, commonConfig, {
|
||||||
find: this.REG_START,
|
find: this.REG_START,
|
||||||
replace: portion => getWrapper('heti-spacing-start', portion.text),
|
replace: portion => getWrapper('heti-spacing-start', portion.text),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Finder($$elm, Object.assign(commonConfig, {
|
Finder($$elm, Object.assign({}, commonConfig, {
|
||||||
find: this.REG_END,
|
find: this.REG_END,
|
||||||
replace: portion => getWrapper('heti-spacing-end', portion.text),
|
replace: portion => getWrapper('heti-spacing-end', portion.text),
|
||||||
|
offset: this.offsetWidth,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
package-lock.json
generated
12
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "heti",
|
"name": "heti",
|
||||||
"version": "0.4.1",
|
"version": "0.5.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1124,11 +1124,6 @@
|
||||||
"path-exists": "^4.0.0"
|
"path-exists": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"findandreplacedomtext": {
|
|
||||||
"version": "0.4.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/findandreplacedomtext/-/findandreplacedomtext-0.4.6.tgz",
|
|
||||||
"integrity": "sha512-CVRIKbEwfWoKTSnLrmyX26WjMY7o0aUUTm0RXN47fF/eHINJa8C+YHZxGagC7gMWVaAEBFwH7uVXuhwZcylWOQ=="
|
|
||||||
},
|
|
||||||
"flat-cache": {
|
"flat-cache": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
|
||||||
|
@ -1424,6 +1419,11 @@
|
||||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"heti-findandreplacedomtext": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/heti-findandreplacedomtext/-/heti-findandreplacedomtext-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-GFZjqU8LAdu1uR72GqrReI+lzNLMlcWtvdz1TKNJiofyo1mfTecFYSZEoEbcLcRMl+KwEldnNQoS4BwO8wtg0A=="
|
||||||
|
},
|
||||||
"hosted-git-info": {
|
"hosted-git-info": {
|
||||||
"version": "2.8.5",
|
"version": "2.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/sivan/heti#readme",
|
"homepage": "https://github.com/sivan/heti#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"findandreplacedomtext": "^0.4.6"
|
"heti-findandreplacedomtext": "^0.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^11.0.2",
|
"@rollup/plugin-commonjs": "^11.0.2",
|
||||||
|
|
|
@ -16,6 +16,9 @@ export default {
|
||||||
name: 'Heti',
|
name: 'Heti',
|
||||||
plugins: [
|
plugins: [
|
||||||
terser({
|
terser({
|
||||||
|
compress: {
|
||||||
|
pure_funcs: ["console.info"] // 移除调试信息
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
comments: false
|
comments: false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue