Skip to content

Commit d9b283f

Browse files
committed
fix(octra): cursor in transcr editor jumps to invalid position on marker insert
1 parent 430331d commit d9b283f

File tree

6 files changed

+124
-188
lines changed

6 files changed

+124
-188
lines changed

apps/octra/src/app/core/component/navbar/navbar.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ <h4 class="offcanvas-title">{{ 'g.settings' | transloco }}</h4>
757757
}
758758
<a class="dropdown-item" (click)="logout()">
759759
<i class="bi bi-door-open-fill"></i>
760-
Logout
760+
{{"g.logout" | transloco}}
761761
</a>
762762
</div>
763763
</li>

apps/octra/src/app/core/component/transcr-editor/transcr-editor.component.ts

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ import { DefaultComponent } from '../default.component';
5252
import { TranscrEditorConfig } from './config';
5353
import { ValidationPopoverComponent } from './validation-popover/validation-popover.component';
5454

55-
declare let document: any;
56-
5755
@Component({
5856
selector: 'octra-transcr-editor',
5957
templateUrl: './transcr-editor.component.html',
@@ -303,7 +301,10 @@ export class TranscrEditorComponent
303301
let html = this.wysiwyg.innerHTML;
304302

305303
html = html.replace(/<((p)|(\s?\/p))>/g, '');
306-
html = html.replace(/&nbsp;/g, ' ');
304+
305+
if (html.includes('⌈') || html.includes('⌉')) {
306+
console.error('HTML contains protected utf-8 icons!');
307+
}
307308

308309
// check for markers that are utf8 symbols
309310
if (this.markers) {
@@ -323,11 +324,9 @@ export class TranscrEditorComponent
323324
}
324325
}
325326

326-
const dom: HTMLElement = document.createElement('p');
327+
const dom: HTMLElement = this.renderer.createElement('p');
327328
dom.innerHTML = html;
328329

329-
let charCounter = 0;
330-
331330
const textSelection = {
332331
start: -1,
333332
end: -1,
@@ -353,23 +352,20 @@ export class TranscrEditorComponent
353352
for (const marker of this.markers) {
354353
if (markerCode === marker.code) {
355354
const parent = elem.parentNode;
356-
parent.replaceChild(document.createTextNode(markerCode), elem);
357-
charCounter += markerCode.length;
355+
parent.replaceChild(this.renderer.createText(markerCode), elem);
358356
break;
359357
}
360358
}
361359
} else if (elem.nodeType === 3) {
362360
// is textNode
363361
const text = elem.nodeValue;
364-
charCounter += text.length;
365362
elem.innerText = text;
366363
} else if (tagName.toLowerCase() === 'img') {
367364
if (getAttr(elem, 'data-samples') !== undefined) {
368365
const boundaryText = `{${getAttr(elem, 'data-samples')}}`;
369-
const textnode = document.createTextNode(boundaryText);
366+
const textnode = this.renderer.createText(boundaryText);
370367
elem.parentNode.insertBefore(textnode, elem);
371368
elem.remove();
372-
charCounter += boundaryText.length;
373369
}
374370
} else if (
375371
getAttr(elem, 'class') === 'val-error' &&
@@ -379,40 +375,47 @@ export class TranscrEditorComponent
379375
} else if (tagName.toLowerCase() === 'span') {
380376
if (getAttr(elem, 'data-jodit-selection_marker') === 'start') {
381377
// save start selection
382-
textSelection.start = charCounter;
378+
const textnode = this.renderer.createText(`⌈start⌉`);
379+
elem.parentNode.insertBefore(textnode, elem);
380+
elem.remove();
383381
} else if (getAttr(elem, 'data-jodit-selection_marker') === 'end') {
384382
// save start selection
385-
textSelection.end = charCounter;
383+
const textnode = this.renderer.createText(`⌈end⌉`);
384+
elem.parentNode.insertBefore(textnode, elem);
385+
elem.remove();
386386
} else if (getAttr(elem, 'class') === 'highlighted') {
387387
elem.remove();
388388
} else {
389389
const elemText = elem.innerText;
390-
const textnode = document.createTextNode(elemText);
390+
const textnode = this.renderer.createText(elemText);
391391
elem.parentNode.insertBefore(textnode, elem);
392392
elem.remove();
393-
charCounter += elemText.length;
394393
}
395394
}
396395
}
397396
};
397+
dom.childNodes.forEach(replaceFunc);
398+
let rawText = dom.innerText.replace(/\uFEFF/gm, '').replace(/&nbsp;/g, ' ');
399+
400+
if (replaceEmptySpaces) {
401+
rawText = rawText.replace(/[\s ]+/g, ' ');
402+
}
403+
404+
textSelection.start = rawText.indexOf('⌈start⌉');
405+
rawText = rawText.replace('⌈start⌉', '');
406+
textSelection.end = rawText.indexOf('⌈end⌉');
407+
rawText = rawText.replace('⌈end⌉', '');
398408

