mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 22:43:30 +03:00
🐛 correctly count multibyte chars in character counters (#487)
closes https://github.com/TryGhost/Ghost/issues/7739 - use es6's `Array.from` to convert the string to an array to get a symbol count rather than a byte count
This commit is contained in:
parent
a1621d65a4
commit
b1c94c6397
@ -1,14 +1,17 @@
|
||||
import {helper} from 'ember-helper';
|
||||
import {htmlSafe} from 'ember-string';
|
||||
|
||||
export default helper(function (params) {
|
||||
export function countCharacters(params) {
|
||||
if (!params || !params.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let el = document.createElement('span');
|
||||
let content = params[0] || '';
|
||||
let {length} = content;
|
||||
|
||||
// convert to array so that we get accurate symbol counts for multibyte chars
|
||||
// this will still count emoji+modifer as two chars
|
||||
let {length} = Array.from(content);
|
||||
|
||||
el.className = 'word-count';
|
||||
|
||||
@ -21,4 +24,8 @@ export default helper(function (params) {
|
||||
el.innerHTML = 200 - length;
|
||||
|
||||
return htmlSafe(el.outerHTML);
|
||||
}
|
||||
|
||||
export default helper(function (params) {
|
||||
return countCharacters(params);
|
||||
});
|
||||
|
@ -1,17 +1,17 @@
|
||||
import {helper} from 'ember-helper';
|
||||
import {htmlSafe} from 'ember-string';
|
||||
|
||||
export default helper(function (params) {
|
||||
export function countDownCharacters(params) {
|
||||
if (!params || params.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
let el = document.createElement('span');
|
||||
let [content, maxCharacters] = params;
|
||||
let length;
|
||||
|
||||
content = content || '';
|
||||
length = content.length;
|
||||
// convert to array so that we get accurate symbol counts for multibyte chars
|
||||
// this will still count emoji+modifer as two chars
|
||||
let {length} = Array.from(content || '');
|
||||
|
||||
el.className = 'word-count';
|
||||
|
||||
@ -24,4 +24,8 @@ export default helper(function (params) {
|
||||
el.innerHTML = length;
|
||||
|
||||
return htmlSafe(el.outerHTML);
|
||||
}
|
||||
|
||||
export default helper(function (params) {
|
||||
return countDownCharacters(params);
|
||||
});
|
||||
|
37
ghost/admin/tests/unit/helpers/gh-count-characters-test.js
Normal file
37
ghost/admin/tests/unit/helpers/gh-count-characters-test.js
Normal file
@ -0,0 +1,37 @@
|
||||
import {expect} from 'chai';
|
||||
import {describe, it} from 'mocha';
|
||||
import {countCharacters} from 'ghost-admin/helpers/gh-count-characters';
|
||||
|
||||
describe('Unit: Helper: gh-count-characters', function() {
|
||||
let defaultStyle = 'color: rgb(158, 157, 149);';
|
||||
let errorStyle = 'color: rgb(226, 84, 64);';
|
||||
|
||||
it('counts remaining chars', function() {
|
||||
let result = countCharacters(['test']);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${defaultStyle}">196</span>`);
|
||||
});
|
||||
|
||||
it('warns when nearing limit', function () {
|
||||
let result = countCharacters([Array(195 + 1).join('x')]);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${errorStyle}">5</span>`);
|
||||
});
|
||||
|
||||
it('indicates too many chars', function () {
|
||||
let result = countCharacters([Array(205 + 1).join('x')]);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${errorStyle}">-5</span>`);
|
||||
});
|
||||
|
||||
it('counts multibyte correctly', function () {
|
||||
let result = countCharacters(['💩']);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${defaultStyle}">199</span>`);
|
||||
|
||||
// emoji + modifier is still two chars
|
||||
result = countCharacters(['💃🏻']);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${defaultStyle}">198</span>`);
|
||||
});
|
||||
});
|
@ -0,0 +1,31 @@
|
||||
import {expect} from 'chai';
|
||||
import {describe, it} from 'mocha';
|
||||
import {countDownCharacters} from 'ghost-admin/helpers/gh-count-down-characters';
|
||||
|
||||
describe('Unit: Helper: gh-count-down-characters', function() {
|
||||
let validStyle = 'color: rgb(159, 187, 88);';
|
||||
let errorStyle = 'color: rgb(226, 84, 64);';
|
||||
|
||||
it('counts chars', function() {
|
||||
let result = countDownCharacters(['test', 200]);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${validStyle}">4</span>`);
|
||||
});
|
||||
|
||||
it('warns with too many chars', function () {
|
||||
let result = countDownCharacters([Array(205 + 1).join('x'), 200]);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${errorStyle}">205</span>`);
|
||||
});
|
||||
|
||||
it('counts multibyte correctly', function () {
|
||||
let result = countDownCharacters(['💩', 200]);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${validStyle}">1</span>`);
|
||||
|
||||
// emoji + modifier is still two chars
|
||||
result = countDownCharacters(['💃🏻', 200]);
|
||||
expect(result.string)
|
||||
.to.equal(`<span class="word-count" style="${validStyle}">2</span>`);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user