Tinymce 6.0.2, Angular 13

Подскажите, если кто знает, мучаюсь уже давно. Подтянула на Angular 13 Tinymce 6.0.2. Но никакого редактора у меня получить так и не получилось. Tinymce новой версии претерпела значительные изменения. Первое из того что я получаю в консоли:

Failed to load model: dom from url models/dom/model.js

В документации я прочитала, что мне необходимо где-то сделать импорт model.js (это одно из изменений, поскольку ранее в папке node_modules/tinymce не было папки models).Я заимпортила его в angular.json. Затем у меня начала появляться ошибка другого плана:

Invalid default value passed for the "toolbar1" option. The value must be a string

Дальше еще 9 подобных ошибок с изменением нумерации "toolbar2","toolbar3" и т.д. При этом с toolbar у меня все в порядке. Помогите плиз. Ошибка возникает при вызове метода setEditorSettings в котором инициализируется tynimce.(В предыдущей версии tinymce код был абсолютно рабочий)

Angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "triggerbee.client": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist",
            "index": "src/index.html",
            "main": "src/main.ts",
            "tsConfig": "src/tsconfig.app.json",
            "polyfills": "src/polyfills.ts",
            "assets": [
              "src/assets",
              {
                "glob": "tinymce.min.js",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "plugins",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "skins",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "themes",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "**/*",
                "input": "node_modules/tinymce/icons",
                "output": "/assets/tinymce/icons/"
              },
              {
                "glob": "Chart.bundle.min.js",
                "input": "node_modules/chart.js/dist",
                "output": "/assets/js"
              },
              {
                "glob": "web.config",
                "input": "config/iis",
                "output": "/"
              },
              {
                "glob": "mocks",
                "input": "src",
                "output": "/"
              }
            ],
            "styles": [
            ],
            "scripts": [
              "./node_modules/chart.js/dist/Chart.js",
              "./node_modules/tinymce/tinymce.js",
              "./node_modules/tinymce/models/dom/model.js",
              "./node_modules/tinymce/plugins/code/plugin.js",
              "./node_modules/tinymce/plugins/lists/plugin.js",
              "./node_modules/tinymce/plugins/link/plugin.js",
              "src/assets/plugins/tinymce/themes/silver/theme.min.js",
              "src/assets/plugins/tinymce/plugins/lineheight/plugin.js",
              "src/assets/plugins/tinymce/plugins/labels/plugin.js",
              "src/assets/plugins/tinymce/plugins/mergevar/plugin.js",
              "src/assets/plugins/tinymce/plugins/labels/langs/sv_SE.js",
              "src/assets/plugins/tinymce/plugins/labels/langs/en.js"
              
            ],
            "vendorChunk": true,
            "extractLicenses": false,
            "buildOptimizer": false,
            "sourceMap": true,
            "optimization": {
              "scripts": true,
              "styles": {
                "minify": true,
                "inlineCritical": false
              },
              "fonts": true
            },
            "namedChunks": true
          },
          "configurations": {
            "dev": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ]
            },
            "devcloud": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/app/environment/environment.dev.ts",
                  "with": "src/app/environment/environment.devcloud.ts"
                }
              ]
            },
            "staging": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/app/environment/environment.dev.ts",
                  "with": "src/app/environment/environment.staging.ts"
                }
              ]
            },
            "stagingcloud": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/app/environment/environment.dev.ts",
                  "with": "src/app/environment/environment.stagingcloud.ts"
                }
              ]
            },
            "prod": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/app/environment/environment.dev.ts",
                  "with": "src/app/environment/environment.prod.ts"
                }
              ]
            },
            "test": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/app/environment/environment.dev.ts",
                  "with": "src/app/environment/environment.test.ts"
                }
              ]
            },
            "mock": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/app/environment/environment.dev.ts",
                  "with": "src/app/environment/environment.mock.ts"
                }
              ]
            },
            "production": {
              "budgets": [
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "150kb"
                }
              ],
              "optimization": {
                "scripts": true,
                "styles": {
                  "minify": true,
                  "inlineCritical": false
                },
                "fonts": true
              },
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          },
          "defaultConfiguration": ""
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "triggerbee.client:build"
          },
          "configurations": {
            "dev": {
              "browserTarget": "triggerbee.client:build:dev"
            },
            "devcloud": {
              "browserTarget": "triggerbee.client:build:devcloud"
            },
            "staging": {
              "browserTarget": "triggerbee.client:build:staging"
            },
            "stagingcloud": {
              "browserTarget": "triggerbee.client:build:stagingcloud"
            },
            "prod": {
              "browserTarget": "triggerbee.client:build:prod"
            },
            "test": {
              "browserTarget": "triggerbee.client:build:test"
            },
            "mock": {
              "browserTarget": "triggerbee.client:build:mock"
            },
            "production": {
              "browserTarget": "triggerbee.client:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "triggerbee.client:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "karmaConfig": "./karma.conf.js",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "scripts": [],
            "styles": [],
            "assets": [
              "src/assets",
              {
                "glob": "tinymce.min.js",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "plugins",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "skins",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "themes",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce"
              },
              {
                "glob": "Chart.bundle.min.js",
                "input": "node_modules/chart.js/dist",
                "output": "/assets/js"
              },
              {
                "glob": "web.config",
                "input": "config/iis",
                "output": "/"
              },
              {
                "glob": "mocks",
                "input": "src",
                "output": "/"
              }
            ]
          }
        }
      }
    },
    "triggerbee.client-e2e": {
      "root": "e2e",
      "sourceRoot": "e2e",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "./protractor.conf.js",
            "devServerTarget": "triggerbee.client:serve"
          }
        }
      }
    }
  },
  "defaultProject": "triggerbee.client",
  "cli": {
    "warnings": {},
    "analytics": false
  },
  "schematics": {
    "@schematics/angular:component": {
      "prefix": "app",
      "style": "scss"
    },
    "@schematics/angular:directive": {
      "prefix": "app"
    }
  }
}

