diff --git a/ghost/admin/app/helpers/gh-count-characters.js b/ghost/admin/app/helpers/gh-count-characters.js index 344dc4f307..107d2ea273 100644 --- a/ghost/admin/app/helpers/gh-count-characters.js +++ b/ghost/admin/app/helpers/gh-count-characters.js @@ -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); }); diff --git a/ghost/admin/app/helpers/gh-count-down-characters.js b/ghost/admin/app/helpers/gh-count-down-characters.js index 4f7077846d..3abab9c61a 100644 --- a/ghost/admin/app/helpers/gh-count-down-characters.js +++ b/ghost/admin/app/helpers/gh-count-down-characters.js @@ -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); }); diff --git a/ghost/admin/tests/unit/helpers/gh-count-characters-test.js b/ghost/admin/tests/unit/helpers/gh-count-characters-test.js new file mode 100644 index 0000000000..fabde5f636 --- /dev/null +++ b/ghost/admin/tests/unit/helpers/gh-count-characters-test.js @@ -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(`196`); + }); + + it('warns when nearing limit', function () { + let result = countCharacters([Array(195 + 1).join('x')]); + expect(result.string) + .to.equal(`5`); + }); + + it('indicates too many chars', function () { + let result = countCharacters([Array(205 + 1).join('x')]); + expect(result.string) + .to.equal(`-5`); + }); + + it('counts multibyte correctly', function () { + let result = countCharacters(['💩']); + expect(result.string) + .to.equal(`199`); + + // emoji + modifier is still two chars + result = countCharacters(['💃🏻']); + expect(result.string) + .to.equal(`198`); + }); +}); diff --git a/ghost/admin/tests/unit/helpers/gh-count-down-characters-test.js b/ghost/admin/tests/unit/helpers/gh-count-down-characters-test.js new file mode 100644 index 0000000000..41d4eb06bd --- /dev/null +++ b/ghost/admin/tests/unit/helpers/gh-count-down-characters-test.js @@ -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(`4`); + }); + + it('warns with too many chars', function () { + let result = countDownCharacters([Array(205 + 1).join('x'), 200]); + expect(result.string) + .to.equal(`205`); + }); + + it('counts multibyte correctly', function () { + let result = countDownCharacters(['💩', 200]); + expect(result.string) + .to.equal(`1`); + + // emoji + modifier is still two chars + result = countDownCharacters(['💃🏻', 200]); + expect(result.string) + .to.equal(`2`); + }); +});