string.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /**
  2. * This file is part of Threema Web.
  3. *
  4. * Threema Web is free software: you can redistribute it and/or modify it
  5. * under the terms of the GNU Affero General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or (at
  7. * your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Affero General Public License
  15. * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. export class StringService {
  18. public byteChunk(str: string, byteLength: number, offset: number = null): string[] {
  19. const chars = [...str];
  20. const chunks = [''];
  21. let currentChunkSize = 0;
  22. let chunkIndex = 0;
  23. const offsetChars = [' ', '\r', '\n', '\t', '.'];
  24. let lastSeparator = -1;
  25. chars.forEach ((charString: string) => {
  26. const length = Buffer.byteLength(charString, 'utf8');
  27. if (offset !== null) {
  28. if (offsetChars.indexOf(charString) > -1) {
  29. lastSeparator = currentChunkSize + 1;
  30. }
  31. }
  32. if (currentChunkSize + length > byteLength) {
  33. let appendNewChunk = true;
  34. if (lastSeparator > -1) {
  35. // check if separator in offset
  36. if (currentChunkSize - lastSeparator <= offset
  37. && chunks.length >= 1) {
  38. // create new chunk with existing data
  39. chunks.push(chunks[chunkIndex].substr(lastSeparator).trim());
  40. // modify old chunk
  41. chunks[chunkIndex] = chunks[chunkIndex].substr(0, lastSeparator).trim();
  42. appendNewChunk = false;
  43. currentChunkSize -= lastSeparator;
  44. chunkIndex++;
  45. lastSeparator = -1;
  46. }
  47. }
  48. if (appendNewChunk) {
  49. chunkIndex++;
  50. currentChunkSize = 0;
  51. // create a new chunk
  52. chunks.push('');
  53. }
  54. }
  55. chunks[chunkIndex] = (chunks[chunkIndex] + charString);
  56. currentChunkSize += length;
  57. });
  58. return chunks;
  59. }
  60. /**
  61. * Return the word below the cursor position.
  62. *
  63. * If the cursor is at the end of a word, the word to the left of it will
  64. * be returned.
  65. *
  66. * If there is whitespace to the left of the cursor, then the returned
  67. * `WordResult` object will include the trimmed word to the left of the
  68. * cursor. The `realLength` includes the trimmed whitespace though.
  69. */
  70. public getWord(input: string, pos: number, additionalSeparators: string[] = null): threema.WordResult {
  71. const result = {
  72. word: null,
  73. realLength: 0,
  74. };
  75. if (input !== null && input.length > 0) {
  76. const chars = [...input];
  77. let charFound = false;
  78. const realPos = Math.min(pos, chars.length) - 1;
  79. if (realPos > 0) {
  80. const wordChars = new Array(realPos);
  81. for (let n = realPos; n >= 0; n--) {
  82. const realChar = chars[n].trim();
  83. if (realChar === '') {
  84. // Abort
  85. if (charFound === false) {
  86. result.realLength++;
  87. continue;
  88. } else {
  89. break;
  90. }
  91. } else if (additionalSeparators !== null) {
  92. if (additionalSeparators.indexOf(chars[n]) > -1) {
  93. // append char
  94. result.realLength++;
  95. wordChars[n] = realChar;
  96. if (charFound === false) {
  97. continue;
  98. } else {
  99. break;
  100. }
  101. }
  102. }
  103. result.realLength++;
  104. wordChars[n] = realChar;
  105. charFound = true;
  106. }
  107. result.word = wordChars.join('');
  108. }
  109. }
  110. return result;
  111. }
  112. }