tinymce.service.ts

import {Inject, Injectable} from '@angular/core';
import {LanguageService} from '../../../core/language.service';
import {Subject} from 'rxjs';
import {WidgetComponentType} from 'app/campaign/widgets.model';
import {DOCUMENT} from '@angular/common';
import {AccountVariable, AccountVariableType} from '../../../account-settings/account-settings-models';
import {debounceTime} from 'rxjs/internal/operators';
import {distinctUntilChanged} from 'rxjs/operators';
import {AbstractControl} from '@angular/forms';
declare const tinymce: any;

@Injectable({ providedIn: 'root' })
export class TinyMceService {
  private language: string;
  public savedTextBS = new Subject<TextComponentEntry>();
  public updatedTextBS = new Subject<TextComponentEntry>();

  public returnTextOnly = false;
  private textUpdatedSubject = new Subject<TextComponentEntry>();
  private textSavedSubject = new Subject<TextComponentEntry>();
  private currentlyOpenId: string;
  private color: string;
  private href: string;

  constructor(private readonly translateService: LanguageService,
              @Inject(DOCUMENT) document) {
    this.translateService.getCurrentLanguageNameAsync().then((response) => {
      this.language = response;
    });

    this.textUpdatedSubject.pipe(debounceTime(100), distinctUntilChanged()).subscribe((value => {
      if (value.id !== this.currentlyOpenId) {
        return;
      }
      if (!tinymce.get(value.id)) {
        console.warn('Can not find tiny editor for id: ' + value.id);
        return;
      }
      value.text = value.onlyTextUpdate ? tinymce.get(value.id).getContent({ format: 'text' })
        : tinymce.get(value.id).getContent({ format: 'html' });
      this.updatedTextBS.next(value);
    }));

    this.textSavedSubject.pipe(debounceTime(100), distinctUntilChanged()).subscribe((value => {
      if (value.id !== this.currentlyOpenId) {
        return;
      }
      value.text = value.onlyTextUpdate ? tinymce.get(value.id).getContent({ format: 'text' })
        : tinymce.get(value.id).getContent({ format: 'html' });
      this.savedTextBS.next(value);
    }));
  }

  public rewrittenColorLink(e): void{
    if(e.target.style.color){
      this.color = e.target.style.color
    } else {
      this.color = 'rgb(0,0,0)' 
    }
  }

  public  setEditorSettings(id: string, componentType: WidgetComponentType, inline: boolean,
                            textVariables: Array<AccountVariable>,
                            textUpdatedSubject: Subject<TextComponentEntry>,
                            textSavedSubject: Subject<TextComponentEntry>,
                            onlyTextShouldBeEdited = false): any {
    return {
      selector: '#' + id,
      body_class: 'widget-editor-tinymce',
      componentType: componentType,
      theme: 'silver',
      menubar: false,
      language: this.language,
      paste_as_text: true,
      inline: inline,
      statusbar: false,
      default_link_target: '_blank',
      link_assume_external_targets: 'https',
      setup: (ed) => {
        ed.on('keydown', (e)  => {
          if (!e.shiftKey && e.keyCode === 13) {
            if (componentType === WidgetComponentType.Text) {
              textUpdatedSubject.next({id: id, onlyTextUpdate: onlyTextShouldBeEdited,
                text: '' + ed.getContent({format: 'html'})} as TextComponentEntry);
            } else {
              e.preventDefault();
              // e.target.blur();
              ed.editorContainer.style.display = 'none';
              textSavedSubject.next({id: id, onlyTextUpdate: onlyTextShouldBeEdited,
                text: '' + ed.getContent({format: 'html'})} as TextComponentEntry);
            }
          } else {
            textUpdatedSubject.next({id: id, onlyTextUpdate: onlyTextShouldBeEdited,
              text: '' + ed.getContent({format: 'html'})} as TextComponentEntry);
          }
        });
        ed.on('change', (event) => { 
          if (!(event instanceof KeyboardEvent)) {
            textUpdatedSubject.next({id: id, onlyTextUpdate: onlyTextShouldBeEdited,
              text: '' + ed.getContent({format: 'html'})} as TextComponentEntry);
          }
        });
        ed.on('click', (e) => {
          this.rewrittenColorLink(e)
        });
        ed.on('mouseUp', (e) => {
          this.rewrittenColorLink(e)
        });
        ed.on('execCommand', (e) => {
          if(e.command === 'mceInsertLink') {
            const linkElem = (document.querySelector(`a[href='${e.value.href}']`) as HTMLElement);
            linkElem.style.color = this.color;
            linkElem.style.textDecoration = 'none';
            linkElem.style.cursor = 'pointer';
          }
        });
        ed.on('click', function () {
          ed.editorContainer.addEventListener('click',(e) =>{
            ed.focus();
          })
        });
      },
      plugins: 'mergevar link',
      toolbar: 'undo redo styleselect bold italic alignleft aligncenter alignright alignjustify | bullist numlist outdent indent',
      lineheight_formats: '10px 11px 12px 14px 16px 18px 20px 22px 24px 26px 36px',
      font_size_formats: '8px 9px 10px 11px 12px 13px 14px 15px 16px 18px 20px 22px 24px 30px 32px 36px 40px 48px 56px 64px 72px',
      theme_url: ('/assets/plugins/tinymce/themes/silver/theme.min.js'),
      skin_url:  ('/assets/plugins/tinymce/skins/ui/oxide'),
    };
  }