399-
if (textSelection.start === -1 || textSelection.end === -1) {
409+
if (textSelection.start === -1 && textSelection.end === -1) {
400410
textSelection.start = 0;
401411
textSelection.end = 0;
402412
}
403413

404414
this._textSelection = textSelection;
405415

406-
dom.childNodes.forEach(replaceFunc);
407-
408-
let rawText = dom.innerText;
409-
410-
if (replaceEmptySpaces) {
411-
rawText = rawText.replace(/[\s ]+/g, ' ');
412-
}
413-
414-
return rawText.replace(/\uFEFF/gm, '');
416+
return rawText;
415417
};
418+
416419
/**
417420
* initializes the editor and the containing jodit editor
418421
*/
@@ -468,7 +471,7 @@ export class TranscrEditorComponent
468471
this.cd.markForCheck();
469472
this.cd.detectChanges();
470473

471-
const validationError = document.createElement('div');
474+
const validationError = this.renderer.createElement('div');
472475
validationError.setAttribute('class', 'card error-card');
473476
validationError.innerHTML = `
474477
<div class="card-header" style="padding:5px 10px; font-weight: bold;background-color:whitesmoke;">
@@ -592,15 +595,15 @@ export class TranscrEditorComponent
592595
) {
593596
// it's an icon
594597

595-
const element = document.createElement('img');
598+
const element = this.renderer.createElement('img');
596599
element.setAttribute('src', icon);
597600
element.setAttribute('class', 'btn-icon-text');
598601
element.setAttribute('data-marker-code', markerCode);
599602
element.setAttribute('alt', markerCode);
600603

601-
editor!.selection.insertNode(document.createTextNode(' '), true);
604+
editor!.selection.insertNode(this.renderer.createText(' '), true);
602605
editor!.selection.insertHTML(element.outerHTML, true);
603-
editor!.selection.insertNode(document.createTextNode(' '), true);
606+
editor!.selection.insertNode(this.renderer.createText(' '), true);
604607
} else {
605608
editor!.selection.insertHTML(icon, true);
606609
}
@@ -779,7 +782,7 @@ export class TranscrEditorComponent
779782
if (!btn) {
780783
const content = getContent();
781784

782-
const button = document.createElement('span');
785+
const button = this.renderer.createElement('span');
783786

784787
if (tooltip) {
785788
button.setAttribute('title', tooltip);
@@ -995,7 +998,7 @@ export class TranscrEditorComponent
995998
: 'Arial';
996999

9971000
const createOption = (fontName: string) => {
998-
const option = document.createElement('option');
1001+
const option = this.renderer.createElement('option');
9991002
option.setAttribute('value', fontName);
10001003
option.style.fontSize = '0.85rem';
10011004
option.innerText = fontName;
@@ -1005,7 +1008,8 @@ export class TranscrEditorComponent
10051008
return option;
10061009
};
10071010

1008-
const selection: HTMLSelectElement = document.createElement('select');
1011+
const selection: HTMLSelectElement =
1012+
this.renderer.createElement('select');
10091013
selection.value = currentFont;
10101014
selection.appendChild(createOption('Helvetica'));
10111015
selection.appendChild(createOption('Arial'));
@@ -1024,7 +1028,7 @@ export class TranscrEditorComponent
10241028
}
10251029

10261030
insertBoundary(imgURL: string) {
1027-
const element = document.createElement('img');
1031+
const element = this.renderer.createElement('img');
10281032
element.setAttribute('src', imgURL);
10291033
element.setAttribute('class', 'btn-icon-text boundary');
10301034
element.setAttribute(
@@ -1135,8 +1139,8 @@ export class TranscrEditorComponent
11351139
let code = this._rawText;
11361140
// insert selection placeholders
11371141
if (!focusAtEnd) {
1138-
const startMarker = '✉✉✉sel-start/📩📩📩';
1139-
const endMarker = '✉✉✉sel-end/📩📩📩';
1142+
const startMarker = 'sel-start/';
1143+
const endMarker = 'sel-end/';
11401144
code =
11411145
this.lastCursorPosition!.endMarker !== undefined &&
11421146
this._textSelection.end >= this._textSelection.start
@@ -1145,7 +1149,7 @@ export class TranscrEditorComponent
11451149
this._textSelection.end,
11461150
endMarker,
11471151
)
1148-
: this._rawText;
1152+
: code;
11491153
code = insertString(code, this._textSelection.start, startMarker);
11501154
code = this.tidyUpRaw(code);
11511155
}
@@ -1284,7 +1288,7 @@ export class TranscrEditorComponent
12841288
}
12851289

12861290
let currentSegIndex = 0;
1287-
let puffer = document.createElement('span');
1291+
let puffer = this.renderer.createElement('span');
12881292
puffer.setAttribute('class', 'highlighted');
12891293

12901294
const parentElement: HTMLElement = dom;
@@ -1321,13 +1325,13 @@ export class TranscrEditorComponent
13211325
pointer.parentNode!.insertBefore(puffer, pointer);
13221326
}
13231327
this.lastHighlightedSegment = currentSegIndex;
1324-
puffer = document.createElement('span');
1328+
puffer = this.renderer.createElement('span');
13251329
puffer.setAttribute('class', 'highlighted');
13261330

13271331
pointer = pointer.nextSibling;
13281332
currentSegIndex++;
13291333
} else {
1330-
puffer = document.createElement('span');
1334+
puffer = this.renderer.createElement('span');
13311335
puffer.setAttribute('class', 'highlighted');
13321336
currentSegIndex++;
13331337
pointer = pointer.nextSibling;
@@ -1722,7 +1726,7 @@ export class TranscrEditorComponent
17221726
(await this.annotationStoreService.rawToHTML(html)) +
17231727
'</span>';
17241728
html = html.replace(/(<p>)|(<\/p>)|(<br\/?>)/g, '');
1725-
const htmlObj = document.createElement('span');
1729+
const htmlObj = this.renderer.createElement('span');
17261730
htmlObj.innerHTML = html;
17271731

17281732
if (this.rawText !== undefined && this._rawText !== '') {
@@ -1742,7 +1746,7 @@ export class TranscrEditorComponent
17421746
() => {
17431747
if (this.workplace?.parentNode) {
17441748
if (!this.popovers.segmentBoundary) {
1745-
const segmentBoundary = document.createElement('div');
1749+
const segmentBoundary = this.renderer.createElement('div');
17461750
segmentBoundary.setAttribute('class', 'panel seg-popover');
17471751
segmentBoundary.innerHTML = '00:00:000';
17481752
this.popovers.segmentBoundary = segmentBoundary;

apps/octra/src/app/core/component/transcr-overview/transcr-overview.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -471,9 +471,9 @@ export class TranscrOverviewComponent implements OnInit, OnDestroy, OnChanges {
471471
obj.transcription.html,
472472
);
473473
obj.transcription.html = obj.transcription.html.replace(
474-
/((?:)|(?:📩📩📩))/,
474+
/((?:)|(?:))/,
475475
(g0, g1) => {
476-
if (g1 === '✉✉✉') {
476+
if (g1 === '') {
477477
return '<';
478478
}
479479
return '>';
@@ -484,9 +484,9 @@ export class TranscrOverviewComponent implements OnInit, OnDestroy, OnChanges {
484484
obj.transcription.html,
485485
);
486486
obj.transcription.html = obj.transcription.html.replace(
487-
/((?:)|(?:📩📩📩))/g,
487+
/((?:)|(?:))/g,
488488
(g0, g1) => {
489-
if (g1 === '✉✉✉') {
489+
if (g1 === '') {
490490
return '<';
491491
}
492492
return '>';

apps/octra/src/app/core/modals/transcription-backup-end/transcription-backup-end-modal.component.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ import { AppStorageService } from '../../shared/service/appstorage.service';
88
import { AnnotationStoreService } from '../../store/login-mode/annotation/annotation.store.service';
99
import { OctraModal } from '../types';
1010

11-
export enum ModalEndAnswer {
12-
CANCEL = 'CANCEL',
13-
QUIT = 'QUIT',
14-
CONTINUE = 'CONTINUE',
15-
}
16-
1711
@Component({
1812
selector: 'octra-transcription-backup-end-modal',
1913
templateUrl: './transcription-backup-end-modal.component.html',

0 commit comments

Comments
 (0)