  public closeAllEditors(exceptForId = undefined as string) {
    if (tinymce.get() && tinymce.get().length > 0) {
      for (let i = 0; i < tinymce.get().length; i++) {
        if (tinymce.get()[i].id !== exceptForId) {
          tinymce.get(i).destroy();
        }
      }
    }
    if (!exceptForId || exceptForId !== this.currentlyOpenId) {
      this.currentlyOpenId = undefined;
    }
  }

  public initializeEditor(id: number, componentType: WidgetComponentType, accountVariables: Array<AccountVariable>) {
    this.closeAllEditors('' + id);
    if (this.currentlyOpenId === ('' + id)) {
      return;
    }

    this.currentlyOpenId = '' + id;

    if (!id) {
      return;
    }

    const textVariables = accountVariables ?
      accountVariables.filter(a => a.type === AccountVariableType.Text) : undefined;
    const onlyTextShouldBeEdited = componentType === WidgetComponentType.InputText ||
      componentType === WidgetComponentType.Date || componentType === WidgetComponentType.Dropdown;
    this.returnTextOnly = onlyTextShouldBeEdited;
    setTimeout(() => {
      tinymce.init(
        this.setEditorSettings('' + id, componentType, true, textVariables, this.textUpdatedSubject,
          this.textSavedSubject, onlyTextShouldBeEdited)
      );

      // this.focusCurrentEditor();

      // Check if tox-container should be removed (to remove arrows)
      if (onlyTextShouldBeEdited) {
        const wait = setInterval(() => {
          if (document.getElementsByClassName('tox-editor-container').length > 0) {
            [].forEach.call(document.getElementsByClassName('tox-editor-container'), function (el) {
              el.style.visibility = 'hidden';
            });
            clearInterval(wait);
          }
        }, 50);
      }
    }, 200);
  }

  public closeEditor(id: string) {
    this.currentlyOpenId = undefined;
    // this.id = undefined;
    const tiny = tinymce.get('' + id);
    if (tiny) {
      tinymce.get('' + id).destroy();
    }
  }

  public editorIsOpen(id: number): boolean {
    return !!tinymce.activeEditor && tinymce.activeEditor.id === ('' + id);
  }

  public focusCurrentEditor() {
    setTimeout(() => {
      if (!!tinymce.activeEditor) {
        tinymce.activeEditor.focus();
      }
    }, 200);
  }

  public initializeTiny(id: string, formcontrol: AbstractControl) {
    tinymce.init({
      selector: '#' + id,
      height: 150,
      theme: 'silver',
      menubar: false,
      plugins: 'link',
      link_assume_external_targets: 'https',
      link_default_target: '_blank',
      toolbar: 'bold italic link forecolor',
      setup: function (ed) {
        ed.on('init', function () {
          tinymce.activeEditor.setContent(formcontrol.value);
        })
        ed.on('keyup', function (e) {
          formcontrol.setValue(tinymce.activeEditor.getContent({format: 'html'}));
        })
        ed.on('click', function () {
          ed.editorContainer.addEventListener('click', function (e) {
            formcontrol.setValue(tinymce.activeEditor.getContent({format: 'html'}));
          })
        })
        ed.on('focusout', function (e) {
          formcontrol.setValue(tinymce.activeEditor.getContent({format: 'html'}));
        })
        ed.on('focus', function (e) {
          formcontrol.markAsTouched();
        });
      },
      theme_url: ('/assets/plugins/tinymce/themes/silver/theme.min.js'),
      skin_url: ('/assets/plugins/tinymce/skins/ui/oxide'),
    })
  }

  public closeTiny(id: string): void {
    tinymce.remove('#' + id);
  }
}

export interface TextComponentEntry {
  onlyTextUpdate: boolean;
  text: string;
  id: string;
}

Ответы (0 шт):